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