xref: /petsc/src/dm/impls/plex/plex.c (revision b0043f701616b3f2f8d3dcb8857530d8692d5c06)
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     int piperet;
2760     piperet = pipe(fd_pipe);
2761     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2762     fd_stdout = dup(1);
2763     close(1);
2764     dup2(fd_pipe[1], 1);
2765   }
2766 #endif
2767   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2768                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2769                    vmax, ndims, eigtol, seed);
2770 #ifdef PETSC_HAVE_UNISTD_H
2771   {
2772     char msgLog[10000];
2773     int  count;
2774 
2775     fflush(stdout);
2776     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2777     if (count < 0) count = 0;
2778     msgLog[count] = 0;
2779     close(1);
2780     dup2(fd_stdout, 1);
2781     close(fd_stdout);
2782     close(fd_pipe[0]);
2783     close(fd_pipe[1]);
2784     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2785   }
2786 #endif
2787   /* Convert to PetscSection+IS */
2788   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2789   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2790   for (v = 0; v < nvtxs; ++v) {
2791     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2792   }
2793   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2794   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2795   for (p = 0, i = 0; p < commSize; ++p) {
2796     for (v = 0; v < nvtxs; ++v) {
2797       if (assignment[v] == p) points[i++] = v;
2798     }
2799   }
2800   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2801   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2802   if (global_method == INERTIAL_METHOD) {
2803     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2804   }
2805   ierr = PetscFree(assignment);CHKERRQ(ierr);
2806   for (i = 0; i < start[numVertices]; ++i) {
2807     --adjacency[i];
2808   }
2809   PetscFunctionReturn(0);
2810 }
2811 #endif
2812 
2813 #ifdef PETSC_HAVE_PARMETIS
2814 #undef __FUNCT__
2815 #define __FUNCT__ "DMPlexPartition_ParMetis"
2816 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2817 {
2818   PetscFunctionBegin;
2819   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2820   PetscFunctionReturn(0);
2821 }
2822 #endif
2823 
2824 #undef __FUNCT__
2825 #define __FUNCT__ "DMPlexEnlargePartition"
2826 /* Expand the partition by BFS on the adjacency graph */
2827 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition) {
2828   PetscHashI      h;
2829   const PetscInt *points;
2830   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2831   PetscInt        pStart, pEnd, part, q;
2832   PetscErrorCode  ierr;
2833 
2834   PetscFunctionBegin;
2835   PetscHashICreate(h);
2836   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2837   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2838   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2839   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2840   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2841   for(part = pStart; part < pEnd; ++part) {
2842     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2843 
2844     PetscHashIClear(h);
2845     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2846     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2847     /* Add all existing points to h */
2848     for(p = 0; p < numPoints; ++p) {
2849       const PetscInt point = points[off+p];
2850       PetscHashIAdd(h, point, 1);
2851     }
2852     PetscHashISize(h, nP);
2853     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2854     /* Add all points in next BFS level */
2855     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2856     for(p = 0; p < numPoints; ++p) {
2857       const PetscInt point = points[off+p];
2858       PetscInt s = start[point], e = start[point+1], a;
2859 
2860       for(a = s; a < e; ++a) {
2861         PetscHashIAdd(h, adjacency[a], 1);
2862       }
2863     }
2864     PetscHashISize(h, numNewPoints);
2865     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2866     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2867     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2868     totPoints += numNewPoints;
2869   }
2870   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2871   PetscHashIDestroy(h);
2872   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2873   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2874   for(part = pStart, q = 0; part < pEnd; ++part) {
2875     PetscInt numPoints, p;
2876 
2877     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2878     for(p = 0; p < numPoints; ++p, ++q) {
2879       newPoints[q] = tmpPoints[part][p];
2880     }
2881     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2882   }
2883   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2884   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2885   PetscFunctionReturn(0);
2886 }
2887 
2888 #undef __FUNCT__
2889 #define __FUNCT__ "DMPlexCreatePartition"
2890 /*
2891   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2892 
2893   Collective on DM
2894 
2895   Input Parameters:
2896   + dm - The DM
2897   . height - The height for points in the partition
2898   - enlarge - Expand each partition with neighbors
2899 
2900   Output Parameters:
2901   + partSection - The PetscSection giving the division of points by partition
2902   . partition - The list of points by partition
2903   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2904   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2905 
2906   Level: developer
2907 
2908 .seealso DMPlexDistribute()
2909 */
2910 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition) {
2911   PetscMPIInt    size;
2912   PetscErrorCode ierr;
2913 
2914   PetscFunctionBegin;
2915   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2916   *origPartSection = PETSC_NULL;
2917   *origPartition   = PETSC_NULL;
2918   if (size == 1) {
2919     PetscInt *points;
2920     PetscInt  cStart, cEnd, c;
2921 
2922     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2923     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2924     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2925     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2926     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2927     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2928     for (c = cStart; c < cEnd; ++c) {
2929       points[c] = c;
2930     }
2931     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2932     PetscFunctionReturn(0);
2933   }
2934   if (height == 0) {
2935     PetscInt  numVertices;
2936     PetscInt *start     = PETSC_NULL;
2937     PetscInt *adjacency = PETSC_NULL;
2938 
2939     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2940     if (1) {
2941 #ifdef PETSC_HAVE_CHACO
2942       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2943 #endif
2944     } else {
2945 #ifdef PETSC_HAVE_PARMETIS
2946       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2947 #endif
2948     }
2949     if (enlarge) {
2950       *origPartSection = *partSection;
2951       *origPartition   = *partition;
2952       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2953     }
2954     ierr = PetscFree(start);CHKERRQ(ierr);
2955     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2956 # if 0
2957   } else if (height == 1) {
2958     /* Build the dual graph for faces and partition the hypergraph */
2959     PetscInt numEdges;
2960 
2961     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2962     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2963     destroyCSR(numEdges, start, adjacency);
2964 #endif
2965   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2966   PetscFunctionReturn(0);
2967 }
2968 
2969 #undef __FUNCT__
2970 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2971 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition) {
2972   /* const PetscInt  height = 0; */
2973   const PetscInt *partArray;
2974   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2975   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2976   PetscErrorCode  ierr;
2977 
2978   PetscFunctionBegin;
2979   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2980   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2981   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2982   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2983   for (rank = rStart; rank < rEnd; ++rank) {
2984     PetscInt partSize = 0;
2985     PetscInt numPoints, offset, p;
2986 
2987     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2988     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2989     for (p = 0; p < numPoints; ++p) {
2990       PetscInt  point   = partArray[offset+p], closureSize, c;
2991       PetscInt *closure = PETSC_NULL;
2992 
2993       /* TODO Include support for height > 0 case */
2994       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2995       /* Merge into existing points */
2996       if (partSize+closureSize > maxPartSize) {
2997         PetscInt *tmpPoints;
2998 
2999         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3000         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3001         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3002         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3003         partPoints = tmpPoints;
3004       }
3005       for (c = 0; c < closureSize; ++c) {
3006         partPoints[partSize+c] = closure[c*2];
3007       }
3008       partSize += closureSize;
3009       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3010       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3011     }
3012     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3013   }
3014   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3015   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3016   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3017 
3018   for (rank = rStart; rank < rEnd; ++rank) {
3019     PetscInt partSize = 0, newOffset;
3020     PetscInt numPoints, offset, p;
3021 
3022     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3023     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3024     for (p = 0; p < numPoints; ++p) {
3025       PetscInt  point   = partArray[offset+p], closureSize, c;
3026       PetscInt *closure = PETSC_NULL;
3027 
3028       /* TODO Include support for height > 0 case */
3029       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3030       /* Merge into existing points */
3031       for (c = 0; c < closureSize; ++c) {
3032         partPoints[partSize+c] = closure[c*2];
3033       }
3034       partSize += closureSize;
3035       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3036       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3037     }
3038     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3039     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3040   }
3041   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3042   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3043   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3044   PetscFunctionReturn(0);
3045 }
3046 
3047 #undef __FUNCT__
3048 #define __FUNCT__ "DMPlexDistributeField"
3049 /*
3050   Input Parameters:
3051 . originalSection
3052 , originalVec
3053 
3054   Output Parameters:
3055 . newSection
3056 . newVec
3057 */
3058 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3059 {
3060   PetscSF         fieldSF;
3061   PetscInt       *remoteOffsets, fieldSize;
3062   PetscScalar    *originalValues, *newValues;
3063   PetscErrorCode  ierr;
3064 
3065   PetscFunctionBegin;
3066   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3067 
3068   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3069   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3070   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3071 
3072   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3073   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3074   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3075   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3076   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3077   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3078   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3079   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3080   PetscFunctionReturn(0);
3081 }
3082 
3083 #undef __FUNCT__
3084 #define __FUNCT__ "DMPlexDistribute"
3085 /*@C
3086   DMPlexDistribute - Distributes the mesh and any associated sections.
3087 
3088   Not Collective
3089 
3090   Input Parameter:
3091 + dm  - The original DMPlex object
3092 . partitioner - The partitioning package, or NULL for the default
3093 - overlap - The overlap of partitions, 0 is the default
3094 
3095   Output Parameter:
3096 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3097 
3098   Note: If the mesh was not distributed, the return value is PETSC_NULL
3099 
3100   Level: intermediate
3101 
3102 .keywords: mesh, elements
3103 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3104 @*/
3105 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3106 {
3107   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3108   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3109   const PetscInt height = 0;
3110   PetscInt       dim, numRemoteRanks;
3111   IS             origCellPart,        cellPart,        part;
3112   PetscSection   origCellPartSection, cellPartSection, partSection;
3113   PetscSFNode   *remoteRanks;
3114   PetscSF        partSF, pointSF, coneSF;
3115   ISLocalToGlobalMapping renumbering;
3116   PetscSection   originalConeSection, newConeSection;
3117   PetscInt      *remoteOffsets;
3118   PetscInt      *cones, *newCones, newConesSize;
3119   PetscBool      flg;
3120   PetscMPIInt    rank, numProcs, p;
3121   PetscErrorCode ierr;
3122 
3123   PetscFunctionBegin;
3124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3125   PetscValidPointer(dmParallel,4);
3126   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3127   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3128   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3129   *dmParallel = PETSC_NULL;
3130   if (numProcs == 1) PetscFunctionReturn(0);
3131 
3132   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3133   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3134   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3135   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3136   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3137   if (!rank) {
3138     numRemoteRanks = numProcs;
3139   } else {
3140     numRemoteRanks = 0;
3141   }
3142   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3143   for (p = 0; p < numRemoteRanks; ++p) {
3144     remoteRanks[p].rank  = p;
3145     remoteRanks[p].index = 0;
3146   }
3147   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3148   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3149   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3150   if (flg) {
3151     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3152     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3153     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3154     if (origCellPart) {
3155       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3156       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3157       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3158     }
3159     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3160   }
3161   /* Close the partition over the mesh */
3162   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3163   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3164   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3165   /* Create new mesh */
3166   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3167   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3168   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3169   pmesh = (DM_Plex *) (*dmParallel)->data;
3170   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3171   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3172   if (flg) {
3173     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3174     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3175     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3176     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3177     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3178     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3179   }
3180   /* Distribute cone section */
3181   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3182   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3183   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3184   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3185   {
3186     PetscInt pStart, pEnd, p;
3187 
3188     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3189     for (p = pStart; p < pEnd; ++p) {
3190       PetscInt coneSize;
3191       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3192       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3193     }
3194   }
3195   /* Communicate and renumber cones */
3196   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3197   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3198   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3199   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3200   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3201   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3202   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3203   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3204   if (flg) {
3205     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3206     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3207     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3208     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3209     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3210   }
3211   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3212   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3213   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3214   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3215   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3216   /* Create supports and stratify sieve */
3217   {
3218     PetscInt pStart, pEnd;
3219 
3220     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3221     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3222   }
3223   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3224   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3225   /* Distribute Coordinates */
3226   {
3227     PetscSection originalCoordSection, newCoordSection;
3228     Vec          originalCoordinates, newCoordinates;
3229     const char  *name;
3230 
3231     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3232     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3233     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3234     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3235     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3236     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3237 
3238     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3239     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3240     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3241   }
3242   /* Distribute labels */
3243   {
3244     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3245     PetscInt   numLabels = 0, l;
3246 
3247     /* Bcast number of labels */
3248     while(next) {++numLabels; next = next->next;}
3249     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3250     next = mesh->labels;
3251     for (l = 0; l < numLabels; ++l) {
3252       DMLabel         newLabel;
3253       const PetscInt *partArray;
3254       char           *name;
3255       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3256       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3257       PetscInt        nameSize, s, p;
3258       PetscBool       isdepth;
3259       size_t          len = 0;
3260 
3261       /* Bcast name (could filter for no points) */
3262       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3263       nameSize = len;
3264       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3265       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3266       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3267       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3268       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3269       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3270       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3271       newLabel->name = name;
3272       /* Bcast numStrata (could filter for no points in stratum) */
3273       if (!rank) {newLabel->numStrata = next->numStrata;}
3274       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3275       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3276                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3277                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3278       /* Bcast stratumValues (could filter for no points in stratum) */
3279       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3280       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3281       /* Find size on each process and Scatter */
3282       if (!rank) {
3283         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3284         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3285         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3286         for (s = 0; s < next->numStrata; ++s) {
3287           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3288             const PetscInt point = next->points[p];
3289             PetscInt       proc;
3290 
3291             for (proc = 0; proc < numProcs; ++proc) {
3292               PetscInt dof, off, pPart;
3293 
3294               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3295               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3296               for (pPart = off; pPart < off+dof; ++pPart) {
3297                 if (partArray[pPart] == point) {
3298                   ++stratumSizes[proc*next->numStrata+s];
3299                   break;
3300                 }
3301               }
3302             }
3303           }
3304         }
3305         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3306       }
3307       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3308       /* Calculate stratumOffsets */
3309       newLabel->stratumOffsets[0] = 0;
3310       for (s = 0; s < newLabel->numStrata; ++s) {
3311         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3312       }
3313       /* Pack points and Scatter */
3314       if (!rank) {
3315         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3316         displs[0] = 0;
3317         for (p = 0; p < numProcs; ++p) {
3318           sendcnts[p] = 0;
3319           for (s = 0; s < next->numStrata; ++s) {
3320             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3321           }
3322           offsets[p]  = displs[p];
3323           displs[p+1] = displs[p] + sendcnts[p];
3324         }
3325         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3326         for (s = 0; s < next->numStrata; ++s) {
3327           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3328             const PetscInt point = next->points[p];
3329             PetscInt       proc;
3330 
3331             for (proc = 0; proc < numProcs; ++proc) {
3332               PetscInt dof, off, pPart;
3333 
3334               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3335               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3336               for (pPart = off; pPart < off+dof; ++pPart) {
3337                 if (partArray[pPart] == point) {
3338                   points[offsets[proc]++] = point;
3339                   break;
3340                 }
3341               }
3342             }
3343           }
3344         }
3345       }
3346       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3347       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3348       ierr = PetscFree(points);CHKERRQ(ierr);
3349       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3350       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3351       /* Renumber points */
3352       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3353       /* Sort points */
3354       for (s = 0; s < newLabel->numStrata; ++s) {
3355         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3356       }
3357       /* Insert into list */
3358       if (newNext) {
3359         newNext->next = newLabel;
3360       } else {
3361         pmesh->labels = newLabel;
3362       }
3363       newNext = newLabel;
3364       if (!rank) {next = next->next;}
3365     }
3366   }
3367   /* Cleanup Partition */
3368   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3369   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3370   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3371   ierr = ISDestroy(&part);CHKERRQ(ierr);
3372   /* Create point SF for parallel mesh */
3373   {
3374     const PetscInt *leaves;
3375     PetscSFNode    *remotePoints, *rowners, *lowners;
3376     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3377     PetscInt        pStart, pEnd;
3378 
3379     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3380     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3381     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3382     for (p=0; p<numRoots; p++) {
3383       rowners[p].rank = -1;
3384       rowners[p].index = -1;
3385     }
3386     if (origCellPart) {
3387       /* Make sure cells in the original partition are not assigned to other procs */
3388       const PetscInt *origCells;
3389 
3390       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3391       for (p = 0; p < numProcs; ++p) {
3392         PetscInt dof, off, d;
3393 
3394         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3395         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3396         for(d = off; d < off+dof; ++d) {
3397           rowners[origCells[d]].rank = p;
3398         }
3399       }
3400       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3401     }
3402     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3403     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3404 
3405     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3406     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3407     for (p = 0; p < numLeaves; ++p) {
3408       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3409         lowners[p].rank = rank;
3410         lowners[p].index = leaves ? leaves[p] : p;
3411       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3412         lowners[p].rank = -2;
3413         lowners[p].index = -2;
3414       }
3415     }
3416     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3417       rowners[p].rank = -3;
3418       rowners[p].index = -3;
3419     }
3420     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3421     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3422     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3423     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3424     for (p = 0; p < numLeaves; ++p) {
3425       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3426       if (lowners[p].rank != rank) ++numGhostPoints;
3427     }
3428     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3429     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3430     for (p = 0, gp = 0; p < numLeaves; ++p) {
3431       if (lowners[p].rank != rank) {
3432         ghostPoints[gp]       = leaves ? leaves[p] : p;
3433         remotePoints[gp].rank  = lowners[p].rank;
3434         remotePoints[gp].index = lowners[p].index;
3435         ++gp;
3436       }
3437     }
3438     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3439     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3440     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3441   }
3442   /* Cleanup */
3443   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3444   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3445   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3446   PetscFunctionReturn(0);
3447 }
3448 
3449 #undef __FUNCT__
3450 #define __FUNCT__ "DMPlexRenumber_Private"
3451 /*
3452   Reasons to renumber:
3453 
3454   1) Permute points, e.g. bandwidth reduction (Renumber)
3455 
3456     a) Must not mix strata
3457 
3458   2) Shift numbers for point insertion (Shift)
3459 
3460     a) Want operation brken into parts so that insertion can be interleaved
3461 
3462   renumbering - An IS which provides the new numbering
3463 */
3464 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3465 {
3466   PetscFunctionBegin;
3467   PetscFunctionReturn(0);
3468 }
3469 
3470 #undef __FUNCT__
3471 #define __FUNCT__ "DMPlexShiftPoint_Private"
3472 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3473 {
3474   if (depth < 0) return p;
3475   /* Cells    */ if (p < depthEnd[depth])   return p;
3476   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3477   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3478   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3479 }
3480 
3481 #undef __FUNCT__
3482 #define __FUNCT__ "DMPlexShiftSizes_Private"
3483 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3484 {
3485   PetscInt      *depthEnd;
3486   PetscInt       depth = 0, d, pStart, pEnd, p;
3487   PetscErrorCode ierr;
3488 
3489   PetscFunctionBegin;
3490   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3491   if (depth < 0) PetscFunctionReturn(0);
3492   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3493   /* Step 1: Expand chart */
3494   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3495   for(d = 0; d <= depth; ++d) {
3496     pEnd += depthShift[d];
3497     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3498   }
3499   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3500   /* Step 2: Set cone and support sizes */
3501   for(d = 0; d <= depth; ++d) {
3502     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3503     for(p = pStart; p < pEnd; ++p) {
3504       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3505       PetscInt size;
3506 
3507       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3508       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3509       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3510       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3511     }
3512   }
3513   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3514   PetscFunctionReturn(0);
3515 }
3516 
3517 #undef __FUNCT__
3518 #define __FUNCT__ "DMPlexShiftPoints_Private"
3519 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3520 {
3521   PetscInt      *depthEnd, *newpoints;
3522   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3523   PetscErrorCode ierr;
3524 
3525   PetscFunctionBegin;
3526   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3527   if (depth < 0) PetscFunctionReturn(0);
3528   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3529   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3530   for(d = 0; d <= depth; ++d) {
3531     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3532   }
3533   /* Step 5: Set cones and supports */
3534   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3535   for(p = pStart; p < pEnd; ++p) {
3536     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3537     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3538 
3539     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3540     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3541     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3542     for(i = 0; i < size; ++i) {
3543       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3544     }
3545     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3546     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3547     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3548     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3549     for(i = 0; i < size; ++i) {
3550       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3551     }
3552     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3553   }
3554   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3555   PetscFunctionReturn(0);
3556 }
3557 
3558 #undef __FUNCT__
3559 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3560 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3561 {
3562   PetscSection   coordSection, newCoordSection;
3563   Vec            coordinates;
3564   PetscInt      *depthEnd;
3565   PetscInt       dim, depth = 0, d, vStart, vEnd, v;
3566   PetscErrorCode ierr;
3567 
3568   PetscFunctionBegin;
3569   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3570   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3571   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3572   for(d = 0; d <= depth; ++d) {
3573     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3574   }
3575   /* Step 8: Convert coordinates */
3576   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3577   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3578   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3579   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3580   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3581   ierr = PetscSectionSetChart(newCoordSection, DMPlexShiftPoint_Private(vStart, depth, depthEnd, depthShift), DMPlexShiftPoint_Private(vEnd, depth, depthEnd, depthShift));CHKERRQ(ierr);
3582   for(v = vStart; v < vEnd; ++v) {
3583     const PetscInt newv = DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift);
3584     ierr = PetscSectionSetDof(newCoordSection, newv, dim);CHKERRQ(ierr);
3585     ierr = PetscSectionSetFieldDof(newCoordSection, newv, 0, dim);CHKERRQ(ierr);
3586   }
3587   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3588   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3589   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3590   ierr = DMSetCoordinatesLocal(dmNew, coordinates);CHKERRQ(ierr);
3591   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3592   PetscFunctionReturn(0);
3593 }
3594 
3595 #undef __FUNCT__
3596 #define __FUNCT__ "DMPlexShiftSF_Private"
3597 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3598 {
3599   PetscInt          *depthEnd;
3600   PetscInt           depth = 0, d;
3601   PetscSF            sfPoint, sfPointNew;
3602   const PetscSFNode *remotePoints;
3603   PetscSFNode       *gremotePoints;
3604   const PetscInt    *localPoints;
3605   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3606   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3607   PetscMPIInt        numProcs;
3608   PetscErrorCode     ierr;
3609 
3610   PetscFunctionBegin;
3611   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3612   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3613   for(d = 0; d <= depth; ++d) {
3614     totShift += depthShift[d];
3615     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3616   }
3617   /* Step 9: Convert pointSF */
3618   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3619   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3620   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3621   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3622   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3623   if (numRoots >= 0) {
3624     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3625     for(l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3626     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3627     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3628     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3629     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3630     for(l = 0; l < numLeaves; ++l) {
3631       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3632       gremotePoints[l].rank  = remotePoints[l].rank;
3633       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3634     }
3635     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3636     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3637   }
3638   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3639   PetscFunctionReturn(0);
3640 }
3641 
3642 #undef __FUNCT__
3643 #define __FUNCT__ "DMPlexShiftLabels_Private"
3644 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3645 {
3646   PetscSF        sfPoint;
3647   DMLabel        vtkLabel, ghostLabel;
3648   PetscInt      *depthEnd;
3649   const PetscSFNode *leafRemote;
3650   const PetscInt    *leafLocal;
3651   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3652   PetscMPIInt    rank;
3653   PetscErrorCode ierr;
3654 
3655   PetscFunctionBegin;
3656   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3657   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3658   for(d = 0; d <= depth; ++d) {
3659     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3660   }
3661   /* Step 10: Convert labels */
3662   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3663   for(l = 0; l < numLabels; ++l) {
3664     DMLabel         label, newlabel;
3665     const char     *lname;
3666     PetscBool       isDepth;
3667     IS              valueIS;
3668     const PetscInt *values;
3669     PetscInt        numValues, val;
3670 
3671     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3672     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3673     if (isDepth) continue;
3674     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3675     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3676     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3677     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3678     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3679     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3680     for(val = 0; val < numValues; ++val) {
3681       IS              pointIS;
3682       const PetscInt *points;
3683       PetscInt        numPoints, p;
3684 
3685       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3686       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3687       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3688       for(p = 0; p < numPoints; ++p) {
3689         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3690 
3691         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3692       }
3693       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3694       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3695     }
3696     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3697     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3698   }
3699   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3700   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3701   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3702   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3703   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3704   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3705   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3706   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3707   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3708   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3709   for(l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3710     for(; c < leafLocal[l] && c < cEnd; ++c) {
3711       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3712     }
3713     if (leafLocal[l] >= cEnd) break;
3714     if (leafRemote[l].rank == rank) {
3715       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3716     } else {
3717       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3718     }
3719   }
3720   for(; c < cEnd; ++c) {
3721     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3722   }
3723   if (0) {
3724     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3725     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3726     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3727   }
3728   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3729   for(f = fStart; f < fEnd; ++f) {
3730     PetscInt numCells;
3731 
3732     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3733     if (numCells < 2) {
3734       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3735     } else {
3736       const PetscInt *cells = PETSC_NULL;
3737       PetscInt        vA, vB;
3738 
3739       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3740       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3741       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3742       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3743     }
3744   }
3745   if (0) {
3746     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3747     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3748     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3749   }
3750   PetscFunctionReturn(0);
3751 }
3752 
3753 #undef __FUNCT__
3754 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3755 /*@C
3756   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3757 
3758   Collective on dm
3759 
3760   Input Parameters:
3761 + dm - The original DM
3762 - labelName - The label specifying the boundary faces (this could be auto-generated)
3763 
3764   Output Parameters:
3765 + numGhostCells - The number of ghost cells added to the DM
3766 - dmGhosted - The new DM
3767 
3768   Level: developer
3769 
3770 .seealso: DMCreate()
3771 */
3772 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3773 {
3774   DMLabel         label;
3775   IS              valueIS;
3776   const PetscInt *values;
3777   PetscInt       *depthShift;
3778   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3779   PetscErrorCode  ierr;
3780 
3781   PetscFunctionBegin;
3782   /* Count ghost cells */
3783   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3784   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3785   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3786   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3787   *numGhostCells = 0;
3788   for(fs = 0; fs < numFS; ++fs) {
3789     PetscInt numBdFaces;
3790 
3791     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3792     *numGhostCells += numBdFaces;
3793   }
3794   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3795   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3796   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3797   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3798   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3799   /* Step 3: Set cone/support sizes for new points */
3800   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3801   for(c = cEnd; c < cEnd + *numGhostCells; ++c) {
3802     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3803   }
3804   for(fs = 0; fs < numFS; ++fs) {
3805     IS              faceIS;
3806     const PetscInt *faces;
3807     PetscInt        numFaces, f;
3808 
3809     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3810     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3811     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3812     for(f = 0; f < numFaces; ++f) {
3813       PetscInt size;
3814 
3815       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3816       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3817       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3818     }
3819     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3820     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3821   }
3822   /* Step 4: Setup ghosted DM */
3823   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3824   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3825   /* Step 6: Set cones and supports for new points */
3826   ghostCell = cEnd;
3827   for(fs = 0; fs < numFS; ++fs) {
3828     IS              faceIS;
3829     const PetscInt *faces;
3830     PetscInt        numFaces, f;
3831 
3832     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3833     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3834     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3835     for(f = 0; f < numFaces; ++f, ++ghostCell) {
3836       PetscInt newFace = faces[f] + *numGhostCells;
3837 
3838       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3839       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3840     }
3841     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3842     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3843   }
3844   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3845   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3846   /* Step 7: Stratify */
3847   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3848   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3849   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3850   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3851   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3852   PetscFunctionReturn(0);
3853 }
3854 
3855 #undef __FUNCT__
3856 #define __FUNCT__ "DMPlexConstructGhostCells"
3857 /*@C
3858   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3859 
3860   Collective on dm
3861 
3862   Input Parameters:
3863 + dm - The original DM
3864 - labelName - The label specifying the boundary faces (this could be auto-generated)
3865 
3866   Output Parameters:
3867 + numGhostCells - The number of ghost cells added to the DM
3868 - dmGhosted - The new DM
3869 
3870   Level: developer
3871 
3872 .seealso: DMCreate()
3873 */
3874 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3875 {
3876   DM             gdm;
3877   PetscInt       dim;
3878   PetscErrorCode ierr;
3879 
3880   PetscFunctionBegin;
3881   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3882   PetscValidPointer(numGhostCells, 3);
3883   PetscValidPointer(dmGhosted, 4);
3884   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3885   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3886   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3887   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3888   switch(dim) {
3889   case 2:
3890     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3891     break;
3892   default:
3893     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3894   }
3895   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3896   *dmGhosted = gdm;
3897   PetscFunctionReturn(0);
3898 }
3899 
3900 #undef __FUNCT__
3901 #define __FUNCT__ "DMPlexInterpolate_2D"
3902 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
3903 {
3904   DM             idm;
3905   DM_Plex    *mesh;
3906   PetscHashIJ    edgeTable;
3907   PetscInt      *off;
3908   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
3909   PetscInt       numEdges, firstEdge, edge, e;
3910   PetscErrorCode ierr;
3911 
3912   PetscFunctionBegin;
3913   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3914   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3915   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3916   numCells    = cEnd - cStart;
3917   numVertices = vEnd - vStart;
3918   firstEdge   = numCells + numVertices;
3919   numEdges    = 0 ;
3920   /* Count edges using algorithm from CreateNeighborCSR */
3921   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
3922   if (off) {
3923     PetscInt numCorners = 0;
3924 
3925     numEdges = off[numCells]/2;
3926 #if 0
3927     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
3928     numEdges += 3*numCells - off[numCells];
3929 #else
3930     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
3931     for(c = cStart; c < cEnd; ++c) {
3932       PetscInt coneSize;
3933 
3934       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
3935       numCorners += coneSize;
3936     }
3937     numEdges += numCorners - off[numCells];
3938 #endif
3939   }
3940 #if 0
3941   /* Check Euler characteristic V - E + F = 1 */
3942   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
3943 #endif
3944   /* Create interpolated mesh */
3945   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
3946   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
3947   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
3948   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
3949   for (c = 0; c < numCells; ++c) {
3950     PetscInt numCorners;
3951 
3952     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
3953     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
3954   }
3955   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
3956     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
3957   }
3958   ierr = DMSetUp(idm);CHKERRQ(ierr);
3959   /* Get edge cones from subsets of cell vertices */
3960   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
3961   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
3962 
3963   for (c = 0, edge = firstEdge; c < numCells; ++c) {
3964     const PetscInt *cellFaces;
3965     PetscInt        numCellFaces, faceSize, cf;
3966 
3967     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
3968     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
3969     for (cf = 0; cf < numCellFaces; ++cf) {
3970 #if 1
3971       PetscHashIJKey key = {PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]),
3972                             PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1])};
3973 
3974       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
3975       if (e < 0) {
3976         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3977         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
3978         e    = edge++;
3979       }
3980 #else
3981       PetscBool found = PETSC_FALSE;
3982 
3983       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
3984       for (e = firstEdge; e < edge; ++e) {
3985         const PetscInt *cone;
3986 
3987         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
3988         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
3989             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
3990           found = PETSC_TRUE;
3991           break;
3992         }
3993       }
3994       if (!found) {
3995         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3996         ++edge;
3997       }
3998 #endif
3999       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4000     }
4001   }
4002   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4003   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4004   ierr = PetscFree(off);CHKERRQ(ierr);
4005   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4006   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4007   mesh = (DM_Plex *) (idm)->data;
4008   /* Orient edges */
4009   for (c = 0; c < numCells; ++c) {
4010     const PetscInt *cone = PETSC_NULL, *cellFaces;
4011     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4012 
4013     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4014     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4015     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4016     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4017     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4018     for (cf = 0; cf < numCellFaces; ++cf) {
4019       const PetscInt *econe = PETSC_NULL;
4020       PetscInt        esize;
4021 
4022       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4023       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4024       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]);
4025       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4026         /* Correctly oriented */
4027         mesh->coneOrientations[coff+cf] = 0;
4028       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4029         /* Start at index 1, and reverse orientation */
4030         mesh->coneOrientations[coff+cf] = -(1+1);
4031       }
4032     }
4033   }
4034   *dmInt  = idm;
4035   PetscFunctionReturn(0);
4036 }
4037 
4038 #undef __FUNCT__
4039 #define __FUNCT__ "DMPlexInterpolate_3D"
4040 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4041 {
4042   DM             idm, fdm;
4043   DM_Plex    *mesh;
4044   PetscInt      *off;
4045   const PetscInt numCorners = 4;
4046   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4047   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4048   PetscErrorCode ierr;
4049 
4050   PetscFunctionBegin;
4051   {
4052     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4053     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4054     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4055   }
4056   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4057   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4058   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4059   numCells    = cEnd - cStart;
4060   numVertices = vEnd - vStart;
4061   firstFace   = numCells + numVertices;
4062   numFaces    = 0 ;
4063   /* Count faces using algorithm from CreateNeighborCSR */
4064   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4065   if (off) {
4066     numFaces = off[numCells]/2;
4067     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4068     numFaces += 4*numCells - off[numCells];
4069   }
4070   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4071   firstEdge = firstFace + numFaces;
4072   numEdges  = numVertices + numFaces - numCells - 1;
4073   /* Create interpolated mesh */
4074   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4075   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4076   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4077   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4078   for (c = 0; c < numCells; ++c) {
4079     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4080   }
4081   for (f = firstFace; f < firstFace+numFaces; ++f) {
4082     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4083   }
4084   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4085     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4086   }
4087   ierr = DMSetUp(idm);CHKERRQ(ierr);
4088   /* Get face cones from subsets of cell vertices */
4089   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4090   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4091   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4092   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4093   for (f = firstFace; f < firstFace+numFaces; ++f) {
4094     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4095   }
4096   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4097   for (c = 0, face = firstFace; c < numCells; ++c) {
4098     const PetscInt *cellFaces;
4099     PetscInt        numCellFaces, faceSize, cf;
4100 
4101     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4102     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4103     for (cf = 0; cf < numCellFaces; ++cf) {
4104       PetscBool found = PETSC_FALSE;
4105 
4106       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4107       for (f = firstFace; f < face; ++f) {
4108         const PetscInt *cone = PETSC_NULL;
4109 
4110         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4111         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4112             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4113             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4114             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4115             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4116             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4117           found = PETSC_TRUE;
4118           break;
4119         }
4120       }
4121       if (!found) {
4122         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4123         /* Save the vertices for orientation calculation */
4124         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4125         ++face;
4126       }
4127       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4128     }
4129   }
4130   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4131   /* Get edge cones from subsets of face vertices */
4132   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4133     const PetscInt *cellFaces;
4134     PetscInt        numCellFaces, faceSize, cf;
4135 
4136     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4137     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4138     for (cf = 0; cf < numCellFaces; ++cf) {
4139       PetscBool found = PETSC_FALSE;
4140 
4141       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4142       for (e = firstEdge; e < edge; ++e) {
4143         const PetscInt *cone = PETSC_NULL;
4144 
4145         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4146         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4147             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4148           found = PETSC_TRUE;
4149           break;
4150         }
4151       }
4152       if (!found) {
4153         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4154         ++edge;
4155       }
4156       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4157     }
4158   }
4159   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4160   ierr = PetscFree(off);CHKERRQ(ierr);
4161   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4162   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4163   mesh = (DM_Plex *) (idm)->data;
4164   /* Orient edges */
4165   for (f = firstFace; f < firstFace+numFaces; ++f) {
4166     const PetscInt *cone, *cellFaces;
4167     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4168 
4169     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4170     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4171     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4172     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4173     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4174     for (cf = 0; cf < numCellFaces; ++cf) {
4175       const PetscInt *econe;
4176       PetscInt        esize;
4177 
4178       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4179       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4180       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]);
4181       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4182         /* Correctly oriented */
4183         mesh->coneOrientations[coff+cf] = 0;
4184       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4185         /* Start at index 1, and reverse orientation */
4186         mesh->coneOrientations[coff+cf] = -(1+1);
4187       }
4188     }
4189   }
4190   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4191   /* Orient faces */
4192   for (c = 0; c < numCells; ++c) {
4193     const PetscInt *cone, *cellFaces;
4194     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4195 
4196     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4197     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4198     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4199     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4200     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4201     for (cf = 0; cf < numCellFaces; ++cf) {
4202       PetscInt *origClosure = PETSC_NULL, *closure;
4203       PetscInt  closureSize, i;
4204 
4205       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4206       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4207       for (i = 4; i < 7; ++i) {
4208         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);
4209       }
4210       closure = &origClosure[4*2];
4211       /* Remember that this is the orientation for edges, not vertices */
4212       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4213         /* Correctly oriented */
4214         mesh->coneOrientations[coff+cf] = 0;
4215       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4216         /* Shifted by 1 */
4217         mesh->coneOrientations[coff+cf] = 1;
4218       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4219         /* Shifted by 2 */
4220         mesh->coneOrientations[coff+cf] = 2;
4221       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4222         /* Start at edge 1, and reverse orientation */
4223         mesh->coneOrientations[coff+cf] = -(1+1);
4224       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4225         /* Start at index 0, and reverse orientation */
4226         mesh->coneOrientations[coff+cf] = -(0+1);
4227       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4228         /* Start at index 2, and reverse orientation */
4229         mesh->coneOrientations[coff+cf] = -(2+1);
4230       } 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);
4231       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4232     }
4233   }
4234   {
4235     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4236     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4237     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4238   }
4239   *dmInt  = idm;
4240   PetscFunctionReturn(0);
4241 }
4242 
4243 #undef __FUNCT__
4244 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4245 /*
4246   This takes as input the common mesh generator output, a list of the vertices for each cell
4247 */
4248 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4249 {
4250   PetscInt      *cone, c, p;
4251   PetscErrorCode ierr;
4252 
4253   PetscFunctionBegin;
4254   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4255   for (c = 0; c < numCells; ++c) {
4256     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4257   }
4258   ierr = DMSetUp(dm);CHKERRQ(ierr);
4259   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4260   for (c = 0; c < numCells; ++c) {
4261     for (p = 0; p < numCorners; ++p) {
4262       cone[p] = cells[c*numCorners+p]+numCells;
4263     }
4264     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4265   }
4266   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4267   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4268   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4269   PetscFunctionReturn(0);
4270 }
4271 
4272 #undef __FUNCT__
4273 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4274 /*
4275   This takes as input the coordinates for each vertex
4276 */
4277 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4278 {
4279   PetscSection   coordSection;
4280   Vec            coordinates;
4281   PetscScalar   *coords;
4282   PetscInt       coordSize, v, d;
4283   PetscErrorCode ierr;
4284 
4285   PetscFunctionBegin;
4286   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4287   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4288   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4289   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4290   for (v = numCells; v < numCells+numVertices; ++v) {
4291     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4292     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4293   }
4294   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4295   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4296   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4297   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4298   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4299   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4300   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4301   for (v = 0; v < numVertices; ++v) {
4302     for (d = 0; d < spaceDim; ++d) {
4303       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4304     }
4305   }
4306   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4307   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4308   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4309   PetscFunctionReturn(0);
4310 }
4311 
4312 #undef __FUNCT__
4313 #define __FUNCT__ "DMPlexCreateFromCellList"
4314 /*
4315   This takes as input the common mesh generator output, a list of the vertices for each cell
4316 */
4317 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4318 {
4319   PetscErrorCode ierr;
4320 
4321   PetscFunctionBegin;
4322   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4323   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4324   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4325   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4326   if (interpolate) {
4327     DM idm;
4328 
4329     switch(dim) {
4330     case 2:
4331       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4332     case 3:
4333       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4334     default:
4335       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4336     }
4337     ierr = DMDestroy(dm);CHKERRQ(ierr);
4338     *dm  = idm;
4339   }
4340   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4341   PetscFunctionReturn(0);
4342 }
4343 
4344 #ifdef PETSC_HAVE_TRIANGLE
4345 #include <triangle.h>
4346 
4347 #undef __FUNCT__
4348 #define __FUNCT__ "InitInput_Triangle"
4349 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx) {
4350   PetscFunctionBegin;
4351   inputCtx->numberofpoints = 0;
4352   inputCtx->numberofpointattributes = 0;
4353   inputCtx->pointlist = PETSC_NULL;
4354   inputCtx->pointattributelist = PETSC_NULL;
4355   inputCtx->pointmarkerlist = PETSC_NULL;
4356   inputCtx->numberofsegments = 0;
4357   inputCtx->segmentlist = PETSC_NULL;
4358   inputCtx->segmentmarkerlist = PETSC_NULL;
4359   inputCtx->numberoftriangleattributes = 0;
4360   inputCtx->trianglelist = PETSC_NULL;
4361   inputCtx->numberofholes = 0;
4362   inputCtx->holelist = PETSC_NULL;
4363   inputCtx->numberofregions = 0;
4364   inputCtx->regionlist = PETSC_NULL;
4365   PetscFunctionReturn(0);
4366 }
4367 
4368 #undef __FUNCT__
4369 #define __FUNCT__ "InitOutput_Triangle"
4370 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx) {
4371   PetscFunctionBegin;
4372   outputCtx->numberofpoints = 0;
4373   outputCtx->pointlist = PETSC_NULL;
4374   outputCtx->pointattributelist = PETSC_NULL;
4375   outputCtx->pointmarkerlist = PETSC_NULL;
4376   outputCtx->numberoftriangles = 0;
4377   outputCtx->trianglelist = PETSC_NULL;
4378   outputCtx->triangleattributelist = PETSC_NULL;
4379   outputCtx->neighborlist = PETSC_NULL;
4380   outputCtx->segmentlist = PETSC_NULL;
4381   outputCtx->segmentmarkerlist = PETSC_NULL;
4382   outputCtx->numberofedges = 0;
4383   outputCtx->edgelist = PETSC_NULL;
4384   outputCtx->edgemarkerlist = PETSC_NULL;
4385   PetscFunctionReturn(0);
4386 }
4387 
4388 #undef __FUNCT__
4389 #define __FUNCT__ "FiniOutput_Triangle"
4390 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx) {
4391   PetscFunctionBegin;
4392   free(outputCtx->pointmarkerlist);
4393   free(outputCtx->edgelist);
4394   free(outputCtx->edgemarkerlist);
4395   free(outputCtx->trianglelist);
4396   free(outputCtx->neighborlist);
4397   PetscFunctionReturn(0);
4398 }
4399 
4400 #undef __FUNCT__
4401 #define __FUNCT__ "DMPlexGenerate_Triangle"
4402 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4403 {
4404   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4405   PetscInt             dim              = 2;
4406   const PetscBool      createConvexHull = PETSC_FALSE;
4407   const PetscBool      constrained      = PETSC_FALSE;
4408   struct triangulateio in;
4409   struct triangulateio out;
4410   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4411   PetscMPIInt          rank;
4412   PetscErrorCode       ierr;
4413 
4414   PetscFunctionBegin;
4415   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4416   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4417   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4418   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4419   in.numberofpoints = vEnd - vStart;
4420   if (in.numberofpoints > 0) {
4421     PetscSection coordSection;
4422     Vec          coordinates;
4423     PetscScalar *array;
4424 
4425     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4426     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4427     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4428     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4429     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4430     for (v = vStart; v < vEnd; ++v) {
4431       const PetscInt idx = v - vStart;
4432       PetscInt       off, d;
4433 
4434       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4435       for (d = 0; d < dim; ++d) {
4436         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4437       }
4438       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4439     }
4440     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4441   }
4442   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4443   in.numberofsegments = eEnd - eStart;
4444   if (in.numberofsegments > 0) {
4445     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4446     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4447     for (e = eStart; e < eEnd; ++e) {
4448       const PetscInt  idx = e - eStart;
4449       const PetscInt *cone;
4450 
4451       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4452       in.segmentlist[idx*2+0] = cone[0] - vStart;
4453       in.segmentlist[idx*2+1] = cone[1] - vStart;
4454       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4455     }
4456   }
4457 #if 0 /* Do not currently support holes */
4458   PetscReal *holeCoords;
4459   PetscInt   h, d;
4460 
4461   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4462   if (in.numberofholes > 0) {
4463     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4464     for (h = 0; h < in.numberofholes; ++h) {
4465       for (d = 0; d < dim; ++d) {
4466         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4467       }
4468     }
4469   }
4470 #endif
4471   if (!rank) {
4472     char args[32];
4473 
4474     /* Take away 'Q' for verbose output */
4475     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4476     if (createConvexHull) {
4477       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4478     }
4479     if (constrained) {
4480       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4481     }
4482     triangulate(args, &in, &out, PETSC_NULL);
4483   }
4484   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4485   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4486   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4487   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4488   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4489 
4490   {
4491     const PetscInt numCorners  = 3;
4492     const PetscInt numCells    = out.numberoftriangles;
4493     const PetscInt numVertices = out.numberofpoints;
4494     const int     *cells       = out.trianglelist;
4495     const double  *meshCoords  = out.pointlist;
4496 
4497     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4498     /* Set labels */
4499     for (v = 0; v < numVertices; ++v) {
4500       if (out.pointmarkerlist[v]) {
4501         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4502       }
4503     }
4504     if (interpolate) {
4505       for (e = 0; e < out.numberofedges; e++) {
4506         if (out.edgemarkerlist[e]) {
4507           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4508           const PetscInt *edges;
4509           PetscInt        numEdges;
4510 
4511           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4512           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4513           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4514           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4515         }
4516       }
4517     }
4518     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4519   }
4520 #if 0 /* Do not currently support holes */
4521   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4522 #endif
4523   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4524   PetscFunctionReturn(0);
4525 }
4526 
4527 #undef __FUNCT__
4528 #define __FUNCT__ "DMPlexRefine_Triangle"
4529 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4530 {
4531   MPI_Comm             comm = ((PetscObject) dm)->comm;
4532   PetscInt             dim  = 2;
4533   struct triangulateio in;
4534   struct triangulateio out;
4535   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4536   PetscMPIInt          rank;
4537   PetscErrorCode       ierr;
4538 
4539   PetscFunctionBegin;
4540   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4541   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4542   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4543   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4544   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4545   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4546   in.numberofpoints = vEnd - vStart;
4547   if (in.numberofpoints > 0) {
4548     PetscSection coordSection;
4549     Vec          coordinates;
4550     PetscScalar *array;
4551 
4552     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4553     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4554     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4555     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4556     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4557     for (v = vStart; v < vEnd; ++v) {
4558       const PetscInt idx = v - vStart;
4559       PetscInt       off, d;
4560 
4561       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4562       for (d = 0; d < dim; ++d) {
4563         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4564       }
4565       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4566     }
4567     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4568   }
4569   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4570   in.numberofcorners   = 3;
4571   in.numberoftriangles = cEnd - cStart;
4572   in.trianglearealist  = (double *) maxVolumes;
4573   if (in.numberoftriangles > 0) {
4574     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4575     for (c = cStart; c < cEnd; ++c) {
4576       const PetscInt idx     = c - cStart;
4577       PetscInt      *closure = PETSC_NULL;
4578       PetscInt       closureSize;
4579 
4580       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4581       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4582       for (v = 0; v < 3; ++v) {
4583         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4584       }
4585       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4586     }
4587   }
4588   /* TODO: Segment markers are missing on input */
4589 #if 0 /* Do not currently support holes */
4590   PetscReal *holeCoords;
4591   PetscInt   h, d;
4592 
4593   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4594   if (in.numberofholes > 0) {
4595     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4596     for (h = 0; h < in.numberofholes; ++h) {
4597       for (d = 0; d < dim; ++d) {
4598         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4599       }
4600     }
4601   }
4602 #endif
4603   if (!rank) {
4604     char args[32];
4605 
4606     /* Take away 'Q' for verbose output */
4607     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4608     triangulate(args, &in, &out, PETSC_NULL);
4609   }
4610   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4611   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4612   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4613   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4614   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4615 
4616   {
4617     const PetscInt numCorners  = 3;
4618     const PetscInt numCells    = out.numberoftriangles;
4619     const PetscInt numVertices = out.numberofpoints;
4620     const int     *cells       = out.trianglelist;
4621     const double  *meshCoords  = out.pointlist;
4622     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4623 
4624     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4625     /* Set labels */
4626     for (v = 0; v < numVertices; ++v) {
4627       if (out.pointmarkerlist[v]) {
4628         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4629       }
4630     }
4631     if (interpolate) {
4632       PetscInt e;
4633 
4634       for (e = 0; e < out.numberofedges; e++) {
4635         if (out.edgemarkerlist[e]) {
4636           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4637           const PetscInt *edges;
4638           PetscInt        numEdges;
4639 
4640           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4641           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4642           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4643           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4644         }
4645       }
4646     }
4647     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4648   }
4649 #if 0 /* Do not currently support holes */
4650   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4651 #endif
4652   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4653   PetscFunctionReturn(0);
4654 }
4655 #endif
4656 
4657 #ifdef PETSC_HAVE_TETGEN
4658 #include <tetgen.h>
4659 #undef __FUNCT__
4660 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4661 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4662 {
4663   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4664   const PetscInt dim  = 3;
4665   ::tetgenio     in;
4666   ::tetgenio     out;
4667   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4668   PetscMPIInt    rank;
4669   PetscErrorCode ierr;
4670 
4671   PetscFunctionBegin;
4672   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4673   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4674   in.numberofpoints = vEnd - vStart;
4675   if (in.numberofpoints > 0) {
4676     PetscSection coordSection;
4677     Vec          coordinates;
4678     PetscScalar *array;
4679 
4680     in.pointlist       = new double[in.numberofpoints*dim];
4681     in.pointmarkerlist = new int[in.numberofpoints];
4682     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4683     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4684     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4685     for (v = vStart; v < vEnd; ++v) {
4686       const PetscInt idx = v - vStart;
4687       PetscInt       off, d;
4688 
4689       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4690       for (d = 0; d < dim; ++d) {
4691         in.pointlist[idx*dim + d] = array[off+d];
4692       }
4693       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4694     }
4695     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4696   }
4697   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4698   in.numberoffacets = fEnd - fStart;
4699   if (in.numberoffacets > 0) {
4700     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4701     in.facetmarkerlist = new int[in.numberoffacets];
4702     for (f = fStart; f < fEnd; ++f) {
4703       const PetscInt idx    = f - fStart;
4704       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
4705 
4706       in.facetlist[idx].numberofpolygons = 1;
4707       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4708       in.facetlist[idx].numberofholes    = 0;
4709       in.facetlist[idx].holelist         = NULL;
4710 
4711       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4712       for (p = 0; p < numPoints*2; p += 2) {
4713         const PetscInt point = points[p];
4714         if ((point >= vStart) && (point < vEnd)) {
4715           points[numVertices++] = point;
4716         }
4717       }
4718 
4719       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4720       poly->numberofvertices = numVertices;
4721       poly->vertexlist       = new int[poly->numberofvertices];
4722       for (v = 0; v < numVertices; ++v) {
4723         const PetscInt vIdx = points[v] - vStart;
4724         poly->vertexlist[v] = vIdx;
4725       }
4726       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4727       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4728     }
4729   }
4730   if (!rank) {
4731     char args[32];
4732 
4733     /* Take away 'Q' for verbose output */
4734     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4735     ::tetrahedralize(args, &in, &out);
4736   }
4737   {
4738     const PetscInt numCorners  = 4;
4739     const PetscInt numCells    = out.numberoftetrahedra;
4740     const PetscInt numVertices = out.numberofpoints;
4741     const int     *cells       = out.tetrahedronlist;
4742     const double  *meshCoords  = out.pointlist;
4743 
4744     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4745     /* Set labels */
4746     for (v = 0; v < numVertices; ++v) {
4747       if (out.pointmarkerlist[v]) {
4748         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4749       }
4750     }
4751     if (interpolate) {
4752       PetscInt e;
4753 
4754       for (e = 0; e < out.numberofedges; e++) {
4755         if (out.edgemarkerlist[e]) {
4756           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4757           const PetscInt *edges;
4758           PetscInt        numEdges;
4759 
4760           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4761           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4762           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4763           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4764         }
4765       }
4766       for (f = 0; f < out.numberoftrifaces; f++) {
4767         if (out.trifacemarkerlist[f]) {
4768           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4769           const PetscInt *faces;
4770           PetscInt        numFaces;
4771 
4772           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4773           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4774           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4775           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4776         }
4777       }
4778     }
4779     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4780   }
4781   PetscFunctionReturn(0);
4782 }
4783 
4784 #undef __FUNCT__
4785 #define __FUNCT__ "DMPlexRefine_Tetgen"
4786 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4787 {
4788   MPI_Comm       comm = ((PetscObject) dm)->comm;
4789   const PetscInt dim  = 3;
4790   ::tetgenio     in;
4791   ::tetgenio     out;
4792   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4793   PetscMPIInt    rank;
4794   PetscErrorCode ierr;
4795 
4796   PetscFunctionBegin;
4797   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4798   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4799   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4800   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4801   in.numberofpoints = vEnd - vStart;
4802   if (in.numberofpoints > 0) {
4803     PetscSection coordSection;
4804     Vec          coordinates;
4805     PetscScalar *array;
4806 
4807     in.pointlist       = new double[in.numberofpoints*dim];
4808     in.pointmarkerlist = new int[in.numberofpoints];
4809     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4810     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4811     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4812     for (v = vStart; v < vEnd; ++v) {
4813       const PetscInt idx = v - vStart;
4814       PetscInt       off, d;
4815 
4816       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4817       for (d = 0; d < dim; ++d) {
4818         in.pointlist[idx*dim + d] = array[off+d];
4819       }
4820       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4821     }
4822     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4823   }
4824   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4825   in.numberofcorners       = 4;
4826   in.numberoftetrahedra    = cEnd - cStart;
4827   in.tetrahedronvolumelist = (double *) maxVolumes;
4828   if (in.numberoftetrahedra > 0) {
4829     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
4830     for (c = cStart; c < cEnd; ++c) {
4831       const PetscInt idx     = c - cStart;
4832       PetscInt      *closure = PETSC_NULL;
4833       PetscInt       closureSize;
4834 
4835       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4836       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4837       for (v = 0; v < 4; ++v) {
4838         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4839       }
4840       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4841     }
4842   }
4843   // TODO: Put in boundary faces with markers
4844   if (!rank) {
4845     char args[32];
4846 
4847     /* Take away 'Q' for verbose output */
4848     //ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr);
4849     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
4850     ::tetrahedralize(args, &in, &out);
4851   }
4852   in.tetrahedronvolumelist = NULL;
4853 
4854   {
4855     const PetscInt numCorners  = 4;
4856     const PetscInt numCells    = out.numberoftetrahedra;
4857     const PetscInt numVertices = out.numberofpoints;
4858     const int     *cells       = out.tetrahedronlist;
4859     const double  *meshCoords  = out.pointlist;
4860     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4861 
4862     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4863     /* Set labels */
4864     for (v = 0; v < numVertices; ++v) {
4865       if (out.pointmarkerlist[v]) {
4866         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4867       }
4868     }
4869     if (interpolate) {
4870       PetscInt e, f;
4871 
4872       for (e = 0; e < out.numberofedges; e++) {
4873         if (out.edgemarkerlist[e]) {
4874           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4875           const PetscInt *edges;
4876           PetscInt        numEdges;
4877 
4878           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4879           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4880           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4881           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4882         }
4883       }
4884       for (f = 0; f < out.numberoftrifaces; f++) {
4885         if (out.trifacemarkerlist[f]) {
4886           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4887           const PetscInt *faces;
4888           PetscInt        numFaces;
4889 
4890           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4891           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4892           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4893           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4894         }
4895       }
4896     }
4897     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4898   }
4899   PetscFunctionReturn(0);
4900 }
4901 #endif
4902 
4903 #ifdef PETSC_HAVE_CTETGEN
4904 #include "ctetgen.h"
4905 
4906 #undef __FUNCT__
4907 #define __FUNCT__ "DMPlexGenerate_CTetgen"
4908 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4909 {
4910   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4911   const PetscInt dim  = 3;
4912   PLC           *in, *out;
4913   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4914   PetscMPIInt    rank;
4915   PetscErrorCode ierr;
4916 
4917   PetscFunctionBegin;
4918   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
4919   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4920   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4921   ierr = PLCCreate(&in);CHKERRQ(ierr);
4922   ierr = PLCCreate(&out);CHKERRQ(ierr);
4923   in->numberofpoints = vEnd - vStart;
4924   if (in->numberofpoints > 0) {
4925     PetscSection coordSection;
4926     Vec          coordinates;
4927     PetscScalar *array;
4928 
4929     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4930     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4931     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4932     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4933     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4934     for (v = vStart; v < vEnd; ++v) {
4935       const PetscInt idx = v - vStart;
4936       PetscInt       off, d, m;
4937 
4938       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4939       for (d = 0; d < dim; ++d) {
4940         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4941       }
4942       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
4943       in->pointmarkerlist[idx] = (int) m;
4944     }
4945     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4946   }
4947   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4948   in->numberoffacets = fEnd - fStart;
4949   if (in->numberoffacets > 0) {
4950     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
4951     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
4952     for (f = fStart; f < fEnd; ++f) {
4953       const PetscInt idx    = f - fStart;
4954       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
4955       polygon       *poly;
4956 
4957       in->facetlist[idx].numberofpolygons = 1;
4958       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
4959       in->facetlist[idx].numberofholes    = 0;
4960       in->facetlist[idx].holelist         = PETSC_NULL;
4961 
4962       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4963       for (p = 0; p < numPoints*2; p += 2) {
4964         const PetscInt point = points[p];
4965         if ((point >= vStart) && (point < vEnd)) {
4966           points[numVertices++] = point;
4967         }
4968       }
4969 
4970       poly = in->facetlist[idx].polygonlist;
4971       poly->numberofvertices = numVertices;
4972       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
4973       for (v = 0; v < numVertices; ++v) {
4974         const PetscInt vIdx = points[v] - vStart;
4975         poly->vertexlist[v] = vIdx;
4976       }
4977       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
4978       in->facetmarkerlist[idx] = (int) m;
4979       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4980     }
4981   }
4982   if (!rank) {
4983     TetGenOpts t;
4984 
4985     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4986     t.in        = boundary; /* Should go away */
4987     t.plc       = 1;
4988     t.quality   = 1;
4989     t.edgesout  = 1;
4990     t.zeroindex = 1;
4991     t.quiet     = 1;
4992     t.verbose   = verbose;
4993     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4994     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4995   }
4996   {
4997     const PetscInt numCorners  = 4;
4998     const PetscInt numCells    = out->numberoftetrahedra;
4999     const PetscInt numVertices = out->numberofpoints;
5000     const int     *cells       = out->tetrahedronlist;
5001     const double  *meshCoords  = out->pointlist;
5002 
5003     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5004     /* Set labels */
5005     for (v = 0; v < numVertices; ++v) {
5006       if (out->pointmarkerlist[v]) {
5007         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5008       }
5009     }
5010     if (interpolate) {
5011       PetscInt e;
5012 
5013       for (e = 0; e < out->numberofedges; e++) {
5014         if (out->edgemarkerlist[e]) {
5015           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5016           const PetscInt *edges;
5017           PetscInt        numEdges;
5018 
5019           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5020           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5021           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5022           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5023         }
5024       }
5025       for (f = 0; f < out->numberoftrifaces; f++) {
5026         if (out->trifacemarkerlist[f]) {
5027           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5028           const PetscInt *faces;
5029           PetscInt        numFaces;
5030 
5031           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5032           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5033           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5034           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5035         }
5036       }
5037     }
5038     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5039   }
5040 
5041   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5042   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5043   PetscFunctionReturn(0);
5044 }
5045 
5046 #undef __FUNCT__
5047 #define __FUNCT__ "DMPlexRefine_CTetgen"
5048 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5049 {
5050   MPI_Comm       comm = ((PetscObject) dm)->comm;
5051   const PetscInt dim  = 3;
5052   PLC           *in, *out;
5053   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5054   PetscMPIInt    rank;
5055   PetscErrorCode ierr;
5056 
5057   PetscFunctionBegin;
5058   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5059   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5060   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5061   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5062   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5063   ierr = PLCCreate(&in);CHKERRQ(ierr);
5064   ierr = PLCCreate(&out);CHKERRQ(ierr);
5065   in->numberofpoints = vEnd - vStart;
5066   if (in->numberofpoints > 0) {
5067     PetscSection coordSection;
5068     Vec          coordinates;
5069     PetscScalar *array;
5070 
5071     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5072     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5073     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5074     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5075     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5076     for (v = vStart; v < vEnd; ++v) {
5077       const PetscInt idx = v - vStart;
5078       PetscInt       off, d, m;
5079 
5080       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5081       for (d = 0; d < dim; ++d) {
5082         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5083       }
5084       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5085       in->pointmarkerlist[idx] = (int) m;
5086     }
5087     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5088   }
5089   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5090   in->numberofcorners       = 4;
5091   in->numberoftetrahedra    = cEnd - cStart;
5092   in->tetrahedronvolumelist = maxVolumes;
5093   if (in->numberoftetrahedra > 0) {
5094     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5095     for (c = cStart; c < cEnd; ++c) {
5096       const PetscInt idx     = c - cStart;
5097       PetscInt      *closure = PETSC_NULL;
5098       PetscInt       closureSize;
5099 
5100       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5101       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5102       for (v = 0; v < 4; ++v) {
5103         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5104       }
5105       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5106     }
5107   }
5108   if (!rank) {
5109     TetGenOpts t;
5110 
5111     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5112     t.in        = dm; /* Should go away */
5113     t.refine    = 1;
5114     t.varvolume = 1;
5115     t.quality   = 1;
5116     t.edgesout  = 1;
5117     t.zeroindex = 1;
5118     t.quiet     = 1;
5119     t.verbose   = verbose; /* Change this */
5120     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5121     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5122   }
5123   {
5124     const PetscInt numCorners  = 4;
5125     const PetscInt numCells    = out->numberoftetrahedra;
5126     const PetscInt numVertices = out->numberofpoints;
5127     const int     *cells       = out->tetrahedronlist;
5128     const double  *meshCoords  = out->pointlist;
5129     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5130 
5131     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5132     /* Set labels */
5133     for (v = 0; v < numVertices; ++v) {
5134       if (out->pointmarkerlist[v]) {
5135         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5136       }
5137     }
5138     if (interpolate) {
5139       PetscInt e, f;
5140 
5141       for (e = 0; e < out->numberofedges; e++) {
5142         if (out->edgemarkerlist[e]) {
5143           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5144           const PetscInt *edges;
5145           PetscInt        numEdges;
5146 
5147           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5148           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5149           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5150           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5151         }
5152       }
5153       for (f = 0; f < out->numberoftrifaces; f++) {
5154         if (out->trifacemarkerlist[f]) {
5155           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5156           const PetscInt *faces;
5157           PetscInt        numFaces;
5158 
5159           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5160           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5161           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5162           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5163         }
5164       }
5165     }
5166     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5167   }
5168   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5169   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5170   PetscFunctionReturn(0);
5171 }
5172 #endif
5173 
5174 #undef __FUNCT__
5175 #define __FUNCT__ "DMPlexGenerate"
5176 /*@C
5177   DMPlexGenerate - Generates a mesh.
5178 
5179   Not Collective
5180 
5181   Input Parameters:
5182 + boundary - The DMPlex boundary object
5183 . name - The mesh generation package name
5184 - interpolate - Flag to create intermediate mesh elements
5185 
5186   Output Parameter:
5187 . mesh - The DMPlex object
5188 
5189   Level: intermediate
5190 
5191 .keywords: mesh, elements
5192 .seealso: DMPlexCreate(), DMRefine()
5193 @*/
5194 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5195 {
5196   PetscInt       dim;
5197   char           genname[1024];
5198   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5199   PetscErrorCode ierr;
5200 
5201   PetscFunctionBegin;
5202   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5203   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5204   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5205   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5206   if (flg) {name = genname;}
5207   if (name) {
5208     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5209     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5210     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5211   }
5212   switch(dim) {
5213   case 1:
5214     if (!name || isTriangle) {
5215 #ifdef PETSC_HAVE_TRIANGLE
5216       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5217 #else
5218       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5219 #endif
5220     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5221     break;
5222   case 2:
5223     if (!name || isCTetgen) {
5224 #ifdef PETSC_HAVE_CTETGEN
5225       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5226 #else
5227       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5228 #endif
5229     } else if (isTetgen) {
5230 #ifdef PETSC_HAVE_TETGEN
5231       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5232 #else
5233       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5234 #endif
5235     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5236     break;
5237   default:
5238     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5239   }
5240   PetscFunctionReturn(0);
5241 }
5242 
5243 typedef PetscInt CellRefiner;
5244 
5245 #undef __FUNCT__
5246 #define __FUNCT__ "GetDepthStart_Private"
5247 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5248 {
5249   PetscFunctionBegin;
5250   if (cStart) *cStart = 0;
5251   if (vStart) *vStart = depthSize[depth];
5252   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5253   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5254   PetscFunctionReturn(0);
5255 }
5256 
5257 #undef __FUNCT__
5258 #define __FUNCT__ "GetDepthEnd_Private"
5259 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5260 {
5261   PetscFunctionBegin;
5262   if (cEnd) *cEnd = depthSize[depth];
5263   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5264   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5265   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5266   PetscFunctionReturn(0);
5267 }
5268 
5269 #undef __FUNCT__
5270 #define __FUNCT__ "CellRefinerGetSizes"
5271 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5272 {
5273   PetscInt       cStart, cEnd, vStart, vEnd, fStart, fEnd, eStart, eEnd;
5274   PetscErrorCode ierr;
5275 
5276   PetscFunctionBegin;
5277   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5278   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5279   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5280   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5281   switch(refiner) {
5282   case 1:
5283     /* Simplicial 2D */
5284     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5285     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5286     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5287     break;
5288   case 2:
5289     /* Hex 2D */
5290     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5291     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5292     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5293     break;
5294   default:
5295     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5296   }
5297   PetscFunctionReturn(0);
5298 }
5299 
5300 #undef __FUNCT__
5301 #define __FUNCT__ "CellRefinerSetConeSizes"
5302 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5303 {
5304   PetscInt       depth, cStart, cStartNew, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fStartNew, fEnd, f, eStart, eStartNew, eEnd, r;
5305   PetscErrorCode ierr;
5306 
5307   PetscFunctionBegin;
5308   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5309   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5310   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5311   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5312   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5313   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5314   switch(refiner) {
5315   case 1:
5316     /* Simplicial 2D */
5317     /* All cells have 3 faces */
5318     for(c = cStart; c < cEnd; ++c) {
5319       for(r = 0; r < 4; ++r) {
5320         const PetscInt newp = (c - cStart)*4 + r;
5321 
5322         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5323       }
5324     }
5325     /* Split faces have 2 vertices and the same cells as the parent */
5326     for(f = fStart; f < fEnd; ++f) {
5327       for(r = 0; r < 2; ++r) {
5328         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5329         PetscInt       size;
5330 
5331         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5332         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5333         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5334       }
5335     }
5336     /* Interior faces have 2 vertices and 2 cells */
5337     for(c = cStart; c < cEnd; ++c) {
5338       for(r = 0; r < 3; ++r) {
5339         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5340 
5341         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5342         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5343       }
5344     }
5345     /* Old vertices have identical supports */
5346     for(v = vStart; v < vEnd; ++v) {
5347       const PetscInt newp = vStartNew + (v - vStart);
5348       PetscInt       size;
5349 
5350       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5351       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5352     }
5353     /* Face vertices have 2 + cells*2 supports */
5354     for(f = fStart; f < fEnd; ++f) {
5355       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5356       PetscInt       size;
5357 
5358       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5359       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5360     }
5361     break;
5362   case 2:
5363     /* Hex 2D */
5364     /* All cells have 4 faces */
5365     for(c = cStart; c < cEnd; ++c) {
5366       for(r = 0; r < 4; ++r) {
5367         const PetscInt newp = (c - cStart)*4 + r;
5368 
5369         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5370       }
5371     }
5372     /* Split faces have 2 vertices and the same cells as the parent */
5373     for(f = fStart; f < fEnd; ++f) {
5374       for(r = 0; r < 2; ++r) {
5375         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5376         PetscInt       size;
5377 
5378         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5379         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5380         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5381       }
5382     }
5383     /* Interior faces have 2 vertices and 2 cells */
5384     for(c = cStart; c < cEnd; ++c) {
5385       for(r = 0; r < 4; ++r) {
5386         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5387 
5388         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5389         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5390       }
5391     }
5392     /* Old vertices have identical supports */
5393     for(v = vStart; v < vEnd; ++v) {
5394       const PetscInt newp = vStartNew + (v - vStart);
5395       PetscInt       size;
5396 
5397       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5398       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5399     }
5400     /* Face vertices have 2 + cells supports */
5401     for(f = fStart; f < fEnd; ++f) {
5402       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5403       PetscInt       size;
5404 
5405       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5406       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5407     }
5408     /* Cell vertices have 4 supports */
5409     for(c = cStart; c < cEnd; ++c) {
5410       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5411 
5412       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5413     }
5414     break;
5415   default:
5416     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5417   }
5418   PetscFunctionReturn(0);
5419 }
5420 
5421 #undef __FUNCT__
5422 #define __FUNCT__ "CellRefinerSetCones"
5423 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5424 {
5425   PetscInt       depth, cStart, cEnd, cStartNew, cEndNew, c, vStart, vEnd, vStartNew, vEndNew, v, fStart, fEnd, fStartNew, fEndNew, f, eStart, eEnd, eStartNew, eEndNew, r, p;
5426   PetscInt       maxSupportSize, *supportRef;
5427   PetscErrorCode ierr;
5428 
5429   PetscFunctionBegin;
5430   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5431   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5432   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5433   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5434   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5435   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5436   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5437   switch(refiner) {
5438   case 1:
5439     /* Simplicial 2D */
5440     /*
5441      2
5442      |\
5443      | \
5444      |  \
5445      |   \
5446      | C  \
5447      |     \
5448      |      \
5449      2---1---1
5450      |\  D  / \
5451      | 2   0   \
5452      |A \ /  B  \
5453      0---0-------1
5454      */
5455     /* All cells have 3 faces */
5456     for(c = cStart; c < cEnd; ++c) {
5457       const PetscInt  newp = (c - cStart)*4;
5458       const PetscInt *cone, *ornt;
5459       PetscInt        coneNew[3], orntNew[3];
5460 
5461       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5462       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5463       /* A triangle */
5464       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5465       orntNew[0] = ornt[0];
5466       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5467       orntNew[1] = -2;
5468       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5469       orntNew[2] = ornt[2];
5470       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5471       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5472 #if 1
5473       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);
5474       for(p = 0; p < 3; ++p) {
5475         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);
5476       }
5477 #endif
5478       /* B triangle */
5479       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5480       orntNew[0] = ornt[0];
5481       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5482       orntNew[1] = ornt[1];
5483       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5484       orntNew[2] = -2;
5485       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5486       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5487 #if 1
5488       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);
5489       for(p = 0; p < 3; ++p) {
5490         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);
5491       }
5492 #endif
5493       /* C triangle */
5494       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5495       orntNew[0] = -2;
5496       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5497       orntNew[1] = ornt[1];
5498       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5499       orntNew[2] = ornt[2];
5500       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5501       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5502 #if 1
5503       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);
5504       for(p = 0; p < 3; ++p) {
5505         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);
5506       }
5507 #endif
5508       /* D triangle */
5509       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5510       orntNew[0] = 0;
5511       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5512       orntNew[1] = 0;
5513       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5514       orntNew[2] = 0;
5515       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5516       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5517 #if 1
5518       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);
5519       for(p = 0; p < 3; ++p) {
5520         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);
5521       }
5522 #endif
5523     }
5524     /* Split faces have 2 vertices and the same cells as the parent */
5525     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5526     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5527     for(f = fStart; f < fEnd; ++f) {
5528       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5529 
5530       for(r = 0; r < 2; ++r) {
5531         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5532         const PetscInt *cone, *support;
5533         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5534 
5535         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5536         coneNew[0] = vStartNew + (cone[0] - vStart);
5537         coneNew[1] = vStartNew + (cone[1] - vStart);
5538         coneNew[(r+1)%2] = newv;
5539         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5540 #if 1
5541         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5542         for(p = 0; p < 2; ++p) {
5543           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);
5544         }
5545 #endif
5546         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5547         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5548         for(s = 0; s < supportSize; ++s) {
5549           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5550           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5551           for(c = 0; c < coneSize; ++c) {
5552             if (cone[c] == f) {
5553               break;
5554             }
5555           }
5556           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5557         }
5558         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5559 #if 1
5560         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5561         for(p = 0; p < supportSize; ++p) {
5562           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);
5563         }
5564 #endif
5565       }
5566     }
5567     /* Interior faces have 2 vertices and 2 cells */
5568     for(c = cStart; c < cEnd; ++c) {
5569       const PetscInt *cone;
5570 
5571       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5572       for(r = 0; r < 3; ++r) {
5573         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5574         PetscInt       coneNew[2];
5575         PetscInt       supportNew[2];
5576 
5577         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5578         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5579         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5580 #if 1
5581         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5582         for(p = 0; p < 2; ++p) {
5583           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);
5584         }
5585 #endif
5586         supportNew[0] = (c - cStart)*4 + r;
5587         supportNew[1] = (c - cStart)*4 + 3;
5588         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5589 #if 1
5590         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5591         for(p = 0; p < 2; ++p) {
5592           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);
5593         }
5594 #endif
5595       }
5596     }
5597     /* Old vertices have identical supports */
5598     for(v = vStart; v < vEnd; ++v) {
5599       const PetscInt  newp = vStartNew + (v - vStart);
5600       const PetscInt *support, *cone;
5601       PetscInt        size, s;
5602 
5603       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5604       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5605       for(s = 0; s < size; ++s) {
5606         PetscInt r = 0;
5607 
5608         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5609         if (cone[1] == v) r = 1;
5610         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5611       }
5612       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5613 #if 1
5614       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5615       for(p = 0; p < size; ++p) {
5616         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);
5617       }
5618 #endif
5619     }
5620     /* Face vertices have 2 + cells*2 supports */
5621     for(f = fStart; f < fEnd; ++f) {
5622       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5623       const PetscInt *cone, *support;
5624       PetscInt        size, s;
5625 
5626       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5627       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5628       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5629       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5630       for(s = 0; s < size; ++s) {
5631         PetscInt r = 0;
5632 
5633         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5634         if      (cone[1] == f) r = 1;
5635         else if (cone[2] == f) r = 2;
5636         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5637         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5638       }
5639       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5640 #if 1
5641       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5642       for(p = 0; p < 2+size*2; ++p) {
5643         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);
5644       }
5645 #endif
5646     }
5647     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5648     break;
5649   case 2:
5650     /* Hex 2D */
5651     /*
5652      3---------2---------2
5653      |         |         |
5654      |    D    2    C    |
5655      |         |         |
5656      3----3----0----1----1
5657      |         |         |
5658      |    A    0    B    |
5659      |         |         |
5660      0---------0---------1
5661      */
5662     /* All cells have 4 faces */
5663     for(c = cStart; c < cEnd; ++c) {
5664       const PetscInt  newp = (c - cStart)*4;
5665       const PetscInt *cone, *ornt;
5666       PetscInt        coneNew[4], orntNew[4];
5667 
5668       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5669       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5670       /* A quad */
5671       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5672       orntNew[0] = ornt[0];
5673       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5674       orntNew[1] = 0;
5675       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5676       orntNew[2] = -2;
5677       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5678       orntNew[3] = ornt[3];
5679       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5680       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5681 #if 1
5682       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);
5683       for(p = 0; p < 4; ++p) {
5684         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);
5685       }
5686 #endif
5687       /* B quad */
5688       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5689       orntNew[0] = ornt[0];
5690       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5691       orntNew[1] = ornt[1];
5692       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5693       orntNew[2] = 0;
5694       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5695       orntNew[3] = -2;
5696       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5697       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5698 #if 1
5699       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);
5700       for(p = 0; p < 4; ++p) {
5701         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);
5702       }
5703 #endif
5704       /* C quad */
5705       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5706       orntNew[0] = -2;
5707       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5708       orntNew[1] = ornt[1];
5709       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5710       orntNew[2] = ornt[2];
5711       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5712       orntNew[3] = 0;
5713       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5714       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5715 #if 1
5716       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);
5717       for(p = 0; p < 4; ++p) {
5718         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);
5719       }
5720 #endif
5721       /* D quad */
5722       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5723       orntNew[0] = 0;
5724       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5725       orntNew[1] = -2;
5726       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5727       orntNew[2] = ornt[2];
5728       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
5729       orntNew[3] = ornt[3];
5730       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5731       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5732 #if 1
5733       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);
5734       for(p = 0; p < 4; ++p) {
5735         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);
5736       }
5737 #endif
5738     }
5739     /* Split faces have 2 vertices and the same cells as the parent */
5740     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5741     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5742     for(f = fStart; f < fEnd; ++f) {
5743       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5744 
5745       for(r = 0; r < 2; ++r) {
5746         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5747         const PetscInt *cone, *support;
5748         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5749 
5750         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5751         coneNew[0] = vStartNew + (cone[0] - vStart);
5752         coneNew[1] = vStartNew + (cone[1] - vStart);
5753         coneNew[(r+1)%2] = newv;
5754         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5755 #if 1
5756         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5757         for(p = 0; p < 2; ++p) {
5758           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);
5759         }
5760 #endif
5761         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5762         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5763         for(s = 0; s < supportSize; ++s) {
5764           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5765           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5766           for(c = 0; c < coneSize; ++c) {
5767             if (cone[c] == f) {
5768               break;
5769             }
5770           }
5771           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
5772         }
5773         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5774 #if 1
5775         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5776         for(p = 0; p < supportSize; ++p) {
5777           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);
5778         }
5779 #endif
5780       }
5781     }
5782     /* Interior faces have 2 vertices and 2 cells */
5783     for(c = cStart; c < cEnd; ++c) {
5784       const PetscInt *cone;
5785       PetscInt        coneNew[2], supportNew[2];
5786 
5787       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5788       for(r = 0; r < 4; ++r) {
5789         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5790 
5791         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5792         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5793         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5794 #if 1
5795         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5796         for(p = 0; p < 2; ++p) {
5797           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);
5798         }
5799 #endif
5800         supportNew[0] = (c - cStart)*4 + r;
5801         supportNew[1] = (c - cStart)*4 + (r+1)%4;
5802         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5803 #if 1
5804         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5805         for(p = 0; p < 2; ++p) {
5806           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);
5807         }
5808 #endif
5809       }
5810     }
5811     /* Old vertices have identical supports */
5812     for(v = vStart; v < vEnd; ++v) {
5813       const PetscInt  newp = vStartNew + (v - vStart);
5814       const PetscInt *support, *cone;
5815       PetscInt        size, s;
5816 
5817       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5818       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5819       for(s = 0; s < size; ++s) {
5820         PetscInt r = 0;
5821 
5822         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5823         if (cone[1] == v) r = 1;
5824         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5825       }
5826       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5827 #if 1
5828       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5829       for(p = 0; p < size; ++p) {
5830         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);
5831       }
5832 #endif
5833     }
5834     /* Face vertices have 2 + cells supports */
5835     for(f = fStart; f < fEnd; ++f) {
5836       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5837       const PetscInt *cone, *support;
5838       PetscInt        size, s;
5839 
5840       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5841       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5842       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5843       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5844       for(s = 0; s < size; ++s) {
5845         PetscInt r = 0;
5846 
5847         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5848         if      (cone[1] == f) r = 1;
5849         else if (cone[2] == f) r = 2;
5850         else if (cone[3] == f) r = 3;
5851         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
5852       }
5853       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5854 #if 1
5855       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5856       for(p = 0; p < 2+size; ++p) {
5857         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);
5858       }
5859 #endif
5860     }
5861     /* Cell vertices have 4 supports */
5862     for(c = cStart; c < cEnd; ++c) {
5863       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5864       PetscInt       supportNew[4];
5865 
5866       for(r = 0; r < 4; ++r) {
5867         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5868       }
5869       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5870     }
5871     break;
5872   default:
5873     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5874   }
5875   PetscFunctionReturn(0);
5876 }
5877 
5878 #undef __FUNCT__
5879 #define __FUNCT__ "CellRefinerSetCoordinates"
5880 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5881 {
5882   PetscSection   coordSection, coordSectionNew;
5883   Vec            coordinates, coordinatesNew;
5884   PetscScalar   *coords, *coordsNew;
5885   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, f;
5886   PetscErrorCode ierr;
5887 
5888   PetscFunctionBegin;
5889   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5890   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5891   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5892   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5893   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5894   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
5895   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5896   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
5897   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5898   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5899   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
5900   switch(refiner) {
5901   case 1:
5902   case 2:
5903     /* Simplicial and Hex 2D */
5904     /* All vertices have the dim coordinates */
5905     for(v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5906       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5907       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5908     }
5909     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5910     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5911     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5912     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5913     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
5914     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5915     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5916     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5917     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5918     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5919     /* Old vertices have the same coordinates */
5920     for(v = vStart; v < vEnd; ++v) {
5921       const PetscInt newv = vStartNew + (v - vStart);
5922       PetscInt       off, offnew, d;
5923 
5924       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5925       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5926       for(d = 0; d < dim; ++d) {
5927         coordsNew[offnew+d] = coords[off+d];
5928       }
5929     }
5930     /* Face vertices have the average of endpoint coordinates */
5931     for(f = fStart; f < fEnd; ++f) {
5932       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5933       const PetscInt *cone;
5934       PetscInt        coneSize, offA, offB, offnew, d;
5935 
5936       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5937       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5938       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5939       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5940       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5941       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5942       for(d = 0; d < dim; ++d) {
5943         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5944       }
5945     }
5946     /* Just Hex 2D */
5947     if (refiner == 2) {
5948       /* Cell vertices have the average of corner coordinates */
5949       for(c = cStart; c < cEnd; ++c) {
5950         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5951         PetscInt      *cone = PETSC_NULL;
5952         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5953 
5954         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5955         for(p = 0; p < closureSize*2; p += 2) {
5956           const PetscInt point = cone[p];
5957           if ((point >= vStart) && (point < vEnd)) {
5958             cone[coneSize++] = point;
5959           }
5960         }
5961         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5962         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5963         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5964         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5965         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5966         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5967         for(d = 0; d < dim; ++d) {
5968           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5969         }
5970         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5971       }
5972     }
5973     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5974     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5975     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5976     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5977     break;
5978   default:
5979     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5980   }
5981   PetscFunctionReturn(0);
5982 }
5983 
5984 #undef __FUNCT__
5985 #define __FUNCT__ "DMPlexCreateProcessSF"
5986 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5987 {
5988   PetscInt           numRoots, numLeaves, l;
5989   const PetscInt    *localPoints;
5990   const PetscSFNode *remotePoints;
5991   PetscInt          *localPointsNew;
5992   PetscSFNode       *remotePointsNew;
5993   PetscInt          *ranks, *ranksNew;
5994   PetscErrorCode     ierr;
5995 
5996   PetscFunctionBegin;
5997   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5998   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5999   for(l = 0; l < numLeaves; ++l) {
6000     ranks[l] = remotePoints[l].rank;
6001   }
6002   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6003   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6004   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6005   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6006   for(l = 0; l < numLeaves; ++l) {
6007     ranksNew[l]              = ranks[l];
6008     localPointsNew[l]        = l;
6009     remotePointsNew[l].index = 0;
6010     remotePointsNew[l].rank  = ranksNew[l];
6011   }
6012   ierr = PetscFree(ranks);CHKERRQ(ierr);
6013   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6014   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6015   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6016   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6017   PetscFunctionReturn(0);
6018 }
6019 
6020 #undef __FUNCT__
6021 #define __FUNCT__ "CellRefinerCreateSF"
6022 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6023 {
6024   PetscSF            sf, sfNew, sfProcess;
6025   IS                 processRanks;
6026   MPI_Datatype       depthType;
6027   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6028   const PetscInt    *localPoints, *neighbors;
6029   const PetscSFNode *remotePoints;
6030   PetscInt          *localPointsNew;
6031   PetscSFNode       *remotePointsNew;
6032   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6033   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, vStart, vStartNew, vEnd, fStart, fStartNew, fEnd, eStart, eStartNew, eEnd, r, n;
6034   PetscErrorCode     ierr;
6035 
6036   PetscFunctionBegin;
6037   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6038   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6039   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6040   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6041   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6042   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6043   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6044   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6045   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6046   /* Caculate size of new SF */
6047   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6048   if (numRoots < 0) PetscFunctionReturn(0);
6049   for(l = 0; l < numLeaves; ++l) {
6050     const PetscInt p = localPoints[l];
6051 
6052     switch(refiner) {
6053     case 1:
6054       /* Simplicial 2D */
6055       if ((p >= vStart) && (p < vEnd)) {
6056         /* Old vertices stay the same */
6057         ++numLeavesNew;
6058       } else if ((p >= fStart) && (p < fEnd)) {
6059         /* Old faces add new faces and vertex */
6060         numLeavesNew += 1 + 2;
6061       } else if ((p >= cStart) && (p < cEnd)) {
6062         /* Old cells add new cells and interior faces */
6063         numLeavesNew += 4 + 3;
6064       }
6065       break;
6066     case 2:
6067       /* Hex 2D */
6068       if ((p >= vStart) && (p < vEnd)) {
6069         /* Old vertices stay the same */
6070         ++numLeavesNew;
6071       } else if ((p >= fStart) && (p < fEnd)) {
6072         /* Old faces add new faces and vertex */
6073         numLeavesNew += 1 + 2;
6074       } else if ((p >= cStart) && (p < cEnd)) {
6075         /* Old cells add new cells and interior faces */
6076         numLeavesNew += 4 + 4;
6077       }
6078       break;
6079     default:
6080       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6081     }
6082   }
6083   /* Communicate depthSizes for each remote rank */
6084   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6085   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6086   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6087   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);
6088   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6089   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6090   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6091   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6092   for(n = 0; n < numNeighbors; ++n) {
6093     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6094   }
6095   depthSizeOld[depth]   = cEnd - cStart;
6096   depthSizeOld[0]       = vEnd - vStart;
6097   depthSizeOld[depth-1] = fEnd - fStart;
6098   depthSizeOld[1]       = eEnd - eStart;
6099   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6100   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6101   for(n = 0; n < numNeighbors; ++n) {
6102     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6103   }
6104   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6105   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6106   /* Calculate new point SF */
6107   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6108   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6109   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6110   for(l = 0, m = 0; l < numLeaves; ++l) {
6111     PetscInt    p     = localPoints[l];
6112     PetscInt    rp    = remotePoints[l].index, n;
6113     PetscMPIInt rrank = remotePoints[l].rank;
6114 
6115     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6116     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6117     switch(refiner) {
6118     case 1:
6119       /* Simplicial 2D */
6120       if ((p >= vStart) && (p < vEnd)) {
6121         /* Old vertices stay the same */
6122         localPointsNew[m]        = vStartNew     + (p  - vStart);
6123         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6124         remotePointsNew[m].rank  = rrank;
6125         ++m;
6126       } else if ((p >= fStart) && (p < fEnd)) {
6127         /* Old faces add new faces and vertex */
6128         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6129         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6130         remotePointsNew[m].rank  = rrank;
6131         ++m;
6132         for(r = 0; r < 2; ++r, ++m) {
6133           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6134           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6135           remotePointsNew[m].rank  = rrank;
6136         }
6137       } else if ((p >= cStart) && (p < cEnd)) {
6138         /* Old cells add new cells and interior faces */
6139         for(r = 0; r < 4; ++r, ++m) {
6140           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6141           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6142           remotePointsNew[m].rank  = rrank;
6143         }
6144         for(r = 0; r < 3; ++r, ++m) {
6145           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6146           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6147           remotePointsNew[m].rank  = rrank;
6148         }
6149       }
6150       break;
6151     case 2:
6152       /* Hex 2D */
6153       if ((p >= vStart) && (p < vEnd)) {
6154         /* Old vertices stay the same */
6155         localPointsNew[m]        = vStartNew     + (p  - vStart);
6156         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6157         remotePointsNew[m].rank  = rrank;
6158         ++m;
6159       } else if ((p >= fStart) && (p < fEnd)) {
6160         /* Old faces add new faces and vertex */
6161         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6162         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6163         remotePointsNew[m].rank  = rrank;
6164         ++m;
6165         for(r = 0; r < 2; ++r, ++m) {
6166           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6167           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6168           remotePointsNew[m].rank  = rrank;
6169         }
6170       } else if ((p >= cStart) && (p < cEnd)) {
6171         /* Old cells add new cells and interior faces */
6172         for(r = 0; r < 4; ++r, ++m) {
6173           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6174           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6175           remotePointsNew[m].rank  = rrank;
6176         }
6177         for(r = 0; r < 4; ++r, ++m) {
6178           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6179           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6180           remotePointsNew[m].rank  = rrank;
6181         }
6182       }
6183       break;
6184     default:
6185       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6186     }
6187   }
6188   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6189   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6190   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6191   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6192   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6193   PetscFunctionReturn(0);
6194 }
6195 
6196 #undef __FUNCT__
6197 #define __FUNCT__ "CellRefinerCreateLabels"
6198 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6199 {
6200   PetscInt       numLabels, l;
6201   PetscInt       newp, cStart, cEnd, vStart, vStartNew, vEnd, fStart, fStartNew, fEnd, eStart, eEnd, r;
6202   PetscErrorCode ierr;
6203 
6204   PetscFunctionBegin;
6205   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6206   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6207   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6208   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6209   vStartNew = depthSize[2];
6210   fStartNew = depthSize[2] + depthSize[0];
6211   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6212   for(l = 0; l < numLabels; ++l) {
6213     DMLabel         label, labelNew;
6214     const char     *lname;
6215     PetscBool       isDepth;
6216     IS              valueIS;
6217     const PetscInt *values;
6218     PetscInt        numValues, val;
6219 
6220     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6221     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6222     if (isDepth) continue;
6223     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6224     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6225     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6226     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6227     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6228     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6229     for(val = 0; val < numValues; ++val) {
6230       IS              pointIS;
6231       const PetscInt *points;
6232       PetscInt        numPoints, n;
6233 
6234       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6235       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6236       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6237       for(n = 0; n < numPoints; ++n) {
6238         const PetscInt p = points[n];
6239         switch(refiner) {
6240         case 1:
6241           /* Simplicial 2D */
6242           if ((p >= vStart) && (p < vEnd)) {
6243             /* Old vertices stay the same */
6244             newp = vStartNew + (p - vStart);
6245             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6246           } else if ((p >= fStart) && (p < fEnd)) {
6247             /* Old faces add new faces and vertex */
6248             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6249             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6250             for(r = 0; r < 2; ++r) {
6251               newp = fStartNew + (p - fStart)*2 + r;
6252               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6253             }
6254           } else if ((p >= cStart) && (p < cEnd)) {
6255             /* Old cells add new cells and interior faces */
6256             for(r = 0; r < 4; ++r) {
6257               newp = (p - cStart)*4 + r;
6258               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6259             }
6260             for(r = 0; r < 3; ++r) {
6261               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6262               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6263             }
6264           }
6265           break;
6266         case 2:
6267           /* Hex 2D */
6268           if ((p >= vStart) && (p < vEnd)) {
6269             /* Old vertices stay the same */
6270             newp = vStartNew + (p - vStart);
6271             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6272           } else if ((p >= fStart) && (p < fEnd)) {
6273             /* Old faces add new faces and vertex */
6274             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6275             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6276             for(r = 0; r < 2; ++r) {
6277               newp = fStartNew + (p - fStart)*2 + r;
6278               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6279             }
6280           } else if ((p >= cStart) && (p < cEnd)) {
6281             /* Old cells add new cells and interior faces and vertex */
6282             for(r = 0; r < 4; ++r) {
6283               newp = (p - cStart)*4 + r;
6284               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6285             }
6286             for(r = 0; r < 4; ++r) {
6287               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6288               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6289             }
6290             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6291             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6292           }
6293           break;
6294         default:
6295           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6296         }
6297       }
6298       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6299       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6300     }
6301     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6302     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6303     if (0) {
6304       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6305       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6306       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6307     }
6308   }
6309   PetscFunctionReturn(0);
6310 }
6311 
6312 #undef __FUNCT__
6313 #define __FUNCT__ "DMPlexRefine_Uniform"
6314 /* This will only work for interpolated meshes */
6315 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6316 {
6317   DM              rdm;
6318   PetscInt       *depthSize;
6319   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
6320   PetscErrorCode  ierr;
6321 
6322   PetscFunctionBegin;
6323   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
6324   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6325   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6326   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6327   /* Calculate number of new points of each depth */
6328   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6329   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
6330   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6331   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6332   /* Step 1: Set chart */
6333   for(d = 0; d <= depth; ++d) {
6334     pEnd += depthSize[d];
6335   }
6336   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6337   /* Step 2: Set cone/support sizes */
6338   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6339   /* Step 3: Setup refined DM */
6340   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6341   /* Step 4: Set cones and supports */
6342   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6343   /* Step 5: Stratify */
6344   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6345   /* Step 6: Set coordinates for vertices */
6346   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6347   /* Step 7: Create pointSF */
6348   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6349   /* Step 8: Create labels */
6350   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6351   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6352 
6353   *dmRefined = rdm;
6354 #if 0
6355   DM_Plex *mesh = (DM_Plex *) dm->data;
6356   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
6357   //ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize()));
6358 
6359   PetscFunctionBegin;
6360   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6361   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
6362   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6363   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6364   ierr = DMPlexGetVTKBounds(dm, &cMax, &vMax);CHKERRQ(ierr);
6365 
6366   /* Count number of new cells which are normal and extra */
6367   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
6368   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
6369   for(c = cStart; c < cEnd2; ++c) {
6370     PetscInt n;
6371     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); // refiner.numNewCells
6372     newNumCellsNormal += n;
6373   }
6374   for(c = cEnd2; c < cEnd; ++c) {
6375     PetscInt n;
6376     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); // refiner.numNewCells
6377     newNumCellsExtra += n;
6378   }
6379   newNumCells = newNumCellsNormal + newNumCellsExtra;
6380   /* Count number of new vertices which are normal and extra */
6381   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
6382   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
6383   for(c = cStart; c < cEnd; ++c) {
6384     PetscInt *closure = PETSC_NULL;
6385     PetscInt  closureSize, numCorners = 0, p;
6386 
6387     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6388     for(p = 0; p < closureSize*2; p += 2) {
6389       const PetscInt point = closure[p];
6390       if ((point >= vStart) && (point < vEnd)) {
6391         closure[numCorners++] = point;
6392       }
6393     }
6394     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); // refiner.splitCell
6395     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6396   }
6397   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
6398   for(c = cEnd2; c < cEnd; ++c) {
6399     PetscInt *closure = PETSC_NULL;
6400     PetscInt  closureSize, numCorners = 0, p;
6401 
6402     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6403     for(p = 0; p < closureSize*2; p += 2) {
6404       const PetscInt point = closure[p];
6405       if ((point >= vStart) && (point < vEnd)) {
6406         closure[numCorners++] = point;
6407       }
6408     }
6409     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); // refiner.splitCellUncensored
6410     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6411   } // for
6412   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
6413   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
6414 
6415 #if 1
6416   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
6417   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
6418   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
6419   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
6420   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
6421   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
6422   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
6423   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
6424   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
6425   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
6426   ierr = PetscSynchronizedFlush(comm);
6427 #endif
6428 
6429   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
6430   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
6431   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
6432   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
6433   ierr = DMPlexGetVTKBounds(*dmRefined, newNumCellsNormal, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
6434   /* Set cone and support sizes for new normal cells */
6435   PetscInt newCell = 0;
6436   for(c = cStart; c < cEnd2; ++c) {
6437     PetscInt coneSize, n, i;
6438 
6439     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6440     ierr = CellRefinerGetNumSubcells(refiner, c, &n); // refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6441     for(i = 0; i < n; ++i, ++newCell) {
6442       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
6443     }
6444 
6445     PetscInt *closure = PETSC_NULL;
6446     PetscInt  closureSize, numCorners = 0, p;
6447 
6448     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6449     for(p = 0; p < closureSize*2; p += 2) {
6450       const PetscInt point = closure[p];
6451       if ((point >= vStart) && (point < vEnd)) {
6452         closure[numCorners++] = point;
6453       }
6454     }
6455     // ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); // refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6456     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6457   }
6458 
6459   // Reset current new cell value and loop over censored cells.
6460   curNewCell = _orderNewMesh->cellsCensored().min();
6461   oldCellsEnd = _orderOldMesh->cellsCensored().end();
6462   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
6463     // Set new cone and support sizes
6464     cV.clear();
6465     sieve->cone(*c_iter, cV);
6466     const point_type* cone = cV.getPoints();
6467     const int coneSize = cV.getSize();
6468 
6469     const point_type* newCells;
6470     int numNewCells = 0;
6471     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6472 
6473     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
6474       newSieve->setConeSize(curNewCell, coneSize);
6475       for(int iVertex=0; iVertex < coneSize; ++iVertex) {
6476 	newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
6477       } // for
6478     } // for
6479   } // for
6480   newSieve->allocate();
6481 
6482   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
6483 
6484   // Create refined cells in new sieve.
6485   curNewCell = _orderNewMesh->cellsNormal().min();
6486   oldCellsEnd = _orderOldMesh->cellsNormal().end();
6487   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
6488     cV.clear();
6489     sieve->cone(*c_iter, cV);
6490     const point_type *cone = cV.getPoints();
6491     const int coneSize = cV.getSize();
6492 
6493     const point_type* newCells;
6494     int numNewCells = 0;
6495     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6496 
6497     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
6498       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
6499     } // for
6500   } // for
6501   curNewCell = _orderNewMesh->cellsCensored().min();
6502   oldCellsEnd = _orderOldMesh->cellsCensored().end();
6503   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
6504     cV.clear();
6505     sieve->cone(*c_iter, cV);
6506     const point_type *cone = cV.getPoints();
6507     const int coneSize = cV.getSize();
6508 
6509     const point_type* newCells;
6510     int numNewCells = 0;
6511     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6512 
6513     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
6514       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
6515     } // for
6516   } // for
6517   newSieve->symmetrize();
6518 
6519   // Set coordinates in refined mesh.
6520   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
6521   assert(!coordinates.isNull());
6522   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
6523   assert(!newCoordinates.isNull());
6524 
6525   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
6526   assert(vertices->size() > 0);
6527   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
6528   assert(spaceDim > 0);
6529   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
6530 
6531   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
6532   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
6533     newCoordinates->setFiberDimension(*v_iter, spaceDim);
6534   } // for
6535   newCoordinates->allocatePoint();
6536 
6537   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
6538   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
6539     //std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl;
6540     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
6541   } // for
6542   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
6543   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
6544     //std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl;
6545     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
6546   } // for
6547 
6548   refiner.setCoordsNewVertices(newCoordinates, coordinates);
6549 
6550   // Create sensored depth
6551   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
6552   assert(!censoredLabel.isNull());
6553 
6554   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
6555 
6556   newSieve->roots(depthVisitor);
6557   while(depthVisitor.isModified()) {
6558     // FIX: Avoid the copy here somehow by fixing the traversal
6559     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
6560 
6561     depthVisitor.clear();
6562     newSieve->support(modifiedPoints, depthVisitor);
6563   } // while
6564   // Stratify refined mesh
6565   // Calculate new point SF
6566   _calcNewOverlap(newMesh, mesh, refiner);
6567   // Calculate new labels
6568   _createLabels(newMesh, mesh, refiner);
6569 #endif
6570   PetscFunctionReturn(0);
6571 }
6572 
6573 #undef __FUNCT__
6574 #define __FUNCT__ "DMPlexSetRefinementUniform"
6575 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6576 {
6577   DM_Plex *mesh = (DM_Plex *) dm->data;
6578 
6579   PetscFunctionBegin;
6580   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6581   mesh->refinementUniform = refinementUniform;
6582   PetscFunctionReturn(0);
6583 }
6584 
6585 #undef __FUNCT__
6586 #define __FUNCT__ "DMPlexGetRefinementUniform"
6587 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6588 {
6589   DM_Plex *mesh = (DM_Plex *) dm->data;
6590 
6591   PetscFunctionBegin;
6592   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6593   PetscValidPointer(refinementUniform,  2);
6594   *refinementUniform = mesh->refinementUniform;
6595   PetscFunctionReturn(0);
6596 }
6597 
6598 #undef __FUNCT__
6599 #define __FUNCT__ "DMPlexSetRefinementLimit"
6600 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6601 {
6602   DM_Plex *mesh = (DM_Plex *) dm->data;
6603 
6604   PetscFunctionBegin;
6605   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6606   mesh->refinementLimit = refinementLimit;
6607   PetscFunctionReturn(0);
6608 }
6609 
6610 #undef __FUNCT__
6611 #define __FUNCT__ "DMPlexGetRefinementLimit"
6612 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6613 {
6614   DM_Plex *mesh = (DM_Plex *) dm->data;
6615 
6616   PetscFunctionBegin;
6617   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6618   PetscValidPointer(refinementLimit,  2);
6619   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6620   *refinementLimit = mesh->refinementLimit;
6621   PetscFunctionReturn(0);
6622 }
6623 
6624 #undef __FUNCT__
6625 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
6626 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
6627 {
6628   PetscInt       dim, cStart, coneSize;
6629   PetscErrorCode ierr;
6630 
6631   PetscFunctionBegin;
6632   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6633   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
6634   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6635   switch(dim) {
6636   case 2:
6637     switch(coneSize) {
6638     case 3:
6639       *cellRefiner = 1;break;
6640     case 4:
6641       *cellRefiner = 2;break;
6642     default:
6643       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6644     }
6645     break;
6646   default:
6647     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6648   }
6649   PetscFunctionReturn(0);
6650 }
6651 
6652 #undef __FUNCT__
6653 #define __FUNCT__ "DMRefine_Plex"
6654 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
6655 {
6656   PetscReal      refinementLimit;
6657   PetscInt       dim, cStart, cEnd;
6658   char           genname[1024], *name = PETSC_NULL;
6659   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
6660   PetscErrorCode ierr;
6661 
6662   PetscFunctionBegin;
6663   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
6664   if (isUniform) {
6665     CellRefiner cellRefiner;
6666 
6667     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
6668     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
6669     PetscFunctionReturn(0);
6670   }
6671   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
6672   if (refinementLimit == 0.0) PetscFunctionReturn(0);
6673   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6674   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6675   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
6676   if (flg) {name = genname;}
6677   if (name) {
6678     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
6679     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
6680     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
6681   }
6682   switch(dim) {
6683   case 2:
6684     if (!name || isTriangle) {
6685 #ifdef PETSC_HAVE_TRIANGLE
6686       double  *maxVolumes;
6687       PetscInt c;
6688 
6689       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6690       for (c = 0; c < cEnd-cStart; ++c) {
6691         maxVolumes[c] = refinementLimit;
6692       }
6693       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6694 #else
6695       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
6696 #endif
6697     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
6698     break;
6699   case 3:
6700     if (!name || isCTetgen) {
6701 #ifdef PETSC_HAVE_CTETGEN
6702       PetscReal *maxVolumes;
6703       PetscInt   c;
6704 
6705       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
6706       for (c = 0; c < cEnd-cStart; ++c) {
6707         maxVolumes[c] = refinementLimit;
6708       }
6709       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6710 #else
6711       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
6712 #endif
6713     } else if (isTetgen) {
6714 #ifdef PETSC_HAVE_TETGEN
6715       double  *maxVolumes;
6716       PetscInt c;
6717 
6718       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6719       for (c = 0; c < cEnd-cStart; ++c) {
6720         maxVolumes[c] = refinementLimit;
6721       }
6722       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6723 #else
6724       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
6725 #endif
6726     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
6727     break;
6728   default:
6729     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
6730   }
6731   PetscFunctionReturn(0);
6732 }
6733 
6734 #undef __FUNCT__
6735 #define __FUNCT__ "DMPlexGetDepth"
6736 /*@
6737   DMPlexGetDepth - get the number of strata
6738 
6739   Not Collective
6740 
6741   Input Parameters:
6742 . dm           - The DMPlex object
6743 
6744   Output Parameters:
6745 . depth - number of strata
6746 
6747   Level: developer
6748 
6749   Notes:
6750   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
6751 
6752 .keywords: mesh, points
6753 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
6754 @*/
6755 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
6756 {
6757   PetscInt       d;
6758   PetscErrorCode ierr;
6759 
6760   PetscFunctionBegin;
6761   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6762   PetscValidPointer(depth, 2);
6763   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
6764   *depth = d-1;
6765   PetscFunctionReturn(0);
6766 }
6767 
6768 #undef __FUNCT__
6769 #define __FUNCT__ "DMPlexGetDepthStratum"
6770 /*@
6771   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
6772 
6773   Not Collective
6774 
6775   Input Parameters:
6776 + dm           - The DMPlex object
6777 - stratumValue - The requested depth
6778 
6779   Output Parameters:
6780 + start - The first point at this depth
6781 - end   - One beyond the last point at this depth
6782 
6783   Level: developer
6784 
6785 .keywords: mesh, points
6786 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
6787 @*/
6788 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) {
6789   DM_Plex    *mesh = (DM_Plex *) dm->data;
6790   DMLabel        next = mesh->labels;
6791   PetscBool      flg  = PETSC_FALSE;
6792   PetscInt       depth;
6793   PetscErrorCode ierr;
6794 
6795   PetscFunctionBegin;
6796   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6797   if (stratumValue < 0) {
6798     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6799     PetscFunctionReturn(0);
6800   } else {
6801     PetscInt pStart, pEnd;
6802 
6803     if (start) {*start = 0;}
6804     if (end)   {*end   = 0;}
6805     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6806     if (pStart == pEnd) {PetscFunctionReturn(0);}
6807   }
6808   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6809   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6810   /* We should have a generic GetLabel() and a Label class */
6811   while(next) {
6812     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6813     if (flg) break;
6814     next = next->next;
6815   }
6816   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6817   depth = stratumValue;
6818   if ((depth < 0) || (depth >= next->numStrata)) {
6819     if (start) {*start = 0;}
6820     if (end)   {*end   = 0;}
6821   } else {
6822     if (start) {*start = next->points[next->stratumOffsets[depth]];}
6823     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
6824   }
6825   PetscFunctionReturn(0);
6826 }
6827 
6828 #undef __FUNCT__
6829 #define __FUNCT__ "DMPlexGetHeightStratum"
6830 /*@
6831   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
6832 
6833   Not Collective
6834 
6835   Input Parameters:
6836 + dm           - The DMPlex object
6837 - stratumValue - The requested height
6838 
6839   Output Parameters:
6840 + start - The first point at this height
6841 - end   - One beyond the last point at this height
6842 
6843   Level: developer
6844 
6845 .keywords: mesh, points
6846 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
6847 @*/
6848 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) {
6849   DM_Plex    *mesh = (DM_Plex *) dm->data;
6850   DMLabel        next = mesh->labels;
6851   PetscBool      flg  = PETSC_FALSE;
6852   PetscInt       depth;
6853   PetscErrorCode ierr;
6854 
6855   PetscFunctionBegin;
6856   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6857   if (stratumValue < 0) {
6858     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6859   } else {
6860     PetscInt pStart, pEnd;
6861 
6862     if (start) {*start = 0;}
6863     if (end)   {*end   = 0;}
6864     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6865     if (pStart == pEnd) {PetscFunctionReturn(0);}
6866   }
6867   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6868   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6869   /* We should have a generic GetLabel() and a Label class */
6870   while(next) {
6871     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6872     if (flg) break;
6873     next = next->next;
6874   }
6875   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6876   depth = next->stratumValues[next->numStrata-1] - stratumValue;
6877   if ((depth < 0) || (depth >= next->numStrata)) {
6878     if (start) {*start = 0;}
6879     if (end)   {*end   = 0;}
6880   } else {
6881     if (start) {*start = next->points[next->stratumOffsets[depth]];}
6882     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
6883   }
6884   PetscFunctionReturn(0);
6885 }
6886 
6887 #undef __FUNCT__
6888 #define __FUNCT__ "DMPlexCreateSectionInitial"
6889 /* Set the number of dof on each point and separate by fields */
6890 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section) {
6891   PetscInt      *numDofTot;
6892   PetscInt       pStart = 0, pEnd = 0;
6893   PetscInt       p, d, f;
6894   PetscErrorCode ierr;
6895 
6896   PetscFunctionBegin;
6897   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
6898   for(d = 0; d <= dim; ++d) {
6899     numDofTot[d] = 0;
6900     for(f = 0; f < numFields; ++f) {
6901       numDofTot[d] += numDof[f*(dim+1)+d];
6902     }
6903   }
6904   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
6905   if (numFields > 0) {
6906     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
6907     if (numComp) {
6908       for(f = 0; f < numFields; ++f) {
6909         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
6910       }
6911     }
6912   }
6913   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6914   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
6915   for(d = 0; d <= dim; ++d) {
6916     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
6917     for(p = pStart; p < pEnd; ++p) {
6918       for(f = 0; f < numFields; ++f) {
6919         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
6920       }
6921       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
6922     }
6923   }
6924   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
6925   PetscFunctionReturn(0);
6926 }
6927 
6928 #undef __FUNCT__
6929 #define __FUNCT__ "DMPlexCreateSectionBCDof"
6930 /* Set the number of dof on each point and separate by fields
6931    If constDof is PETSC_DETERMINE, constrain every dof on the point
6932 */
6933 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section) {
6934   PetscInt       numFields;
6935   PetscInt       bc;
6936   PetscErrorCode ierr;
6937 
6938   PetscFunctionBegin;
6939   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6940   for (bc = 0; bc < numBC; ++bc) {
6941     PetscInt        field = 0;
6942     const PetscInt *idx;
6943     PetscInt        n, i;
6944 
6945     if (numFields) {field = bcField[bc];}
6946     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
6947     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6948     for (i = 0; i < n; ++i) {
6949       const PetscInt p = idx[i];
6950       PetscInt       numConst = constDof;
6951 
6952       /* Constrain every dof on the point */
6953       if (numConst < 0) {
6954         if (numFields) {
6955           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
6956         } else {
6957           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
6958         }
6959       }
6960       if (numFields) {
6961         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
6962       }
6963       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
6964     }
6965     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6966   }
6967   PetscFunctionReturn(0);
6968 }
6969 
6970 #undef __FUNCT__
6971 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
6972 /* Set the constrained indices on each point and separate by fields */
6973 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section) {
6974   PetscInt      *maxConstraints;
6975   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
6976   PetscErrorCode ierr;
6977 
6978   PetscFunctionBegin;
6979   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6980   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6981   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
6982   for(f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
6983   for(p = pStart; p < pEnd; ++p) {
6984     PetscInt cdof;
6985 
6986     if (numFields) {
6987       for(f = 0; f < numFields; ++f) {
6988         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
6989         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6990       }
6991     } else {
6992       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6993       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6994     }
6995   }
6996   for (f = 0; f < numFields; ++f) {
6997     maxConstraints[numFields] += maxConstraints[f];
6998   }
6999   if (maxConstraints[numFields]) {
7000     PetscInt *indices;
7001 
7002     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7003     for (p = pStart; p < pEnd; ++p) {
7004       PetscInt cdof, d;
7005 
7006       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7007       if (cdof) {
7008         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7009         if (numFields) {
7010           PetscInt numConst = 0, foff = 0;
7011 
7012           for (f = 0; f < numFields; ++f) {
7013             PetscInt cfdof, fdof;
7014 
7015             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7016             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7017             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7018             for(d = 0; d < cfdof; ++d) {
7019               indices[numConst+d] = d;
7020             }
7021             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7022             for(d = 0; d < cfdof; ++d) {
7023               indices[numConst+d] += foff;
7024             }
7025             numConst += cfdof;
7026             foff     += fdof;
7027           }
7028           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7029         } else {
7030           for (d = 0; d < cdof; ++d) {
7031             indices[d] = d;
7032           }
7033         }
7034         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7035       }
7036     }
7037     ierr = PetscFree(indices);CHKERRQ(ierr);
7038   }
7039   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7040   PetscFunctionReturn(0);
7041 }
7042 
7043 #undef __FUNCT__
7044 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7045 /* Set the constrained field indices on each point */
7046 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section) {
7047   const PetscInt *points, *indices;
7048   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7049   PetscErrorCode  ierr;
7050 
7051   PetscFunctionBegin;
7052   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7053   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7054 
7055   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7056   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7057   if (!constraintIndices) {
7058     PetscInt *idx, i;
7059 
7060     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7061     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7062     for(i = 0; i < maxDof; ++i) {idx[i] = i;}
7063     for(p = 0; p < numPoints; ++p) {
7064       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7065     }
7066     ierr = PetscFree(idx);CHKERRQ(ierr);
7067   } else {
7068     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7069     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7070     for(p = 0; p < numPoints; ++p) {
7071       PetscInt fcdof;
7072 
7073       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7074       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);
7075       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7076     }
7077     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7078   }
7079   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7080   PetscFunctionReturn(0);
7081 }
7082 
7083 #undef __FUNCT__
7084 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7085 /* Set the constrained indices on each point and separate by fields */
7086 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section) {
7087   PetscInt      *indices;
7088   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7089   PetscErrorCode ierr;
7090 
7091   PetscFunctionBegin;
7092   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7093   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7094   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7095   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7096   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7097   for (p = pStart; p < pEnd; ++p) {
7098     PetscInt cdof, d;
7099 
7100     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7101     if (cdof) {
7102       PetscInt numConst = 0, foff = 0;
7103 
7104       for (f = 0; f < numFields; ++f) {
7105         const PetscInt *fcind;
7106         PetscInt        fdof, fcdof;
7107 
7108         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7109         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7110         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7111         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7112         for(d = 0; d < fcdof; ++d) {
7113           indices[numConst+d] = fcind[d]+foff;
7114         }
7115         foff     += fdof;
7116         numConst += fcdof;
7117       }
7118       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7119       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7120     }
7121   }
7122   ierr = PetscFree(indices);CHKERRQ(ierr);
7123   PetscFunctionReturn(0);
7124 }
7125 
7126 #undef __FUNCT__
7127 #define __FUNCT__ "DMPlexCreateSection"
7128 /*@C
7129   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7130 
7131   Not Collective
7132 
7133   Input Parameters:
7134 + dm        - The DMPlex object
7135 . dim       - The spatial dimension of the problem
7136 . numFields - The number of fields in the problem
7137 . numComp   - An array of size numFields that holds the number of components for each field
7138 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7139 . numBC     - The number of boundary conditions
7140 . bcField   - An array of size numBC giving the field number for each boundry condition
7141 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7142 
7143   Output Parameter:
7144 . section - The PetscSection object
7145 
7146   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
7147   nubmer of dof for field 0 on each edge.
7148 
7149   Level: developer
7150 
7151 .keywords: mesh, elements
7152 .seealso: DMPlexCreate(), PetscSectionCreate()
7153 @*/
7154 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section) {
7155   PetscErrorCode ierr;
7156 
7157   PetscFunctionBegin;
7158   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7159   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7160   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7161   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7162   {
7163     PetscBool view = PETSC_FALSE;
7164 
7165     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7166     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7167   }
7168   PetscFunctionReturn(0);
7169 }
7170 
7171 #undef __FUNCT__
7172 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7173 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) {
7174   PetscSection   section;
7175   PetscErrorCode ierr;
7176 
7177   PetscFunctionBegin;
7178   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7179   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
7180   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7181   PetscFunctionReturn(0);
7182 }
7183 
7184 #undef __FUNCT__
7185 #define __FUNCT__ "DMPlexGetCoordinateSection"
7186 /*@
7187   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7188 
7189   Not Collective
7190 
7191   Input Parameter:
7192 . dm - The DMPlex object
7193 
7194   Output Parameter:
7195 . section - The PetscSection object
7196 
7197   Level: intermediate
7198 
7199 .keywords: mesh, coordinates
7200 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7201 @*/
7202 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section) {
7203   DM cdm;
7204   PetscErrorCode ierr;
7205 
7206   PetscFunctionBegin;
7207   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7208   PetscValidPointer(section, 2);
7209   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7210   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7211   PetscFunctionReturn(0);
7212 }
7213 
7214 #undef __FUNCT__
7215 #define __FUNCT__ "DMPlexSetCoordinateSection"
7216 /*@
7217   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7218 
7219   Not Collective
7220 
7221   Input Parameters:
7222 + dm      - The DMPlex object
7223 - section - The PetscSection object
7224 
7225   Level: intermediate
7226 
7227 .keywords: mesh, coordinates
7228 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7229 @*/
7230 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section) {
7231   DM             cdm;
7232   PetscErrorCode ierr;
7233 
7234   PetscFunctionBegin;
7235   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7236   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7237   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7238   PetscFunctionReturn(0);
7239 }
7240 
7241 #undef __FUNCT__
7242 #define __FUNCT__ "DMPlexGetConeSection"
7243 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) {
7244   DM_Plex *mesh = (DM_Plex *) dm->data;
7245 
7246   PetscFunctionBegin;
7247   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7248   if (section) *section = mesh->coneSection;
7249   PetscFunctionReturn(0);
7250 }
7251 
7252 #undef __FUNCT__
7253 #define __FUNCT__ "DMPlexGetCones"
7254 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) {
7255   DM_Plex *mesh = (DM_Plex *) dm->data;
7256 
7257   PetscFunctionBegin;
7258   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7259   if (cones) *cones = mesh->cones;
7260   PetscFunctionReturn(0);
7261 }
7262 
7263 #undef __FUNCT__
7264 #define __FUNCT__ "DMPlexGetConeOrientations"
7265 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) {
7266   DM_Plex *mesh = (DM_Plex *) dm->data;
7267 
7268   PetscFunctionBegin;
7269   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7270   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7271   PetscFunctionReturn(0);
7272 }
7273 
7274 #undef __FUNCT__
7275 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7276 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7277 {
7278   const PetscInt embedDim = 2;
7279   PetscReal      x = PetscRealPart(point[0]);
7280   PetscReal      y = PetscRealPart(point[1]);
7281   PetscReal      v0[2], J[4], invJ[4], detJ;
7282   PetscReal      xi, eta;
7283   PetscErrorCode ierr;
7284 
7285   PetscFunctionBegin;
7286   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7287   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7288   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7289 
7290   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
7291     *cell = c;
7292   } else {
7293     *cell = -1;
7294   }
7295   PetscFunctionReturn(0);
7296 }
7297 
7298 #undef __FUNCT__
7299 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7300 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7301 {
7302   PetscSection       coordSection;
7303   Vec                coordsLocal;
7304   const PetscScalar *coords;
7305   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7306   PetscReal          x         = PetscRealPart(point[0]);
7307   PetscReal          y         = PetscRealPart(point[1]);
7308   PetscInt           crossings = 0, f;
7309   PetscErrorCode     ierr;
7310 
7311   PetscFunctionBegin;
7312   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7313   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7314   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7315   for(f = 0; f < 4; ++f) {
7316     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7317     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7318     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7319     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7320     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7321     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7322     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7323     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7324     if ((cond1 || cond2)  && above) ++crossings;
7325   }
7326   if (crossings % 2) {
7327     *cell = c;
7328   } else {
7329     *cell = -1;
7330   }
7331   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7332   PetscFunctionReturn(0);
7333 }
7334 
7335 #undef __FUNCT__
7336 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7337 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7338 {
7339   const PetscInt embedDim = 3;
7340   PetscReal      v0[3], J[9], invJ[9], detJ;
7341   PetscReal      x = PetscRealPart(point[0]);
7342   PetscReal      y = PetscRealPart(point[1]);
7343   PetscReal      z = PetscRealPart(point[2]);
7344   PetscReal      xi, eta, zeta;
7345   PetscErrorCode ierr;
7346 
7347   PetscFunctionBegin;
7348   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7349   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7350   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7351   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7352 
7353   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
7354     *cell = c;
7355   } else {
7356     *cell = -1;
7357   }
7358   PetscFunctionReturn(0);
7359 }
7360 
7361 #undef __FUNCT__
7362 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7363 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7364 {
7365   PetscSection       coordSection;
7366   Vec                coordsLocal;
7367   const PetscScalar *coords;
7368   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7369                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7370   PetscBool          found     = PETSC_TRUE;
7371   PetscInt           f;
7372   PetscErrorCode     ierr;
7373 
7374   PetscFunctionBegin;
7375   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7376   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7377   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7378   for(f = 0; f < 6; ++f) {
7379     /* Check the point is under plane */
7380     /*   Get face normal */
7381     PetscReal v_i[3]    = {PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]),
7382                            PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]),
7383                            PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2])};
7384     PetscReal v_j[3]    = {PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]),
7385                            PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]),
7386                            PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2])};
7387     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]};
7388     PetscReal pp[3]     = {PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]),
7389                            PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]),
7390                            PetscRealPart(coords[faces[f*4+0]*3+2] - point[2])};
7391     PetscReal dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7392     /* Check that projected point is in face (2D location problem) */
7393     if (dot < 0.0) {
7394       found = PETSC_FALSE;
7395       break;
7396     }
7397   }
7398   if (found) {
7399     *cell = c;
7400   } else {
7401     *cell = -1;
7402   }
7403   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7404   PetscFunctionReturn(0);
7405 }
7406 
7407 #undef __FUNCT__
7408 #define __FUNCT__ "DMLocatePoints_Plex"
7409 /*
7410  Need to implement using the guess
7411 */
7412 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7413 {
7414   PetscInt       cell = -1/*, guess = -1*/;
7415   PetscInt       bs, numPoints, p;
7416   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7417   PetscInt      *cells;
7418   PetscScalar   *a;
7419   PetscErrorCode ierr;
7420 
7421   PetscFunctionBegin;
7422   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7423   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7424   ierr = DMPlexGetVTKBounds(dm, &cMax, PETSC_NULL);CHKERRQ(ierr);
7425   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
7426   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7427   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7428   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7429   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);
7430   numPoints /= bs;
7431   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7432   for(p = 0; p < numPoints; ++p) {
7433     const PetscScalar *point = &a[p*bs];
7434 
7435     switch(dim) {
7436     case 2:
7437       for(c = cStart; c < cEnd; ++c) {
7438         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7439         switch(coneSize) {
7440         case 3:
7441           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7442           break;
7443         case 4:
7444           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7445           break;
7446         default:
7447           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7448         }
7449         if (cell >= 0) break;
7450       }
7451       break;
7452     case 3:
7453       for(c = cStart; c < cEnd; ++c) {
7454         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7455         switch(coneSize) {
7456         case 4:
7457           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
7458           break;
7459         case 8:
7460           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
7461           break;
7462         default:
7463           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7464         }
7465         if (cell >= 0) break;
7466       }
7467       break;
7468     default:
7469       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
7470     }
7471     cells[p] = cell;
7472   }
7473   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
7474   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
7475   PetscFunctionReturn(0);
7476 }
7477 
7478 /******************************** FEM Support **********************************/
7479 
7480 #undef __FUNCT__
7481 #define __FUNCT__ "DMPlexVecGetClosure"
7482 /*@C
7483   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
7484 
7485   Not collective
7486 
7487   Input Parameters:
7488 + dm - The DM
7489 . section - The section describing the layout in v, or PETSC_NULL to use the default section
7490 . v - The local vector
7491 - point - The sieve point in the DM
7492 
7493   Output Parameters:
7494 + csize - The number of values in the closure, or PETSC_NULL
7495 - values - The array of values, which is a borrowed array and should not be freed
7496 
7497   Level: intermediate
7498 
7499 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7500 @*/
7501 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
7502   PetscScalar    *array, *vArray;
7503   PetscInt       *points = PETSC_NULL;
7504   PetscInt        offsets[32];
7505   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
7506   PetscErrorCode  ierr;
7507 
7508   PetscFunctionBegin;
7509   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7510   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7511   if (!section) {
7512     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7513   }
7514   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7515   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7516   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7517   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7518   /* Compress out points not in the section */
7519   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7520   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7521     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7522       points[q*2]   = points[p];
7523       points[q*2+1] = points[p+1];
7524       ++q;
7525     }
7526   }
7527   numPoints = q;
7528   for (p = 0, size = 0; p < numPoints*2; p += 2) {
7529     PetscInt dof, fdof;
7530 
7531     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7532     for (f = 0; f < numFields; ++f) {
7533       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7534       offsets[f+1] += fdof;
7535     }
7536     size += dof;
7537   }
7538   for (f = 1; f < numFields; ++f) {
7539     offsets[f+1] += offsets[f];
7540   }
7541   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
7542   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
7543   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
7544   for (p = 0; p < numPoints*2; p += 2) {
7545     PetscInt     o = points[p+1];
7546     PetscInt     dof, off, d;
7547     PetscScalar *varr;
7548 
7549     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7550     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
7551     varr = &vArray[off];
7552     if (numFields) {
7553       PetscInt fdof, foff, fcomp, f, c;
7554 
7555       for (f = 0, foff = 0; f < numFields; ++f) {
7556         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7557         if (o >= 0) {
7558           for (d = 0; d < fdof; ++d, ++offsets[f]) {
7559             array[offsets[f]] = varr[foff+d];
7560           }
7561         } else {
7562           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7563           for (d = fdof/fcomp-1; d >= 0; --d) {
7564             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
7565               array[offsets[f]] = varr[foff+d*fcomp+c];
7566             }
7567           }
7568         }
7569         foff += fdof;
7570       }
7571     } else {
7572       if (o >= 0) {
7573         for (d = 0; d < dof; ++d, ++offsets[0]) {
7574           array[offsets[0]] = varr[d];
7575         }
7576       } else {
7577         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
7578           array[offsets[0]] = varr[d];
7579         }
7580       }
7581     }
7582   }
7583   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7584   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
7585   if (csize) *csize = size;
7586   *values = array;
7587   PetscFunctionReturn(0);
7588 }
7589 
7590 #undef __FUNCT__
7591 #define __FUNCT__ "DMPlexVecRestoreClosure"
7592 /*@C
7593   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
7594 
7595   Not collective
7596 
7597   Input Parameters:
7598 + dm - The DM
7599 . section - The section describing the layout in v, or PETSC_NULL to use the default section
7600 . v - The local vector
7601 . point - The sieve point in the DM
7602 . csize - The number of values in the closure, or PETSC_NULL
7603 - values - The array of values, which is a borrowed array and should not be freed
7604 
7605   Level: intermediate
7606 
7607 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7608 @*/
7609 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
7610   PetscInt        size = 0;
7611   PetscErrorCode  ierr;
7612 
7613   PetscFunctionBegin;
7614   /* Should work without recalculating size */
7615   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
7616   PetscFunctionReturn(0);
7617 }
7618 
7619 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
7620 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
7621 
7622 #undef __FUNCT__
7623 #define __FUNCT__ "updatePoint_private"
7624 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
7625 {
7626   PetscInt        cdof;  /* The number of constraints on this point */
7627   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7628   PetscScalar    *a;
7629   PetscInt        off, cind = 0, k;
7630   PetscErrorCode  ierr;
7631 
7632   PetscFunctionBegin;
7633   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7634   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7635   a    = &array[off];
7636   if (!cdof || setBC) {
7637     if (orientation >= 0) {
7638       for (k = 0; k < dof; ++k) {
7639         fuse(&a[k], values[k]);
7640       }
7641     } else {
7642       for (k = 0; k < dof; ++k) {
7643         fuse(&a[k], values[dof-k-1]);
7644       }
7645     }
7646   } else {
7647     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7648     if (orientation >= 0) {
7649       for (k = 0; k < dof; ++k) {
7650         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7651         fuse(&a[k], values[k]);
7652       }
7653     } else {
7654       for (k = 0; k < dof; ++k) {
7655         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7656         fuse(&a[k], values[dof-k-1]);
7657       }
7658     }
7659   }
7660   PetscFunctionReturn(0);
7661 }
7662 
7663 #undef __FUNCT__
7664 #define __FUNCT__ "updatePointFields_private"
7665 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[]) {
7666   PetscScalar   *a;
7667   PetscInt       numFields, off, foff, f;
7668   PetscErrorCode ierr;
7669 
7670   PetscFunctionBegin;
7671   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7672   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7673   a    = &array[off];
7674   for (f = 0, foff = 0; f < numFields; ++f) {
7675     PetscInt        fdof, fcomp, fcdof;
7676     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7677     PetscInt        cind = 0, k, c;
7678 
7679     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7680     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7681     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
7682     if (!fcdof || setBC) {
7683       if (orientation >= 0) {
7684         for (k = 0; k < fdof; ++k) {
7685           fuse(&a[foff+k], values[foffs[f]+k]);
7686         }
7687       } else {
7688         for (k = fdof/fcomp-1; k >= 0; --k) {
7689           for (c = 0; c < fcomp; ++c) {
7690             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7691           }
7692         }
7693       }
7694     } else {
7695       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7696       if (orientation >= 0) {
7697         for (k = 0; k < fdof; ++k) {
7698           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
7699           fuse(&a[foff+k], values[foffs[f]+k]);
7700         }
7701       } else {
7702         for (k = fdof/fcomp-1; k >= 0; --k) {
7703           for (c = 0; c < fcomp; ++c) {
7704             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
7705             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7706           }
7707         }
7708       }
7709     }
7710     foff     += fdof;
7711     foffs[f] += fdof;
7712   }
7713   PetscFunctionReturn(0);
7714 }
7715 
7716 #undef __FUNCT__
7717 #define __FUNCT__ "DMPlexVecSetClosure"
7718 /*@C
7719   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
7720 
7721   Not collective
7722 
7723   Input Parameters:
7724 + dm - The DM
7725 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
7726 . v - The local vector
7727 . point - The sieve point in the DM
7728 . values - The array of values, which is a borrowed array and should not be freed
7729 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7730 
7731   Level: intermediate
7732 
7733 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
7734 @*/
7735 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) {
7736   PetscScalar    *array;
7737   PetscInt       *points = PETSC_NULL;
7738   PetscInt        offsets[32];
7739   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
7740   PetscErrorCode  ierr;
7741 
7742   PetscFunctionBegin;
7743   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7744   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7745   if (!section) {
7746     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7747   }
7748   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7749   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7750   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7751   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7752   /* Compress out points not in the section */
7753   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7754   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7755     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7756       points[q*2]   = points[p];
7757       points[q*2+1] = points[p+1];
7758       ++q;
7759     }
7760   }
7761   numPoints = q;
7762   for (p = 0; p < numPoints*2; p += 2) {
7763     PetscInt fdof;
7764 
7765     for (f = 0; f < numFields; ++f) {
7766       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7767       offsets[f+1] += fdof;
7768     }
7769   }
7770   for (f = 1; f < numFields; ++f) {
7771     offsets[f+1] += offsets[f];
7772   }
7773   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
7774   if (numFields) {
7775     switch(mode) {
7776     case INSERT_VALUES:
7777       for (p = 0; p < numPoints*2; p += 2) {
7778         PetscInt o = points[p+1];
7779         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
7780       } break;
7781     case INSERT_ALL_VALUES:
7782       for (p = 0; p < numPoints*2; p += 2) {
7783         PetscInt o = points[p+1];
7784         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
7785       } break;
7786     case ADD_VALUES:
7787       for (p = 0; p < numPoints*2; p += 2) {
7788         PetscInt o = points[p+1];
7789         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
7790       } break;
7791     case ADD_ALL_VALUES:
7792       for (p = 0; p < numPoints*2; p += 2) {
7793         PetscInt o = points[p+1];
7794         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
7795       } break;
7796     default:
7797       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7798     }
7799   } else {
7800     switch(mode) {
7801     case INSERT_VALUES:
7802       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7803         PetscInt o = points[p+1];
7804         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7805         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
7806       } break;
7807     case INSERT_ALL_VALUES:
7808       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7809         PetscInt o = points[p+1];
7810         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7811         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
7812       } break;
7813     case ADD_VALUES:
7814       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7815         PetscInt o = points[p+1];
7816         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7817         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
7818       } break;
7819     case ADD_ALL_VALUES:
7820       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7821         PetscInt o = points[p+1];
7822         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7823         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
7824       } break;
7825     default:
7826       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7827     }
7828   }
7829   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7830   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
7831   PetscFunctionReturn(0);
7832 }
7833 
7834 #undef __FUNCT__
7835 #define __FUNCT__ "DMPlexPrintMatSetValues"
7836 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
7837 {
7838   PetscMPIInt    rank;
7839   PetscInt       i, j;
7840   PetscErrorCode ierr;
7841 
7842   PetscFunctionBegin;
7843   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
7844   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
7845   for (i = 0; i < numIndices; i++) {
7846     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
7847   }
7848   for (i = 0; i < numIndices; i++) {
7849     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
7850     for (j = 0; j < numIndices; j++) {
7851 #ifdef PETSC_USE_COMPLEX
7852       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
7853 #else
7854       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
7855 #endif
7856     }
7857     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
7858   }
7859   PetscFunctionReturn(0);
7860 }
7861 
7862 #undef __FUNCT__
7863 #define __FUNCT__ "indicesPoint_private"
7864 /* . off - The global offset of this point */
7865 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
7866   PetscInt        cdof;  /* The number of constraints on this point */
7867   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7868   PetscInt        cind = 0, k;
7869   PetscErrorCode  ierr;
7870 
7871   PetscFunctionBegin;
7872   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
7873   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7874   if (!cdof || setBC) {
7875     if (orientation >= 0) {
7876       for (k = 0; k < dof; ++k) {
7877         indices[k] = off+k;
7878       }
7879     } else {
7880       for (k = 0; k < dof; ++k) {
7881         indices[dof-k-1] = off+k;
7882       }
7883     }
7884   } else {
7885     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7886     if (orientation >= 0) {
7887       for (k = 0; k < dof; ++k) {
7888         if ((cind < cdof) && (k == cdofs[cind])) {
7889           /* Insert check for returning constrained indices */
7890           indices[k] = -(off+k+1);
7891           ++cind;
7892         } else {
7893           indices[k] = off+k-cind;
7894         }
7895       }
7896     } else {
7897       for (k = 0; k < dof; ++k) {
7898         if ((cind < cdof) && (k == cdofs[cind])) {
7899           /* Insert check for returning constrained indices */
7900           indices[dof-k-1] = -(off+k+1);
7901           ++cind;
7902         } else {
7903           indices[dof-k-1] = off+k-cind;
7904         }
7905       }
7906     }
7907   }
7908   PetscFunctionReturn(0);
7909 }
7910 
7911 #undef __FUNCT__
7912 #define __FUNCT__ "indicesPointFields_private"
7913 /* . off - The global offset of this point */
7914 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
7915   PetscInt       numFields, foff, f;
7916   PetscErrorCode ierr;
7917 
7918   PetscFunctionBegin;
7919   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7920   for (f = 0, foff = 0; f < numFields; ++f) {
7921     PetscInt        fdof, fcomp, cfdof;
7922     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7923     PetscInt        cind = 0, k, c;
7924 
7925     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7926     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7927     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
7928     if (!cfdof || setBC) {
7929       if (orientation >= 0) {
7930         for (k = 0; k < fdof; ++k) {
7931           indices[foffs[f]+k] = off+foff+k;
7932         }
7933       } else {
7934         for (k = fdof/fcomp-1; k >= 0; --k) {
7935           for (c = 0; c < fcomp; ++c) {
7936             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
7937           }
7938         }
7939       }
7940     } else {
7941       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7942       if (orientation >= 0) {
7943         for (k = 0; k < fdof; ++k) {
7944           if ((cind < cfdof) && (k == fcdofs[cind])) {
7945             indices[foffs[f]+k] = -(off+foff+k+1);
7946             ++cind;
7947           } else {
7948             indices[foffs[f]+k] = off+foff+k-cind;
7949           }
7950         }
7951       } else {
7952         for (k = fdof/fcomp-1; k >= 0; --k) {
7953           for (c = 0; c < fcomp; ++c) {
7954             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
7955               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
7956               ++cind;
7957             } else {
7958               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
7959             }
7960           }
7961         }
7962       }
7963     }
7964     foff     += fdof - cfdof;
7965     foffs[f] += fdof;
7966   }
7967   PetscFunctionReturn(0);
7968 }
7969 
7970 #undef __FUNCT__
7971 #define __FUNCT__ "DMPlexMatSetClosure"
7972 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
7973 {
7974   DM_Plex     *mesh   = (DM_Plex *) dm->data;
7975   PetscInt       *points = PETSC_NULL;
7976   PetscInt       *indices;
7977   PetscInt        offsets[32];
7978   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
7979   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
7980   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
7981   PetscErrorCode  ierr;
7982 
7983   PetscFunctionBegin;
7984   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7985   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
7986   if (useDefault) {
7987     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7988   }
7989   if (useGlobalDefault) {
7990     if (useDefault) {
7991       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
7992     } else {
7993       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7994     }
7995   }
7996   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7997   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7998   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7999   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8000   /* Compress out points not in the section */
8001   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8002   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8003     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8004       points[q*2]   = points[p];
8005       points[q*2+1] = points[p+1];
8006       ++q;
8007     }
8008   }
8009   numPoints = q;
8010   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8011     PetscInt fdof;
8012 
8013     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8014     for (f = 0; f < numFields; ++f) {
8015       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8016       offsets[f+1] += fdof;
8017     }
8018     numIndices += dof;
8019   }
8020   for (f = 1; f < numFields; ++f) {
8021     offsets[f+1] += offsets[f];
8022   }
8023   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8024   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8025   if (numFields) {
8026     for (p = 0; p < numPoints*2; p += 2) {
8027       PetscInt o = points[p+1];
8028       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8029       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8030     }
8031   } else {
8032     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8033       PetscInt o = points[p+1];
8034       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8035       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8036     }
8037   }
8038   if (useGlobalDefault && !useDefault) {
8039     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8040   }
8041   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8042   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8043   if (ierr) {
8044     PetscMPIInt    rank;
8045     PetscErrorCode ierr2;
8046 
8047     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8048     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8049     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8050     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8051     CHKERRQ(ierr);
8052   }
8053   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8054   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8055   PetscFunctionReturn(0);
8056 }
8057 
8058 #undef __FUNCT__
8059 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8060 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8061 {
8062   PetscSection       coordSection;
8063   Vec                coordinates;
8064   const PetscScalar *coords;
8065   const PetscInt     dim = 2;
8066   PetscInt           d, f;
8067   PetscErrorCode     ierr;
8068 
8069   PetscFunctionBegin;
8070   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8071   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8072   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8073   if (v0) {
8074     for (d = 0; d < dim; d++) {
8075       v0[d] = PetscRealPart(coords[d]);
8076     }
8077   }
8078   if (J) {
8079     for (d = 0; d < dim; d++) {
8080       for (f = 0; f < dim; f++) {
8081         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8082       }
8083     }
8084     *detJ = J[0]*J[3] - J[1]*J[2];
8085 #if 0
8086     if (detJ < 0.0) {
8087       const PetscReal xLength = mesh->periodicity[0];
8088 
8089       if (xLength != 0.0) {
8090         PetscReal v0x = coords[0*dim+0];
8091 
8092         if (v0x == 0.0) {
8093           v0x = v0[0] = xLength;
8094         }
8095         for (f = 0; f < dim; f++) {
8096           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8097 
8098           J[0*dim+f] = 0.5*(px - v0x);
8099         }
8100       }
8101       detJ = J[0]*J[3] - J[1]*J[2];
8102     }
8103 #endif
8104     PetscLogFlops(8.0 + 3.0);
8105   }
8106   if (invJ) {
8107     const PetscReal invDet = 1.0/(*detJ);
8108 
8109     invJ[0] =  invDet*J[3];
8110     invJ[1] = -invDet*J[1];
8111     invJ[2] = -invDet*J[2];
8112     invJ[3] =  invDet*J[0];
8113     PetscLogFlops(5.0);
8114   }
8115   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8116   PetscFunctionReturn(0);
8117 }
8118 
8119 #undef __FUNCT__
8120 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8121 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8122 {
8123   PetscSection       coordSection;
8124   Vec                coordinates;
8125   const PetscScalar *coords;
8126   const PetscInt     dim = 2;
8127   PetscInt           d, f;
8128   PetscErrorCode     ierr;
8129 
8130   PetscFunctionBegin;
8131   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8132   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8133   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8134   if (v0) {
8135     for (d = 0; d < dim; d++) {
8136       v0[d] = PetscRealPart(coords[d]);
8137     }
8138   }
8139   if (J) {
8140     for (d = 0; d < dim; d++) {
8141       for (f = 0; f < dim; f++) {
8142         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8143       }
8144     }
8145     *detJ = J[0]*J[3] - J[1]*J[2];
8146     PetscLogFlops(8.0 + 3.0);
8147   }
8148   if (invJ) {
8149     const PetscReal invDet = 1.0/(*detJ);
8150 
8151     invJ[0] =  invDet*J[3];
8152     invJ[1] = -invDet*J[1];
8153     invJ[2] = -invDet*J[2];
8154     invJ[3] =  invDet*J[0];
8155     PetscLogFlops(5.0);
8156   }
8157   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8158   PetscFunctionReturn(0);
8159 }
8160 
8161 #undef __FUNCT__
8162 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8163 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8164 {
8165   PetscSection       coordSection;
8166   Vec                coordinates;
8167   const PetscScalar *coords;
8168   const PetscInt     dim = 3;
8169   PetscInt           d, f;
8170   PetscErrorCode     ierr;
8171 
8172   PetscFunctionBegin;
8173   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8174   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8175   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8176   if (v0) {
8177     for (d = 0; d < dim; d++) {
8178       v0[d] = PetscRealPart(coords[d]);
8179     }
8180   }
8181   if (J) {
8182     for (d = 0; d < dim; d++) {
8183       for (f = 0; f < dim; f++) {
8184         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8185       }
8186     }
8187     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8188     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8189              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8190              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8191     PetscLogFlops(18.0 + 12.0);
8192   }
8193   if (invJ) {
8194     const PetscReal invDet = -1.0/(*detJ);
8195 
8196     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8197     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8198     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8199     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8200     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8201     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8202     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8203     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8204     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8205     PetscLogFlops(37.0);
8206   }
8207   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8208   PetscFunctionReturn(0);
8209 }
8210 
8211 #undef __FUNCT__
8212 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8213 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8214 {
8215   PetscSection       coordSection;
8216   Vec                coordinates;
8217   const PetscScalar *coords;
8218   const PetscInt     dim = 3;
8219   PetscInt           d;
8220   PetscErrorCode     ierr;
8221 
8222   PetscFunctionBegin;
8223   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8224   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8225   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8226   if (v0) {
8227     for (d = 0; d < dim; d++) {
8228       v0[d] = PetscRealPart(coords[d]);
8229     }
8230   }
8231   if (J) {
8232     for (d = 0; d < dim; d++) {
8233       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8234       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8235       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8236     }
8237     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8238              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8239              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8240     PetscLogFlops(18.0 + 12.0);
8241   }
8242   if (invJ) {
8243     const PetscReal invDet = -1.0/(*detJ);
8244 
8245     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8246     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8247     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8248     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8249     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8250     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8251     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8252     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8253     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8254     PetscLogFlops(37.0);
8255   }
8256   *detJ *= 8.0;
8257   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8258   PetscFunctionReturn(0);
8259 }
8260 
8261 #undef __FUNCT__
8262 #define __FUNCT__ "DMPlexComputeCellGeometry"
8263 /*@C
8264   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8265 
8266   Collective on DM
8267 
8268   Input Arguments:
8269 + dm   - the DM
8270 - cell - the cell
8271 
8272   Output Arguments:
8273 + v0   - the translation part of this affine transform
8274 . J    - the Jacobian of the transform to the reference element
8275 . invJ - the inverse of the Jacobian
8276 - detJ - the Jacobian determinant
8277 
8278   Level: advanced
8279 
8280 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8281 @*/
8282 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ) {
8283   PetscInt       dim, maxConeSize;
8284   PetscErrorCode ierr;
8285 
8286   PetscFunctionBegin;
8287   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8288   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
8289   switch(dim) {
8290   case 2:
8291     switch(maxConeSize) {
8292     case 3:
8293       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8294       break;
8295     case 4:
8296       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8297       break;
8298     default:
8299       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of cell vertices %D for element geometry computation", maxConeSize);
8300     }
8301     break;
8302   case 3:
8303     switch(maxConeSize) {
8304     case 4:
8305       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8306       break;
8307     case 8:
8308       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8309       break;
8310     default:
8311       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of cell vertices %D for element geometry computation", maxConeSize);
8312     }
8313     break;
8314   default:
8315     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8316   }
8317   PetscFunctionReturn(0);
8318 }
8319 
8320 #undef __FUNCT__
8321 #define __FUNCT__ "DMPlexGetFaceOrientation"
8322 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented) {
8323   MPI_Comm       comm      = ((PetscObject) dm)->comm;
8324   PetscBool      posOrient = PETSC_FALSE;
8325   const PetscInt debug     = 0;
8326   PetscInt       cellDim, faceSize, f;
8327   PetscErrorCode ierr;
8328 
8329   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
8330   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
8331 
8332   if (cellDim == numCorners-1) {
8333     /* Simplices */
8334     faceSize  = numCorners-1;
8335     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
8336   } else if (cellDim == 1 && numCorners == 3) {
8337     /* Quadratic line */
8338     faceSize  = 1;
8339     posOrient = PETSC_TRUE;
8340   } else if (cellDim == 2 && numCorners == 4) {
8341     /* Quads */
8342     faceSize  = 2;
8343     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
8344       posOrient = PETSC_TRUE;
8345     } else if ((indices[0] == 3) && (indices[1] == 0)) {
8346       posOrient = PETSC_TRUE;
8347     } else {
8348       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
8349         posOrient = PETSC_FALSE;
8350       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
8351     }
8352   } else if (cellDim == 2 && numCorners == 6) {
8353     /* Quadratic triangle (I hate this) */
8354     /* Edges are determined by the first 2 vertices (corners of edges) */
8355     const PetscInt faceSizeTri = 3;
8356     PetscInt  sortedIndices[3], i, iFace;
8357     PetscBool found = PETSC_FALSE;
8358     PetscInt  faceVerticesTriSorted[9] = {
8359       0, 3,  4, /* bottom */
8360       1, 4,  5, /* right */
8361       2, 3,  5, /* left */
8362     };
8363     PetscInt  faceVerticesTri[9] = {
8364       0, 3,  4, /* bottom */
8365       1, 4,  5, /* right */
8366       2, 5,  3, /* left */
8367     };
8368 
8369     faceSize = faceSizeTri;
8370     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
8371     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
8372     for (iFace = 0; iFace < 3; ++iFace) {
8373       const PetscInt ii = iFace*faceSizeTri;
8374       PetscInt       fVertex, cVertex;
8375 
8376       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
8377           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
8378         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
8379           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
8380             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
8381               faceVertices[fVertex] = origVertices[cVertex];
8382               break;
8383             }
8384           }
8385         }
8386         found = PETSC_TRUE;
8387         break;
8388       }
8389     }
8390     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
8391     if (posOriented) {*posOriented = PETSC_TRUE;}
8392     PetscFunctionReturn(0);
8393   } else if (cellDim == 2 && numCorners == 9) {
8394     /* Quadratic quad (I hate this) */
8395     /* Edges are determined by the first 2 vertices (corners of edges) */
8396     const PetscInt faceSizeQuad = 3;
8397     PetscInt  sortedIndices[3], i, iFace;
8398     PetscBool found = PETSC_FALSE;
8399     PetscInt  faceVerticesQuadSorted[12] = {
8400       0, 1,  4, /* bottom */
8401       1, 2,  5, /* right */
8402       2, 3,  6, /* top */
8403       0, 3,  7, /* left */
8404     };
8405     PetscInt  faceVerticesQuad[12] = {
8406       0, 1,  4, /* bottom */
8407       1, 2,  5, /* right */
8408       2, 3,  6, /* top */
8409       3, 0,  7, /* left */
8410     };
8411 
8412     faceSize = faceSizeQuad;
8413     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
8414     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
8415     for (iFace = 0; iFace < 4; ++iFace) {
8416       const PetscInt ii = iFace*faceSizeQuad;
8417       PetscInt       fVertex, cVertex;
8418 
8419       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
8420           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
8421         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
8422           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
8423             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
8424               faceVertices[fVertex] = origVertices[cVertex];
8425               break;
8426             }
8427           }
8428         }
8429         found = PETSC_TRUE;
8430         break;
8431       }
8432     }
8433     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
8434     if (posOriented) {*posOriented = PETSC_TRUE;}
8435     PetscFunctionReturn(0);
8436   } else if (cellDim == 3 && numCorners == 8) {
8437     /* Hexes
8438        A hex is two oriented quads with the normal of the first
8439        pointing up at the second.
8440 
8441           7---6
8442          /|  /|
8443         4---5 |
8444         | 3-|-2
8445         |/  |/
8446         0---1
8447 
8448         Faces are determined by the first 4 vertices (corners of faces) */
8449     const PetscInt faceSizeHex = 4;
8450     PetscInt  sortedIndices[4], i, iFace;
8451     PetscBool found = PETSC_FALSE;
8452     PetscInt faceVerticesHexSorted[24] = {
8453       0, 1, 2, 3,  /* bottom */
8454       4, 5, 6, 7,  /* top */
8455       0, 1, 4, 5,  /* front */
8456       1, 2, 5, 6,  /* right */
8457       2, 3, 6, 7,  /* back */
8458       0, 3, 4, 7,  /* left */
8459     };
8460     PetscInt faceVerticesHex[24] = {
8461       3, 2, 1, 0,  /* bottom */
8462       4, 5, 6, 7,  /* top */
8463       0, 1, 5, 4,  /* front */
8464       1, 2, 6, 5,  /* right */
8465       2, 3, 7, 6,  /* back */
8466       3, 0, 4, 7,  /* left */
8467     };
8468 
8469     faceSize = faceSizeHex;
8470     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
8471     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
8472     for (iFace = 0; iFace < 6; ++iFace) {
8473       const PetscInt ii = iFace*faceSizeHex;
8474       PetscInt       fVertex, cVertex;
8475 
8476       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
8477           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
8478           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
8479           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
8480         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
8481           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
8482             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
8483               faceVertices[fVertex] = origVertices[cVertex];
8484               break;
8485             }
8486           }
8487         }
8488         found = PETSC_TRUE;
8489         break;
8490       }
8491     }
8492     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
8493     if (posOriented) {*posOriented = PETSC_TRUE;}
8494     PetscFunctionReturn(0);
8495   } else if (cellDim == 3 && numCorners == 10) {
8496     /* Quadratic tet */
8497     /* Faces are determined by the first 3 vertices (corners of faces) */
8498     const PetscInt faceSizeTet = 6;
8499     PetscInt  sortedIndices[6], i, iFace;
8500     PetscBool found = PETSC_FALSE;
8501     PetscInt faceVerticesTetSorted[24] = {
8502       0, 1, 2,  6, 7, 8, /* bottom */
8503       0, 3, 4,  6, 7, 9,  /* front */
8504       1, 4, 5,  7, 8, 9,  /* right */
8505       2, 3, 5,  6, 8, 9,  /* left */
8506     };
8507     PetscInt faceVerticesTet[24] = {
8508       0, 1, 2,  6, 7, 8, /* bottom */
8509       0, 4, 3,  6, 7, 9,  /* front */
8510       1, 5, 4,  7, 8, 9,  /* right */
8511       2, 3, 5,  8, 6, 9,  /* left */
8512     };
8513 
8514     faceSize = faceSizeTet;
8515     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
8516     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
8517     for (iFace=0; iFace < 4; ++iFace) {
8518       const PetscInt ii = iFace*faceSizeTet;
8519       PetscInt       fVertex, cVertex;
8520 
8521       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
8522           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
8523           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
8524           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
8525         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
8526           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
8527             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
8528               faceVertices[fVertex] = origVertices[cVertex];
8529               break;
8530             }
8531           }
8532         }
8533         found = PETSC_TRUE;
8534         break;
8535       }
8536     }
8537     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
8538     if (posOriented) {*posOriented = PETSC_TRUE;}
8539     PetscFunctionReturn(0);
8540   } else if (cellDim == 3 && numCorners == 27) {
8541     /* Quadratic hexes (I hate this)
8542        A hex is two oriented quads with the normal of the first
8543        pointing up at the second.
8544 
8545          7---6
8546         /|  /|
8547        4---5 |
8548        | 3-|-2
8549        |/  |/
8550        0---1
8551 
8552        Faces are determined by the first 4 vertices (corners of faces) */
8553     const PetscInt faceSizeQuadHex = 9;
8554     PetscInt  sortedIndices[9], i, iFace;
8555     PetscBool found = PETSC_FALSE;
8556     PetscInt faceVerticesQuadHexSorted[54] = {
8557       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
8558       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
8559       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
8560       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
8561       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
8562       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
8563     };
8564     PetscInt faceVerticesQuadHex[54] = {
8565       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
8566       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
8567       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
8568       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
8569       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
8570       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
8571     };
8572 
8573     faceSize = faceSizeQuadHex;
8574     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
8575     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
8576     for (iFace = 0; iFace < 6; ++iFace) {
8577       const PetscInt ii = iFace*faceSizeQuadHex;
8578       PetscInt       fVertex, cVertex;
8579 
8580       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
8581           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
8582           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
8583           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
8584         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
8585           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
8586             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
8587               faceVertices[fVertex] = origVertices[cVertex];
8588               break;
8589             }
8590           }
8591         }
8592         found = PETSC_TRUE;
8593         break;
8594       }
8595     }
8596     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
8597     if (posOriented) {*posOriented = PETSC_TRUE;}
8598     PetscFunctionReturn(0);
8599   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
8600   if (!posOrient) {
8601     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
8602     for (f = 0; f < faceSize; ++f) {
8603       faceVertices[f] = origVertices[faceSize-1 - f];
8604     }
8605   } else {
8606     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
8607     for (f = 0; f < faceSize; ++f) {
8608       faceVertices[f] = origVertices[f];
8609     }
8610   }
8611   if (posOriented) {*posOriented = posOrient;}
8612   PetscFunctionReturn(0);
8613 }
8614 
8615 #undef __FUNCT__
8616 #define __FUNCT__ "DMPlexGetOrientedFace"
8617 /*
8618     Given a cell and a face, as a set of vertices,
8619       return the oriented face, as a set of vertices, in faceVertices
8620     The orientation is such that the face normal points out of the cell
8621 */
8622 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
8623 {
8624   const PetscInt *cone = PETSC_NULL;
8625   PetscInt        coneSize, v, f, v2;
8626   PetscInt        oppositeVertex = -1;
8627   PetscErrorCode  ierr;
8628 
8629   PetscFunctionBegin;
8630   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8631   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
8632   for (v = 0, v2 = 0; v < coneSize; ++v) {
8633     PetscBool found  = PETSC_FALSE;
8634 
8635     for (f = 0; f < faceSize; ++f) {
8636       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
8637     }
8638     if (found) {
8639       indices[v2]      = v;
8640       origVertices[v2] = cone[v];
8641       ++v2;
8642     } else {
8643       oppositeVertex = v;
8644     }
8645   }
8646   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
8647   PetscFunctionReturn(0);
8648 }
8649 
8650 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8651 {
8652   switch(i) {
8653   case 0:
8654     switch(j) {
8655     case 0: return 0;
8656     case 1:
8657       switch(k) {
8658       case 0: return 0;
8659       case 1: return 0;
8660       case 2: return 1;
8661       }
8662     case 2:
8663       switch(k) {
8664       case 0: return 0;
8665       case 1: return -1;
8666       case 2: return 0;
8667       }
8668     }
8669   case 1:
8670     switch(j) {
8671     case 0:
8672       switch(k) {
8673       case 0: return 0;
8674       case 1: return 0;
8675       case 2: return -1;
8676       }
8677     case 1: return 0;
8678     case 2:
8679       switch(k) {
8680       case 0: return 1;
8681       case 1: return 0;
8682       case 2: return 0;
8683       }
8684     }
8685   case 2:
8686     switch(j) {
8687     case 0:
8688       switch(k) {
8689       case 0: return 0;
8690       case 1: return 1;
8691       case 2: return 0;
8692       }
8693     case 1:
8694       switch(k) {
8695       case 0: return -1;
8696       case 1: return 0;
8697       case 2: return 0;
8698       }
8699     case 2: return 0;
8700     }
8701   }
8702   return 0;
8703 }
8704 
8705 #undef __FUNCT__
8706 #define __FUNCT__ "DMPlexCreateRigidBody"
8707 /*@C
8708   DMPlexCreateRigidBody - create rigid body modes from coordinates
8709 
8710   Collective on DM
8711 
8712   Input Arguments:
8713 + dm - the DM
8714 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
8715 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
8716 
8717   Output Argument:
8718 . sp - the null space
8719 
8720   Note: This is necessary to take account of Dirichlet conditions on the displacements
8721 
8722   Level: advanced
8723 
8724 .seealso: MatNullSpaceCreate()
8725 @*/
8726 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8727 {
8728   MPI_Comm       comm = ((PetscObject) dm)->comm;
8729   Vec            coordinates, localMode, mode[6];
8730   PetscSection   coordSection;
8731   PetscScalar   *coords;
8732   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8733   PetscErrorCode ierr;
8734 
8735   PetscFunctionBegin;
8736   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8737   if (dim == 1) {
8738     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
8739     PetscFunctionReturn(0);
8740   }
8741   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8742   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8743   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8744   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8745   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8746   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8747   m    = (dim*(dim+1))/2;
8748   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8749   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8750   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8751   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8752   /* Assume P1 */
8753   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8754   for (d = 0; d < dim; ++d) {
8755     PetscScalar values[3] = {0.0, 0.0, 0.0};
8756 
8757     values[d] = 1.0;
8758     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8759     for (v = vStart; v < vEnd; ++v) {
8760       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8761     }
8762     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8763     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8764   }
8765   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8766   for (d = dim; d < dim*(dim+1)/2; ++d) {
8767     PetscInt i, j, k = dim > 2 ? d - dim : d;
8768 
8769     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8770     for (v = vStart; v < vEnd; ++v) {
8771       PetscScalar values[3] = {0.0, 0.0, 0.0};
8772       PetscInt    off;
8773 
8774       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8775       for (i = 0; i < dim; ++i) {
8776         for (j = 0; j < dim; ++j) {
8777           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8778         }
8779       }
8780       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8781     }
8782     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8783     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8784   }
8785   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8786   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8787   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
8788   /* Orthonormalize system */
8789   for (i = dim; i < m; ++i) {
8790     PetscScalar dots[6];
8791 
8792     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8793     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8794     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8795     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
8796   }
8797   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
8798   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
8799   PetscFunctionReturn(0);
8800 }
8801 
8802 #undef __FUNCT__
8803 #define __FUNCT__ "DMPlexGetVTKBounds"
8804 PetscErrorCode DMPlexGetVTKBounds(DM dm, PetscInt *cMax, PetscInt *vMax)
8805 {
8806   DM_Plex *mesh = (DM_Plex *) dm->data;
8807 
8808   PetscFunctionBegin;
8809   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8810   if (cMax) *cMax = mesh->vtkCellMax;
8811   if (vMax) *vMax = mesh->vtkVertexMax;
8812   PetscFunctionReturn(0);
8813 }
8814 
8815 #undef __FUNCT__
8816 #define __FUNCT__ "DMPlexSetVTKBounds"
8817 PetscErrorCode DMPlexSetVTKBounds(DM dm, PetscInt cMax, PetscInt vMax)
8818 {
8819   DM_Plex *mesh = (DM_Plex *) dm->data;
8820 
8821   PetscFunctionBegin;
8822   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8823   if (cMax >= 0) mesh->vtkCellMax   = cMax;
8824   if (vMax >= 0) mesh->vtkVertexMax = vMax;
8825   PetscFunctionReturn(0);
8826 }
8827 
8828 #undef __FUNCT__
8829 #define __FUNCT__ "DMPlexGetVTKCellHeight"
8830 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8831 {
8832   DM_Plex *mesh = (DM_Plex *) dm->data;
8833 
8834   PetscFunctionBegin;
8835   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8836   PetscValidPointer(cellHeight, 2);
8837   *cellHeight = mesh->vtkCellHeight;
8838   PetscFunctionReturn(0);
8839 }
8840 
8841 #undef __FUNCT__
8842 #define __FUNCT__ "DMPlexSetVTKCellHeight"
8843 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8844 {
8845   DM_Plex *mesh = (DM_Plex *) dm->data;
8846 
8847   PetscFunctionBegin;
8848   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8849   mesh->vtkCellHeight = cellHeight;
8850   PetscFunctionReturn(0);
8851 }
8852 
8853 #undef __FUNCT__
8854 #define __FUNCT__ "DMPlexInsertFace_Private"
8855 /*
8856   DMPlexInsertFace_Private - Puts a face into the mesh
8857 
8858   Not collective
8859 
8860   Input Parameters:
8861   + dm              - The DMPlex
8862   . numFaceVertex   - The number of vertices in the face
8863   . faceVertices    - The vertices in the face for dm
8864   . subfaceVertices - The vertices in the face for subdm
8865   . numCorners      - The number of vertices in the cell
8866   . cell            - A cell in dm containing the face
8867   . subcell         - A cell in subdm containing the face
8868   . firstFace       - First face in the mesh
8869   - newFacePoint    - Next face in the mesh
8870 
8871   Output Parameters:
8872   . newFacePoint - Contains next face point number on input, updated on output
8873 
8874   Level: developer
8875 */
8876 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)
8877 {
8878   MPI_Comm        comm    = ((PetscObject) dm)->comm;
8879   DM_Plex     *submesh = (DM_Plex *) subdm->data;
8880   const PetscInt *faces;
8881   PetscInt        numFaces, coneSize;
8882   PetscErrorCode  ierr;
8883 
8884   PetscFunctionBegin;
8885   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
8886   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
8887 #if 0
8888   /* Cannot use this because support() has not been constructed yet */
8889   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
8890 #else
8891   {
8892     PetscInt f;
8893 
8894     numFaces = 0;
8895     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
8896     for(f = firstFace; f < *newFacePoint; ++f) {
8897       PetscInt dof, off, d;
8898 
8899       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
8900       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
8901       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
8902       for(d = 0; d < dof; ++d) {
8903         const PetscInt p = submesh->cones[off+d];
8904         PetscInt       v;
8905 
8906         for(v = 0; v < numFaceVertices; ++v) {
8907           if (subfaceVertices[v] == p) break;
8908         }
8909         if (v == numFaceVertices) break;
8910       }
8911       if (d == dof) {
8912         numFaces = 1;
8913         ((PetscInt *) faces)[0] = f;
8914       }
8915     }
8916   }
8917 #endif
8918   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
8919   else if (numFaces == 1) {
8920     /* Add the other cell neighbor for this face */
8921     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
8922   } else {
8923     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
8924     PetscBool posOriented;
8925 
8926     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
8927     origVertices = &orientedVertices[numFaceVertices];
8928     indices      = &orientedVertices[numFaceVertices*2];
8929     orientedSubVertices = &orientedVertices[numFaceVertices*3];
8930     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
8931     /* TODO: I know that routine should return a permutation, not the indices */
8932     for(v = 0; v < numFaceVertices; ++v) {
8933       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
8934       for(ov = 0; ov < numFaceVertices; ++ov) {
8935         if (orientedVertices[ov] == vertex) {
8936           orientedSubVertices[ov] = subvertex;
8937           break;
8938         }
8939       }
8940       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
8941     }
8942     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
8943     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
8944     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
8945     ++(*newFacePoint);
8946   }
8947   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
8948   PetscFunctionReturn(0);
8949 }
8950 
8951 #undef __FUNCT__
8952 #define __FUNCT__ "DMPlexCreateSubmesh"
8953 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
8954 {
8955   MPI_Comm        comm = ((PetscObject) dm)->comm;
8956   DM_Plex     *submesh;
8957   PetscBool       boundaryFaces = PETSC_FALSE;
8958   PetscSection    coordSection, subCoordSection;
8959   Vec             coordinates, subCoordinates;
8960   PetscScalar    *coords, *subCoords;
8961   IS              labelIS;
8962   const PetscInt *subVertices;
8963   PetscInt       *subVerticesActive, *tmpPoints;
8964   PetscInt       *subCells = PETSC_NULL;
8965   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
8966   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
8967   PetscInt        dim; /* Right now, do not specify dimension */
8968   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
8969   PetscErrorCode  ierr;
8970 
8971   PetscFunctionBegin;
8972   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8973   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8974   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8975   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
8976   ierr = DMPlexGetVTKBounds(dm, &cMax, &vMax);CHKERRQ(ierr);
8977   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8978   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
8979   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
8980   subface = &face[maxConeSize];
8981   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
8982   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
8983   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
8984   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
8985   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
8986   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
8987   maxSubCells = numSubVertices;
8988   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
8989   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
8990   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
8991   for(v = 0; v < numSubVertices; ++v) {
8992     const PetscInt vertex = subVertices[v];
8993     PetscInt *star = PETSC_NULL;
8994     PetscInt  starSize, numCells = 0;
8995 
8996     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
8997     for(p = 0; p < starSize*2; p += 2) {
8998       const PetscInt point = star[p];
8999       if ((point >= cStart) && (point < cEnd)) {
9000         star[numCells++] = point;
9001       }
9002     }
9003     numOldSubCells = numSubCells;
9004     for(c = 0; c < numCells; ++c) {
9005       const PetscInt cell    = star[c];
9006       PetscInt      *closure = PETSC_NULL;
9007       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9008       PetscInt       cellLoc;
9009 
9010       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9011       if (cellLoc >= 0) continue;
9012       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9013       for(p = 0; p < closureSize*2; p += 2) {
9014         const PetscInt point = closure[p];
9015         if ((point >= vStart) && (point < vEnd)) {
9016           closure[numCorners++] = point;
9017         }
9018       }
9019       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9020       for(corner = 0; corner < numCorners; ++corner) {
9021         const PetscInt cellVertex = closure[corner];
9022         PetscInt       subVertex;
9023 
9024         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9025         if (subVertex >= 0) { /* contains submesh vertex */
9026           for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9027           if (i == faceSize) {
9028             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9029             face[faceSize]    = cellVertex;
9030             subface[faceSize] = subVertex;
9031             ++faceSize;
9032           }
9033         }
9034       }
9035       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9036       if (faceSize >= nFV) {
9037         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9038         if (numSubCells >= maxSubCells) {
9039           PetscInt *tmpCells;
9040           maxSubCells *= 2;
9041           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9042           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9043           ierr = PetscFree(subCells);CHKERRQ(ierr);
9044           subCells = tmpCells;
9045         }
9046         /* TOOD: Maybe overestimate then squeeze out empty faces */
9047         if (faceSize > nFV) {
9048           /* TODO: This is tricky. Maybe just add all faces */
9049           numSubFaces++;
9050         } else {
9051           numSubFaces++;
9052         }
9053         for(f = 0; f < faceSize; ++f) {
9054           subVerticesActive[subface[f]] = 1;
9055         }
9056         subCells[numSubCells++] = cell;
9057       }
9058     }
9059     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9060     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9061   }
9062   /* Pick out active subvertices */
9063   for(v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9064     if (subVerticesActive[v]) {
9065       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9066     }
9067   }
9068   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9069   /* Set cone sizes */
9070   firstSubVertex = numSubCells;
9071   firstSubFace   = numSubCells+numSubVerticesActive;
9072   newFacePoint   = firstSubFace;
9073   for(c = 0; c < numSubCells; ++c) {
9074     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
9075   }
9076   for(f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9077     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
9078   }
9079   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
9080   /* Create face cones */
9081   for(c = 0; c < numSubCells; ++c) {
9082     const PetscInt cell    = subCells[c];
9083     PetscInt      *closure = PETSC_NULL;
9084     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9085 
9086     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9087     for(p = 0; p < closureSize*2; p += 2) {
9088       const PetscInt point = closure[p];
9089       if ((point >= vStart) && (point < vEnd)) {
9090         closure[numCorners++] = point;
9091       }
9092     }
9093     for(corner = 0; corner < numCorners; ++corner) {
9094       const PetscInt cellVertex = closure[corner];
9095       PetscInt       subVertex;
9096 
9097       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9098       if (subVertex >= 0) { /* contains submesh vertex */
9099         for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9100         if (i == faceSize) {
9101           face[faceSize]    = cellVertex;
9102           subface[faceSize] = numSubCells+subVertex;
9103           ++faceSize;
9104         }
9105       }
9106     }
9107     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9108     if (faceSize >= nFV) {
9109       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9110       // Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron)
9111       //   We have to take all the faces, and discard those in the interior
9112       //   We check the join of the face vertices, which produces 2 cells if in the interior
9113 #if 0
9114       // This object just calls insert on each face that comes from subsets()
9115       // In fact, we can just always acll subsets(), since when we pass a single face it is a single call
9116       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9117       PointArray                          faceVec(face->begin(), face->end());
9118 
9119       subsets(faceVec, nFV, inserter);
9120 #endif
9121       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
9122     }
9123   }
9124   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
9125   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
9126   /* Build coordinates */
9127   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9128   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9129   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
9130   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
9131   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
9132     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
9133   }
9134   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
9135   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
9136   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
9137   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
9138   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
9139   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
9140   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9141   for(v = 0; v < numSubVerticesActive; ++v) {
9142     const PetscInt vertex    = subVerticesActive[v];
9143     const PetscInt subVertex = firstSubVertex+v;
9144     PetscInt dof, off, sdof, soff;
9145 
9146     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
9147     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
9148     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
9149     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
9150     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
9151     for(d = 0; d < dof; ++d) {
9152       subCoords[soff+d] = coords[off+d];
9153     }
9154   }
9155   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
9156   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9157   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
9158   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
9159 
9160   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
9161   /* Create map from submesh points to original mesh points */
9162   submesh = (DM_Plex *) (*subdm)->data;
9163   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
9164   for(c = 0; c < numSubCells; ++c) {
9165     tmpPoints[c] = subCells[c];
9166   }
9167   for(v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
9168     tmpPoints[v] = subVerticesActive[v-numSubCells];
9169   }
9170   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
9171 
9172   ierr = PetscFree(subCells);CHKERRQ(ierr);
9173   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
9174   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
9175   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
9176   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9177   PetscFunctionReturn(0);
9178 }
9179 
9180 #undef __FUNCT__
9181 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9182 /* We can easily have a form that takes an IS instead */
9183 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9184 {
9185   PetscSection   section, globalSection;
9186   PetscInt      *numbers, p;
9187   PetscErrorCode ierr;
9188 
9189   PetscFunctionBegin;
9190   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
9191   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9192   for(p = pStart; p < pEnd; ++p) {
9193     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9194   }
9195   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9196   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9197   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9198   for(p = pStart; p < pEnd; ++p) {
9199     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9200   }
9201   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9202   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9203   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9204   PetscFunctionReturn(0);
9205 }
9206 
9207 #undef __FUNCT__
9208 #define __FUNCT__ "DMPlexGetCellNumbering"
9209 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9210 {
9211   DM_Plex    *mesh = (DM_Plex *) dm->data;
9212   PetscInt       cellHeight, cStart, cEnd, cMax;
9213   PetscErrorCode ierr;
9214 
9215   PetscFunctionBegin;
9216   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9217   if (!mesh->globalCellNumbers) {
9218     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9219     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9220     ierr = DMPlexGetVTKBounds(dm, &cMax, PETSC_NULL);CHKERRQ(ierr);
9221     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9222     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9223   }
9224   *globalCellNumbers = mesh->globalCellNumbers;
9225   PetscFunctionReturn(0);
9226 }
9227 
9228 #undef __FUNCT__
9229 #define __FUNCT__ "DMPlexGetVertexNumbering"
9230 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9231 {
9232   DM_Plex    *mesh = (DM_Plex *) dm->data;
9233   PetscInt       vStart, vEnd, vMax;
9234   PetscErrorCode ierr;
9235 
9236   PetscFunctionBegin;
9237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9238   if (!mesh->globalVertexNumbers) {
9239     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9240     ierr = DMPlexGetVTKBounds(dm, PETSC_NULL, &vMax);CHKERRQ(ierr);
9241     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9242     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9243   }
9244   *globalVertexNumbers = mesh->globalVertexNumbers;
9245   PetscFunctionReturn(0);
9246 }
9247 
9248 #undef __FUNCT__
9249 #define __FUNCT__ "DMPlexGetSubpointMap"
9250 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
9251 {
9252   DM_Plex *mesh = (DM_Plex *) dm->data;
9253 
9254   PetscFunctionBegin;
9255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9256   PetscValidPointer(subpointMap, 2);
9257   *subpointMap = mesh->subpointMap;
9258   PetscFunctionReturn(0);
9259 }
9260 
9261 #undef __FUNCT__
9262 #define __FUNCT__ "DMPlexSetSubpointMap"
9263 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
9264 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
9265 {
9266   DM_Plex *mesh = (DM_Plex *) dm->data;
9267 
9268   PetscFunctionBegin;
9269   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9270   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
9271   mesh->subpointMap = subpointMap;
9272   PetscFunctionReturn(0);
9273 }
9274 
9275 #undef __FUNCT__
9276 #define __FUNCT__ "DMPlexGetScale"
9277 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9278 {
9279   DM_Plex *mesh = (DM_Plex *) dm->data;
9280 
9281   PetscFunctionBegin;
9282   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9283   PetscValidPointer(scale, 3);
9284   *scale = mesh->scale[unit];
9285   PetscFunctionReturn(0);
9286 }
9287 
9288 #undef __FUNCT__
9289 #define __FUNCT__ "DMPlexSetScale"
9290 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9291 {
9292   DM_Plex *mesh = (DM_Plex *) dm->data;
9293 
9294   PetscFunctionBegin;
9295   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9296   mesh->scale[unit] = scale;
9297   PetscFunctionReturn(0);
9298 }
9299 
9300 
9301 /*******************************************************************************
9302 This should be in a separate Discretization object, but I am not sure how to lay
9303 it out yet, so I am stuffing things here while I experiment.
9304 *******************************************************************************/
9305 #undef __FUNCT__
9306 #define __FUNCT__ "DMPlexSetFEMIntegration"
9307 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9308                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9309                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9310                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9311                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9312                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9313                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9314                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9315                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9316                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9317                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9318                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9319                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9320                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9321                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9322                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9323                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9324 {
9325   DM_Plex *mesh = (DM_Plex *) dm->data;
9326 
9327   PetscFunctionBegin;
9328   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9329   mesh->integrateResidualFEM       = integrateResidualFEM;
9330   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9331   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9332   PetscFunctionReturn(0);
9333 }
9334 
9335 #undef __FUNCT__
9336 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9337 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9338 {
9339   Vec            coordinates;
9340   PetscSection   section, cSection;
9341   PetscInt       dim, vStart, vEnd, v, c, d;
9342   PetscScalar   *values, *cArray;
9343   PetscReal     *coords;
9344   PetscErrorCode ierr;
9345 
9346   PetscFunctionBegin;
9347   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9348   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9349   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9350   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9351   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9352   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9353   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9354   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9355   for (v = vStart; v < vEnd; ++v) {
9356     PetscInt dof, off;
9357 
9358     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9359     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9360     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9361     for(d = 0; d < dof; ++d) {
9362       coords[d] = PetscRealPart(cArray[off+d]);
9363     }
9364     for(c = 0; c < numComp; ++c) {
9365       values[c] = (*funcs[c])(coords);
9366     }
9367     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9368   }
9369   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9370   /* Temporary, must be replaced by a projection on the finite element basis */
9371   {
9372     PetscInt eStart = 0, eEnd = 0, e, depth;
9373 
9374     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9375     --depth;
9376     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9377     for (e = eStart; e < eEnd; ++e) {
9378       const PetscInt *cone = PETSC_NULL;
9379       PetscInt        coneSize, d;
9380       PetscScalar    *coordsA, *coordsB;
9381 
9382       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9383       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9384       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9385       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9386       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9387       for (d = 0; d < dim; ++d) {
9388         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9389       }
9390       for (c = 0; c < numComp; ++c) {
9391         values[c] = (*funcs[c])(coords);
9392       }
9393       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9394     }
9395   }
9396 
9397   ierr = PetscFree(coords);CHKERRQ(ierr);
9398   ierr = PetscFree(values);CHKERRQ(ierr);
9399 #if 0
9400   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9401   PetscReal      detJ;
9402 
9403   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9404   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9405   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV((int) pow(this->_mesh->getSieve()->getMaxConeSize(), dim+1)+1, true);
9406 
9407   for (PetscInt c = cStart; c < cEnd; ++c) {
9408     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9409     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9410     const int                          oSize   = pV.getSize();
9411     int                                v       = 0;
9412 
9413     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
9414     for (PetscInt cl = 0; cl < oSize; ++cl) {
9415       const PetscInt fDim;
9416 
9417       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9418       if (pointDim) {
9419         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9420           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9421         }
9422       }
9423     }
9424     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
9425     pV.clear();
9426   }
9427   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9428   ierr = PetscFree(values);CHKERRQ(ierr);
9429 #endif
9430   PetscFunctionReturn(0);
9431 }
9432 
9433 #undef __FUNCT__
9434 #define __FUNCT__ "DMPlexProjectFunction"
9435 /*@C
9436   DMPlexProjectFunction - This projects the given function into the function space provided.
9437 
9438   Input Parameters:
9439 + dm      - The DM
9440 . numComp - The number of components (functions)
9441 . funcs   - The coordinate functions to evaluate
9442 - mode    - The insertion mode for values
9443 
9444   Output Parameter:
9445 . X - vector
9446 
9447   Level: developer
9448 
9449   Note:
9450   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9451   We will eventually fix it.
9452 
9453 ,seealso: DMPlexComputeL2Diff()
9454 */
9455 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9456 {
9457   Vec            localX;
9458   PetscErrorCode ierr;
9459 
9460   PetscFunctionBegin;
9461   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9462   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9463   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9464   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9465   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9466   PetscFunctionReturn(0);
9467 }
9468 
9469 #undef __FUNCT__
9470 #define __FUNCT__ "DMPlexComputeL2Diff"
9471 /*@C
9472   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9473 
9474   Input Parameters:
9475 + dm    - The DM
9476 . quad  - The PetscQuadrature object for each field
9477 . funcs - The functions to evaluate for each field component
9478 - X     - The coefficient vector u_h
9479 
9480   Output Parameter:
9481 . diff - The diff ||u - u_h||_2
9482 
9483   Level: developer
9484 
9485 .seealso: DMPlexProjectFunction()
9486 */
9487 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff) {
9488   const PetscInt   debug = 0;
9489   PetscSection     section;
9490   Vec              localX;
9491   PetscReal       *coords, *v0, *J, *invJ, detJ;
9492   PetscReal        localDiff = 0.0;
9493   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9494   PetscErrorCode   ierr;
9495 
9496   PetscFunctionBegin;
9497   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9498   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9499   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9500   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9501   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9502   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9503   for (field = 0; field < numFields; ++field) {
9504     numComponents += quad[field].numComponents;
9505   }
9506   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9507   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9508   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9509   for (c = cStart; c < cEnd; ++c) {
9510     const PetscScalar *x;
9511     PetscReal          elemDiff = 0.0;
9512 
9513     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9514     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9515     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
9516 
9517     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9518       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9519       const PetscReal *quadPoints    = quad[field].quadPoints;
9520       const PetscReal *quadWeights   = quad[field].quadWeights;
9521       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9522       const PetscInt   numBasisComps = quad[field].numComponents;
9523       const PetscReal *basis         = quad[field].basis;
9524       PetscInt         q, d, e, fc, f;
9525 
9526       if (debug) {
9527         char title[1024];
9528         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9529         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9530       }
9531       for (q = 0; q < numQuadPoints; ++q) {
9532         for (d = 0; d < dim; d++) {
9533           coords[d] = v0[d];
9534           for (e = 0; e < dim; e++) {
9535             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9536           }
9537         }
9538         for (fc = 0; fc < numBasisComps; ++fc) {
9539           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9540           PetscReal       interpolant = 0.0;
9541           for (f = 0; f < numBasisFuncs; ++f) {
9542             const PetscInt fidx = f*numBasisComps+fc;
9543             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9544           }
9545           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9546           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9547         }
9548       }
9549       comp        += numBasisComps;
9550       fieldOffset += numBasisFuncs*numBasisComps;
9551     }
9552     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
9553     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9554     localDiff += elemDiff;
9555   }
9556   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9557   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9558   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9559   *diff = PetscSqrtReal(*diff);
9560   PetscFunctionReturn(0);
9561 }
9562 
9563 #undef __FUNCT__
9564 #define __FUNCT__ "DMPlexComputeResidualFEM"
9565 /*@
9566   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9567 
9568   Input Parameters:
9569 + dm - The mesh
9570 . X  - Local input vector
9571 - user - The user context
9572 
9573   Output Parameter:
9574 . F  - Local output vector
9575 
9576   Note:
9577   The second member of the user context must be an FEMContext.
9578 
9579   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9580   like a GPU, or vectorize on a multicore machine.
9581 
9582 .seealso: DMPlexComputeJacobianActionFEM()
9583 */
9584 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9585 {
9586   DM_Plex      *mesh = (DM_Plex *) dm->data;
9587   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9588   PetscQuadrature *quad = fem->quad;
9589   PetscSection     section;
9590   PetscReal       *v0, *J, *invJ, *detJ;
9591   PetscScalar     *elemVec, *u;
9592   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9593   PetscInt         cellDof = 0, numComponents = 0;
9594   PetscErrorCode   ierr;
9595 
9596   PetscFunctionBegin;
9597   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9598   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9599   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9600   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9601   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9602   numCells = cEnd - cStart;
9603   for (field = 0; field < numFields; ++field) {
9604     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9605     numComponents += quad[field].numComponents;
9606   }
9607   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9608   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9609   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);
9610   for (c = cStart; c < cEnd; ++c) {
9611     const PetscScalar *x;
9612     PetscInt           i;
9613 
9614     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9615     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9616     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9617 
9618     for (i = 0; i < cellDof; ++i) {
9619       u[c*cellDof+i] = x[i];
9620     }
9621     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9622   }
9623   for (field = 0; field < numFields; ++field) {
9624     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9625     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9626     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9627     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9628     /* Conforming batches */
9629     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9630     PetscInt numBlocks  = 1;
9631     PetscInt batchSize  = numBlocks * blockSize;
9632     PetscInt numBatches = numBatchesTmp;
9633     PetscInt numChunks  = numCells / (numBatches*batchSize);
9634     /* Remainder */
9635     PetscInt numRemainder = numCells % (numBatches * batchSize);
9636     PetscInt offset       = numCells - numRemainder;
9637 
9638     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9639     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9640                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9641   }
9642   for (c = cStart; c < cEnd; ++c) {
9643     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9644     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9645   }
9646   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9647   if (mesh->printFEM) {
9648     PetscMPIInt rank, numProcs;
9649     PetscInt    p;
9650 
9651     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9652     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9653     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9654     for (p = 0; p < numProcs; ++p) {
9655       if (p == rank) {
9656         Vec f;
9657 
9658         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9659         ierr = VecCopy(F, f);CHKERRQ(ierr);
9660         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9661         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9662         ierr = VecDestroy(&f);CHKERRQ(ierr);
9663         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9664       }
9665       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9666     }
9667   }
9668   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9669   PetscFunctionReturn(0);
9670 }
9671 
9672 #undef __FUNCT__
9673 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9674 /*@C
9675   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9676 
9677   Input Parameters:
9678 + dm - The mesh
9679 . J  - The Jacobian shell matrix
9680 . X  - Local input vector
9681 - user - The user context
9682 
9683   Output Parameter:
9684 . F  - Local output vector
9685 
9686   Note:
9687   The second member of the user context must be an FEMContext.
9688 
9689   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9690   like a GPU, or vectorize on a multicore machine.
9691 
9692 .seealso: DMPlexComputeResidualFEM()
9693 */
9694 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9695 {
9696   DM_Plex      *mesh = (DM_Plex *) dm->data;
9697   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9698   PetscQuadrature *quad = fem->quad;
9699   PetscSection     section;
9700   JacActionCtx    *jctx;
9701   PetscReal       *v0, *J, *invJ, *detJ;
9702   PetscScalar     *elemVec, *u, *a;
9703   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9704   PetscInt         cellDof = 0;
9705   PetscErrorCode   ierr;
9706 
9707   PetscFunctionBegin;
9708   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9709   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9710   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9711   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9712   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9713   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9714   numCells = cEnd - cStart;
9715   for (field = 0; field < numFields; ++field) {
9716     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9717   }
9718   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9719   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);
9720   for (c = cStart; c < cEnd; ++c) {
9721     const PetscScalar *x;
9722     PetscInt           i;
9723 
9724     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9725     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9726     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
9727     for (i = 0; i < cellDof; ++i) {
9728       u[c*cellDof+i] = x[i];
9729     }
9730     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
9731     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9732     for (i = 0; i < cellDof; ++i) {
9733       a[c*cellDof+i] = x[i];
9734     }
9735     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9736   }
9737   for (field = 0; field < numFields; ++field) {
9738     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9739     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9740     /* Conforming batches */
9741     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9742     PetscInt numBlocks  = 1;
9743     PetscInt batchSize  = numBlocks * blockSize;
9744     PetscInt numBatches = numBatchesTmp;
9745     PetscInt numChunks  = numCells / (numBatches*batchSize);
9746     /* Remainder */
9747     PetscInt numRemainder = numCells % (numBatches * batchSize);
9748     PetscInt offset       = numCells - numRemainder;
9749 
9750     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);
9751     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],
9752                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9753   }
9754   for (c = cStart; c < cEnd; ++c) {
9755     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9756     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9757   }
9758   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9759   if (mesh->printFEM) {
9760     PetscMPIInt rank, numProcs;
9761     PetscInt    p;
9762 
9763     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9764     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9765     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9766     for (p = 0; p < numProcs; ++p) {
9767       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9768       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9769     }
9770   }
9771   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9772   PetscFunctionReturn(0);
9773 }
9774 
9775 #undef __FUNCT__
9776 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9777 /*@
9778   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9779 
9780   Input Parameters:
9781 + dm - The mesh
9782 . X  - Local input vector
9783 - user - The user context
9784 
9785   Output Parameter:
9786 . Jac  - Jacobian matrix
9787 
9788   Note:
9789   The second member of the user context must be an FEMContext.
9790 
9791   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9792   like a GPU, or vectorize on a multicore machine.
9793 
9794 .seealso: FormFunctionLocal()
9795 */
9796 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9797 {
9798   DM_Plex      *mesh = (DM_Plex *) dm->data;
9799   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9800   PetscQuadrature *quad = fem->quad;
9801   PetscSection     section;
9802   PetscReal       *v0, *J, *invJ, *detJ;
9803   PetscScalar     *elemMat, *u;
9804   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9805   PetscInt         cellDof = 0, numComponents = 0;
9806   PetscBool        isShell;
9807   PetscErrorCode   ierr;
9808 
9809   PetscFunctionBegin;
9810   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9811   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9812   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9813   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9814   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9815   numCells = cEnd - cStart;
9816   for (field = 0; field < numFields; ++field) {
9817     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9818     numComponents += quad[field].numComponents;
9819   }
9820   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9821   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9822   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);
9823   for (c = cStart; c < cEnd; ++c) {
9824     const PetscScalar *x;
9825     PetscInt           i;
9826 
9827     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9828     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9829     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9830 
9831     for (i = 0; i < cellDof; ++i) {
9832       u[c*cellDof+i] = x[i];
9833     }
9834     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9835   }
9836   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9837   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9838     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9839     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9840     PetscInt       fieldJ;
9841 
9842     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9843       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9844       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9845       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9846       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9847       /* Conforming batches */
9848       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9849       PetscInt numBlocks  = 1;
9850       PetscInt batchSize  = numBlocks * blockSize;
9851       PetscInt numBatches = numBatchesTmp;
9852       PetscInt numChunks  = numCells / (numBatches*batchSize);
9853       /* Remainder */
9854       PetscInt numRemainder = numCells % (numBatches * batchSize);
9855       PetscInt offset       = numCells - numRemainder;
9856 
9857       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9858       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9859                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9860     }
9861   }
9862   for (c = cStart; c < cEnd; ++c) {
9863     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9864     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9865   }
9866   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9867 
9868   /* Assemble matrix, using the 2-step process:
9869        MatAssemblyBegin(), MatAssemblyEnd(). */
9870   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9871   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9872 
9873   if (mesh->printFEM) {
9874     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9875     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9876     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9877   }
9878   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9879   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9880   if (isShell) {
9881     JacActionCtx *jctx;
9882 
9883     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9884     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9885   }
9886   *str = SAME_NONZERO_PATTERN;
9887   PetscFunctionReturn(0);
9888 }
9889 
9890 
9891 #undef __FUNCT__
9892 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9893 /*@C
9894   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9895   the local section and an SF describing the section point overlap.
9896 
9897   Input Parameters:
9898   + s - The PetscSection for the local field layout
9899   . sf - The SF describing parallel layout of the section points
9900   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9901   . label - The label specifying the points
9902   - labelValue - The label stratum specifying the points
9903 
9904   Output Parameter:
9905   . gsection - The PetscSection for the global field layout
9906 
9907   Note: This gives negative sizes and offsets to points not owned by this process
9908 
9909   Level: developer
9910 
9911 .seealso: PetscSectionCreate()
9912 @*/
9913 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9914 {
9915   PetscInt      *neg;
9916   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9917   PetscErrorCode ierr;
9918 
9919   PetscFunctionBegin;
9920   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9921   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9922   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9923   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9924   /* Mark ghost points with negative dof */
9925   for (p = pStart; p < pEnd; ++p) {
9926     PetscInt value;
9927 
9928     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9929     if (value != labelValue) continue;
9930     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9931     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9932     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9933     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9934     neg[p-pStart] = -(dof+1);
9935   }
9936   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9937   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
9938   if (nroots >= 0) {
9939     if (nroots > pEnd - pStart) {
9940       PetscInt *tmpDof;
9941       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9942       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9943       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9944       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9945       for (p = pStart; p < pEnd; ++p) {
9946         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
9947       }
9948       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9949     } else {
9950       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9951       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9952     }
9953   }
9954   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9955   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9956     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9957     (*gsection)->atlasOff[p] = off;
9958     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9959   }
9960   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9961   globalOff -= off;
9962   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9963     (*gsection)->atlasOff[p] += globalOff;
9964     neg[p] = -((*gsection)->atlasOff[p]+1);
9965   }
9966   /* Put in negative offsets for ghost points */
9967   if (nroots >= 0) {
9968     if (nroots > pEnd - pStart) {
9969       PetscInt *tmpOff;
9970       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9971       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9972       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9973       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9974       for (p = pStart; p < pEnd; ++p) {
9975         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
9976       }
9977       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9978     } else {
9979       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9980       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9981     }
9982   }
9983   ierr = PetscFree(neg);CHKERRQ(ierr);
9984   PetscFunctionReturn(0);
9985 }
9986