xref: /petsc/src/dm/impls/plex/plex.c (revision 8ad47952706b5b3a4d2ddd55b418d583f25bc7ec)
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   = coords[faces[2*f+0]*2+0];
7315     PetscReal y_i   = coords[faces[2*f+0]*2+1];
7316     PetscReal x_j   = coords[faces[2*f+1]*2+0];
7317     PetscReal y_j   = 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   PetscReal          x         = PetscRealPart(point[0]);
7369   PetscReal          y         = PetscRealPart(point[1]);
7370   PetscReal          z         = PetscRealPart(point[2]);
7371   PetscBool          found     = PETSC_TRUE;
7372   PetscInt           f;
7373   PetscErrorCode     ierr;
7374 
7375   PetscFunctionBegin;
7376   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7377   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7378   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7379   for(f = 0; f < 6; ++f) {
7380     /* Check the point is under plane */
7381     /*   Get face normal */
7382     PetscReal v_i[3]    = {coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0],coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1],coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]};
7383     PetscReal v_j[3]    = {coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0],coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1],coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]};
7384     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]};
7385     PetscReal pp[3]     = {coords[faces[f*4+0]*3+0] - x,coords[faces[f*4+0]*3+1] - y,coords[faces[f*4+0]*3+2] - z};
7386     PetscReal dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7387     /* Check that projected point is in face (2D location problem) */
7388     if (dot < 0.0) {
7389       found = PETSC_FALSE;
7390       break;
7391     }
7392   }
7393   if (found) {
7394     *cell = c;
7395   } else {
7396     *cell = -1;
7397   }
7398   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7399   PetscFunctionReturn(0);
7400 }
7401 
7402 #undef __FUNCT__
7403 #define __FUNCT__ "DMLocatePoints_Plex"
7404 /*
7405  Need to implement using the guess
7406 */
7407 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7408 {
7409   PetscInt       cell = -1/*, guess = -1*/;
7410   PetscInt       bs, numPoints, p;
7411   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7412   PetscInt      *cells;
7413   PetscScalar   *a;
7414   PetscErrorCode ierr;
7415 
7416   PetscFunctionBegin;
7417   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7418   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7419   ierr = DMPlexGetVTKBounds(dm, &cMax, PETSC_NULL);CHKERRQ(ierr);
7420   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7421   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7422   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7423   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);
7424   numPoints /= bs;
7425   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7426   for(p = 0; p < numPoints; ++p) {
7427     const PetscScalar *point = &a[p*bs];
7428 
7429     switch(dim) {
7430     case 2:
7431       for(c = cStart; c < cEnd; ++c) {
7432         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7433         switch(coneSize) {
7434         case 3:
7435           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7436           break;
7437         case 4:
7438           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7439           break;
7440         default:
7441           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7442         }
7443         if (cell >= 0) break;
7444       }
7445       break;
7446     case 3:
7447       for(c = cStart; c < cEnd; ++c) {
7448         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7449         switch(coneSize) {
7450         case 4:
7451           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
7452           break;
7453         case 8:
7454           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
7455           break;
7456         default:
7457           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7458         }
7459         if (cell >= 0) break;
7460       }
7461       break;
7462     default:
7463       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
7464     }
7465     cells[p] = cell;
7466   }
7467   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
7468   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
7469   PetscFunctionReturn(0);
7470 }
7471 
7472 /******************************** FEM Support **********************************/
7473 
7474 #undef __FUNCT__
7475 #define __FUNCT__ "DMPlexVecGetClosure"
7476 /*@C
7477   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
7478 
7479   Not collective
7480 
7481   Input Parameters:
7482 + dm - The DM
7483 . section - The section describing the layout in v, or PETSC_NULL to use the default section
7484 . v - The local vector
7485 - point - The sieve point in the DM
7486 
7487   Output Parameters:
7488 + csize - The number of values in the closure, or PETSC_NULL
7489 - values - The array of values, which is a borrowed array and should not be freed
7490 
7491   Level: intermediate
7492 
7493 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7494 @*/
7495 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
7496   PetscScalar    *array, *vArray;
7497   PetscInt       *points = PETSC_NULL;
7498   PetscInt        offsets[32];
7499   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
7500   PetscErrorCode  ierr;
7501 
7502   PetscFunctionBegin;
7503   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7504   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7505   if (!section) {
7506     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7507   }
7508   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7509   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7510   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7511   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7512   /* Compress out points not in the section */
7513   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7514   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7515     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7516       points[q*2]   = points[p];
7517       points[q*2+1] = points[p+1];
7518       ++q;
7519     }
7520   }
7521   numPoints = q;
7522   for (p = 0, size = 0; p < numPoints*2; p += 2) {
7523     PetscInt dof, fdof;
7524 
7525     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7526     for (f = 0; f < numFields; ++f) {
7527       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7528       offsets[f+1] += fdof;
7529     }
7530     size += dof;
7531   }
7532   for (f = 1; f < numFields; ++f) {
7533     offsets[f+1] += offsets[f];
7534   }
7535   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
7536   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
7537   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
7538   for (p = 0; p < numPoints*2; p += 2) {
7539     PetscInt     o = points[p+1];
7540     PetscInt     dof, off, d;
7541     PetscScalar *varr;
7542 
7543     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7544     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
7545     varr = &vArray[off];
7546     if (numFields) {
7547       PetscInt fdof, foff, fcomp, f, c;
7548 
7549       for (f = 0, foff = 0; f < numFields; ++f) {
7550         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7551         if (o >= 0) {
7552           for (d = 0; d < fdof; ++d, ++offsets[f]) {
7553             array[offsets[f]] = varr[foff+d];
7554           }
7555         } else {
7556           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7557           for (d = fdof/fcomp-1; d >= 0; --d) {
7558             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
7559               array[offsets[f]] = varr[foff+d*fcomp+c];
7560             }
7561           }
7562         }
7563         foff += fdof;
7564       }
7565     } else {
7566       if (o >= 0) {
7567         for (d = 0; d < dof; ++d, ++offsets[0]) {
7568           array[offsets[0]] = varr[d];
7569         }
7570       } else {
7571         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
7572           array[offsets[0]] = varr[d];
7573         }
7574       }
7575     }
7576   }
7577   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7578   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
7579   if (csize) *csize = size;
7580   *values = array;
7581   PetscFunctionReturn(0);
7582 }
7583 
7584 #undef __FUNCT__
7585 #define __FUNCT__ "DMPlexVecRestoreClosure"
7586 /*@C
7587   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
7588 
7589   Not collective
7590 
7591   Input Parameters:
7592 + dm - The DM
7593 . section - The section describing the layout in v, or PETSC_NULL to use the default section
7594 . v - The local vector
7595 . point - The sieve point in the DM
7596 . csize - The number of values in the closure, or PETSC_NULL
7597 - values - The array of values, which is a borrowed array and should not be freed
7598 
7599   Level: intermediate
7600 
7601 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7602 @*/
7603 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
7604   PetscInt        size = 0;
7605   PetscErrorCode  ierr;
7606 
7607   PetscFunctionBegin;
7608   /* Should work without recalculating size */
7609   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
7610   PetscFunctionReturn(0);
7611 }
7612 
7613 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
7614 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
7615 
7616 #undef __FUNCT__
7617 #define __FUNCT__ "updatePoint_private"
7618 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
7619 {
7620   PetscInt        cdof;  /* The number of constraints on this point */
7621   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7622   PetscScalar    *a;
7623   PetscInt        off, cind = 0, k;
7624   PetscErrorCode  ierr;
7625 
7626   PetscFunctionBegin;
7627   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7628   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7629   a    = &array[off];
7630   if (!cdof || setBC) {
7631     if (orientation >= 0) {
7632       for (k = 0; k < dof; ++k) {
7633         fuse(&a[k], values[k]);
7634       }
7635     } else {
7636       for (k = 0; k < dof; ++k) {
7637         fuse(&a[k], values[dof-k-1]);
7638       }
7639     }
7640   } else {
7641     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7642     if (orientation >= 0) {
7643       for (k = 0; k < dof; ++k) {
7644         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7645         fuse(&a[k], values[k]);
7646       }
7647     } else {
7648       for (k = 0; k < dof; ++k) {
7649         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7650         fuse(&a[k], values[dof-k-1]);
7651       }
7652     }
7653   }
7654   PetscFunctionReturn(0);
7655 }
7656 
7657 #undef __FUNCT__
7658 #define __FUNCT__ "updatePointFields_private"
7659 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[]) {
7660   PetscScalar   *a;
7661   PetscInt       numFields, off, foff, f;
7662   PetscErrorCode ierr;
7663 
7664   PetscFunctionBegin;
7665   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7666   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7667   a    = &array[off];
7668   for (f = 0, foff = 0; f < numFields; ++f) {
7669     PetscInt        fdof, fcomp, fcdof;
7670     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7671     PetscInt        cind = 0, k, c;
7672 
7673     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7674     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7675     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
7676     if (!fcdof || setBC) {
7677       if (orientation >= 0) {
7678         for (k = 0; k < fdof; ++k) {
7679           fuse(&a[foff+k], values[foffs[f]+k]);
7680         }
7681       } else {
7682         for (k = fdof/fcomp-1; k >= 0; --k) {
7683           for (c = 0; c < fcomp; ++c) {
7684             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7685           }
7686         }
7687       }
7688     } else {
7689       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7690       if (orientation >= 0) {
7691         for (k = 0; k < fdof; ++k) {
7692           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
7693           fuse(&a[foff+k], values[foffs[f]+k]);
7694         }
7695       } else {
7696         for (k = fdof/fcomp-1; k >= 0; --k) {
7697           for (c = 0; c < fcomp; ++c) {
7698             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
7699             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7700           }
7701         }
7702       }
7703     }
7704     foff     += fdof;
7705     foffs[f] += fdof;
7706   }
7707   PetscFunctionReturn(0);
7708 }
7709 
7710 #undef __FUNCT__
7711 #define __FUNCT__ "DMPlexVecSetClosure"
7712 /*@C
7713   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
7714 
7715   Not collective
7716 
7717   Input Parameters:
7718 + dm - The DM
7719 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
7720 . v - The local vector
7721 . point - The sieve point in the DM
7722 . values - The array of values, which is a borrowed array and should not be freed
7723 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7724 
7725   Level: intermediate
7726 
7727 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
7728 @*/
7729 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) {
7730   PetscScalar    *array;
7731   PetscInt       *points = PETSC_NULL;
7732   PetscInt        offsets[32];
7733   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
7734   PetscErrorCode  ierr;
7735 
7736   PetscFunctionBegin;
7737   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7738   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7739   if (!section) {
7740     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7741   }
7742   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7743   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7744   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7745   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7746   /* Compress out points not in the section */
7747   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7748   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7749     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7750       points[q*2]   = points[p];
7751       points[q*2+1] = points[p+1];
7752       ++q;
7753     }
7754   }
7755   numPoints = q;
7756   for (p = 0; p < numPoints*2; p += 2) {
7757     PetscInt fdof;
7758 
7759     for (f = 0; f < numFields; ++f) {
7760       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7761       offsets[f+1] += fdof;
7762     }
7763   }
7764   for (f = 1; f < numFields; ++f) {
7765     offsets[f+1] += offsets[f];
7766   }
7767   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
7768   if (numFields) {
7769     switch(mode) {
7770     case INSERT_VALUES:
7771       for (p = 0; p < numPoints*2; p += 2) {
7772         PetscInt o = points[p+1];
7773         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
7774       } break;
7775     case INSERT_ALL_VALUES:
7776       for (p = 0; p < numPoints*2; p += 2) {
7777         PetscInt o = points[p+1];
7778         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
7779       } break;
7780     case ADD_VALUES:
7781       for (p = 0; p < numPoints*2; p += 2) {
7782         PetscInt o = points[p+1];
7783         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
7784       } break;
7785     case ADD_ALL_VALUES:
7786       for (p = 0; p < numPoints*2; p += 2) {
7787         PetscInt o = points[p+1];
7788         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
7789       } break;
7790     default:
7791       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7792     }
7793   } else {
7794     switch(mode) {
7795     case INSERT_VALUES:
7796       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7797         PetscInt o = points[p+1];
7798         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7799         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
7800       } break;
7801     case INSERT_ALL_VALUES:
7802       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7803         PetscInt o = points[p+1];
7804         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7805         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
7806       } break;
7807     case ADD_VALUES:
7808       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7809         PetscInt o = points[p+1];
7810         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7811         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
7812       } break;
7813     case ADD_ALL_VALUES:
7814       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7815         PetscInt o = points[p+1];
7816         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7817         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
7818       } break;
7819     default:
7820       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7821     }
7822   }
7823   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7824   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
7825   PetscFunctionReturn(0);
7826 }
7827 
7828 #undef __FUNCT__
7829 #define __FUNCT__ "DMPlexPrintMatSetValues"
7830 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
7831 {
7832   PetscMPIInt    rank;
7833   PetscInt       i, j;
7834   PetscErrorCode ierr;
7835 
7836   PetscFunctionBegin;
7837   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
7838   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
7839   for (i = 0; i < numIndices; i++) {
7840     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
7841   }
7842   for (i = 0; i < numIndices; i++) {
7843     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
7844     for (j = 0; j < numIndices; j++) {
7845 #ifdef PETSC_USE_COMPLEX
7846       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
7847 #else
7848       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
7849 #endif
7850     }
7851     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
7852   }
7853   PetscFunctionReturn(0);
7854 }
7855 
7856 #undef __FUNCT__
7857 #define __FUNCT__ "indicesPoint_private"
7858 /* . off - The global offset of this point */
7859 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
7860   PetscInt        cdof;  /* The number of constraints on this point */
7861   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7862   PetscInt        cind = 0, k;
7863   PetscErrorCode  ierr;
7864 
7865   PetscFunctionBegin;
7866   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
7867   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7868   if (!cdof || setBC) {
7869     if (orientation >= 0) {
7870       for (k = 0; k < dof; ++k) {
7871         indices[k] = off+k;
7872       }
7873     } else {
7874       for (k = 0; k < dof; ++k) {
7875         indices[dof-k-1] = off+k;
7876       }
7877     }
7878   } else {
7879     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7880     if (orientation >= 0) {
7881       for (k = 0; k < dof; ++k) {
7882         if ((cind < cdof) && (k == cdofs[cind])) {
7883           /* Insert check for returning constrained indices */
7884           indices[k] = -(off+k+1);
7885           ++cind;
7886         } else {
7887           indices[k] = off+k-cind;
7888         }
7889       }
7890     } else {
7891       for (k = 0; k < dof; ++k) {
7892         if ((cind < cdof) && (k == cdofs[cind])) {
7893           /* Insert check for returning constrained indices */
7894           indices[dof-k-1] = -(off+k+1);
7895           ++cind;
7896         } else {
7897           indices[dof-k-1] = off+k-cind;
7898         }
7899       }
7900     }
7901   }
7902   PetscFunctionReturn(0);
7903 }
7904 
7905 #undef __FUNCT__
7906 #define __FUNCT__ "indicesPointFields_private"
7907 /* . off - The global offset of this point */
7908 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
7909   PetscInt       numFields, foff, f;
7910   PetscErrorCode ierr;
7911 
7912   PetscFunctionBegin;
7913   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7914   for (f = 0, foff = 0; f < numFields; ++f) {
7915     PetscInt        fdof, fcomp, cfdof;
7916     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7917     PetscInt        cind = 0, k, c;
7918 
7919     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7920     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7921     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
7922     if (!cfdof || setBC) {
7923       if (orientation >= 0) {
7924         for (k = 0; k < fdof; ++k) {
7925           indices[foffs[f]+k] = off+foff+k;
7926         }
7927       } else {
7928         for (k = fdof/fcomp-1; k >= 0; --k) {
7929           for (c = 0; c < fcomp; ++c) {
7930             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
7931           }
7932         }
7933       }
7934     } else {
7935       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7936       if (orientation >= 0) {
7937         for (k = 0; k < fdof; ++k) {
7938           if ((cind < cfdof) && (k == fcdofs[cind])) {
7939             indices[foffs[f]+k] = -(off+foff+k+1);
7940             ++cind;
7941           } else {
7942             indices[foffs[f]+k] = off+foff+k-cind;
7943           }
7944         }
7945       } else {
7946         for (k = fdof/fcomp-1; k >= 0; --k) {
7947           for (c = 0; c < fcomp; ++c) {
7948             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
7949               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
7950               ++cind;
7951             } else {
7952               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
7953             }
7954           }
7955         }
7956       }
7957     }
7958     foff     += fdof - cfdof;
7959     foffs[f] += fdof;
7960   }
7961   PetscFunctionReturn(0);
7962 }
7963 
7964 #undef __FUNCT__
7965 #define __FUNCT__ "DMPlexMatSetClosure"
7966 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
7967 {
7968   DM_Plex     *mesh   = (DM_Plex *) dm->data;
7969   PetscInt       *points = PETSC_NULL;
7970   PetscInt       *indices;
7971   PetscInt        offsets[32];
7972   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
7973   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
7974   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
7975   PetscErrorCode  ierr;
7976 
7977   PetscFunctionBegin;
7978   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7979   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
7980   if (useDefault) {
7981     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7982   }
7983   if (useGlobalDefault) {
7984     if (useDefault) {
7985       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
7986     } else {
7987       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7988     }
7989   }
7990   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7991   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7992   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7993   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7994   /* Compress out points not in the section */
7995   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7996   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7997     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7998       points[q*2]   = points[p];
7999       points[q*2+1] = points[p+1];
8000       ++q;
8001     }
8002   }
8003   numPoints = q;
8004   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8005     PetscInt fdof;
8006 
8007     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8008     for (f = 0; f < numFields; ++f) {
8009       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8010       offsets[f+1] += fdof;
8011     }
8012     numIndices += dof;
8013   }
8014   for (f = 1; f < numFields; ++f) {
8015     offsets[f+1] += offsets[f];
8016   }
8017   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8018   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8019   if (numFields) {
8020     for (p = 0; p < numPoints*2; p += 2) {
8021       PetscInt o = points[p+1];
8022       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8023       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8024     }
8025   } else {
8026     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8027       PetscInt o = points[p+1];
8028       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8029       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8030     }
8031   }
8032   if (useGlobalDefault && !useDefault) {
8033     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8034   }
8035   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8036   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8037   if (ierr) {
8038     PetscMPIInt    rank;
8039     PetscErrorCode ierr2;
8040 
8041     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8042     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8043     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8044     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8045     CHKERRQ(ierr);
8046   }
8047   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8048   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8049   PetscFunctionReturn(0);
8050 }
8051 
8052 #undef __FUNCT__
8053 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8054 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8055 {
8056   PetscSection       coordSection;
8057   Vec                coordinates;
8058   const PetscScalar *coords;
8059   const PetscInt     dim = 2;
8060   PetscInt           d, f;
8061   PetscErrorCode     ierr;
8062 
8063   PetscFunctionBegin;
8064   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8065   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8066   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8067   if (v0) {
8068     for (d = 0; d < dim; d++) {
8069       v0[d] = PetscRealPart(coords[d]);
8070     }
8071   }
8072   if (J) {
8073     for (d = 0; d < dim; d++) {
8074       for (f = 0; f < dim; f++) {
8075         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8076       }
8077     }
8078     *detJ = J[0]*J[3] - J[1]*J[2];
8079 #if 0
8080     if (detJ < 0.0) {
8081       const PetscReal xLength = mesh->periodicity[0];
8082 
8083       if (xLength != 0.0) {
8084         PetscReal v0x = coords[0*dim+0];
8085 
8086         if (v0x == 0.0) {
8087           v0x = v0[0] = xLength;
8088         }
8089         for (f = 0; f < dim; f++) {
8090           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8091 
8092           J[0*dim+f] = 0.5*(px - v0x);
8093         }
8094       }
8095       detJ = J[0]*J[3] - J[1]*J[2];
8096     }
8097 #endif
8098     PetscLogFlops(8.0 + 3.0);
8099   }
8100   if (invJ) {
8101     const PetscReal invDet = 1.0/(*detJ);
8102 
8103     invJ[0] =  invDet*J[3];
8104     invJ[1] = -invDet*J[1];
8105     invJ[2] = -invDet*J[2];
8106     invJ[3] =  invDet*J[0];
8107     PetscLogFlops(5.0);
8108   }
8109   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8110   PetscFunctionReturn(0);
8111 }
8112 
8113 #undef __FUNCT__
8114 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8115 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8116 {
8117   PetscSection       coordSection;
8118   Vec                coordinates;
8119   const PetscScalar *coords;
8120   const PetscInt     dim = 2;
8121   PetscInt           d, f;
8122   PetscErrorCode     ierr;
8123 
8124   PetscFunctionBegin;
8125   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8126   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8127   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8128   if (v0) {
8129     for (d = 0; d < dim; d++) {
8130       v0[d] = PetscRealPart(coords[d]);
8131     }
8132   }
8133   if (J) {
8134     for (d = 0; d < dim; d++) {
8135       for (f = 0; f < dim; f++) {
8136         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8137       }
8138     }
8139     *detJ = J[0]*J[3] - J[1]*J[2];
8140     PetscLogFlops(8.0 + 3.0);
8141   }
8142   if (invJ) {
8143     const PetscReal invDet = 1.0/(*detJ);
8144 
8145     invJ[0] =  invDet*J[3];
8146     invJ[1] = -invDet*J[1];
8147     invJ[2] = -invDet*J[2];
8148     invJ[3] =  invDet*J[0];
8149     PetscLogFlops(5.0);
8150   }
8151   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8152   PetscFunctionReturn(0);
8153 }
8154 
8155 #undef __FUNCT__
8156 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8157 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8158 {
8159   PetscSection       coordSection;
8160   Vec                coordinates;
8161   const PetscScalar *coords;
8162   const PetscInt     dim = 3;
8163   PetscInt           d, f;
8164   PetscErrorCode     ierr;
8165 
8166   PetscFunctionBegin;
8167   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8168   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8169   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8170   if (v0) {
8171     for (d = 0; d < dim; d++) {
8172       v0[d] = PetscRealPart(coords[d]);
8173     }
8174   }
8175   if (J) {
8176     for (d = 0; d < dim; d++) {
8177       for (f = 0; f < dim; f++) {
8178         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8179       }
8180     }
8181     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8182     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8183              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8184              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8185     PetscLogFlops(18.0 + 12.0);
8186   }
8187   if (invJ) {
8188     const PetscReal invDet = -1.0/(*detJ);
8189 
8190     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8191     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8192     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8193     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8194     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8195     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8196     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8197     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8198     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8199     PetscLogFlops(37.0);
8200   }
8201   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8202   PetscFunctionReturn(0);
8203 }
8204 
8205 #undef __FUNCT__
8206 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8207 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8208 {
8209   PetscSection       coordSection;
8210   Vec                coordinates;
8211   const PetscScalar *coords;
8212   const PetscInt     dim = 3;
8213   PetscInt           d;
8214   PetscErrorCode     ierr;
8215 
8216   PetscFunctionBegin;
8217   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8218   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8219   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8220   if (v0) {
8221     for (d = 0; d < dim; d++) {
8222       v0[d] = PetscRealPart(coords[d]);
8223     }
8224   }
8225   if (J) {
8226     for (d = 0; d < dim; d++) {
8227       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8228       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8229       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8230     }
8231     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8232              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8233              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8234     PetscLogFlops(18.0 + 12.0);
8235   }
8236   if (invJ) {
8237     const PetscReal invDet = -1.0/(*detJ);
8238 
8239     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8240     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8241     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8242     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8243     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8244     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8245     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8246     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8247     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8248     PetscLogFlops(37.0);
8249   }
8250   *detJ *= 8.0;
8251   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8252   PetscFunctionReturn(0);
8253 }
8254 
8255 #undef __FUNCT__
8256 #define __FUNCT__ "DMPlexComputeCellGeometry"
8257 /*@C
8258   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8259 
8260   Collective on DM
8261 
8262   Input Arguments:
8263 + dm   - the DM
8264 - cell - the cell
8265 
8266   Output Arguments:
8267 + v0   - the translation part of this affine transform
8268 . J    - the Jacobian of the transform to the reference element
8269 . invJ - the inverse of the Jacobian
8270 - detJ - the Jacobian determinant
8271 
8272   Level: advanced
8273 
8274 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8275 @*/
8276 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ) {
8277   PetscInt       dim, maxConeSize;
8278   PetscErrorCode ierr;
8279 
8280   PetscFunctionBegin;
8281   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8282   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
8283   switch(dim) {
8284   case 2:
8285     switch(maxConeSize) {
8286     case 3:
8287       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8288       break;
8289     case 4:
8290       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8291       break;
8292     default:
8293       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of cell vertices %D for element geometry computation", maxConeSize);
8294     }
8295     break;
8296   case 3:
8297     switch(maxConeSize) {
8298     case 4:
8299       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8300       break;
8301     case 8:
8302       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8303       break;
8304     default:
8305       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of cell vertices %D for element geometry computation", maxConeSize);
8306     }
8307     break;
8308   default:
8309     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8310   }
8311   PetscFunctionReturn(0);
8312 }
8313 
8314 #undef __FUNCT__
8315 #define __FUNCT__ "DMPlexGetFaceOrientation"
8316 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented) {
8317   MPI_Comm       comm      = ((PetscObject) dm)->comm;
8318   PetscBool      posOrient = PETSC_FALSE;
8319   const PetscInt debug     = 0;
8320   PetscInt       cellDim, faceSize, f;
8321   PetscErrorCode ierr;
8322 
8323   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
8324   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
8325 
8326   if (cellDim == numCorners-1) {
8327     /* Simplices */
8328     faceSize  = numCorners-1;
8329     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
8330   } else if (cellDim == 1 && numCorners == 3) {
8331     /* Quadratic line */
8332     faceSize  = 1;
8333     posOrient = PETSC_TRUE;
8334   } else if (cellDim == 2 && numCorners == 4) {
8335     /* Quads */
8336     faceSize  = 2;
8337     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
8338       posOrient = PETSC_TRUE;
8339     } else if ((indices[0] == 3) && (indices[1] == 0)) {
8340       posOrient = PETSC_TRUE;
8341     } else {
8342       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
8343         posOrient = PETSC_FALSE;
8344       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
8345     }
8346   } else if (cellDim == 2 && numCorners == 6) {
8347     /* Quadratic triangle (I hate this) */
8348     /* Edges are determined by the first 2 vertices (corners of edges) */
8349     const PetscInt faceSizeTri = 3;
8350     PetscInt  sortedIndices[3], i, iFace;
8351     PetscBool found = PETSC_FALSE;
8352     PetscInt  faceVerticesTriSorted[9] = {
8353       0, 3,  4, /* bottom */
8354       1, 4,  5, /* right */
8355       2, 3,  5, /* left */
8356     };
8357     PetscInt  faceVerticesTri[9] = {
8358       0, 3,  4, /* bottom */
8359       1, 4,  5, /* right */
8360       2, 5,  3, /* left */
8361     };
8362 
8363     faceSize = faceSizeTri;
8364     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
8365     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
8366     for (iFace = 0; iFace < 3; ++iFace) {
8367       const PetscInt ii = iFace*faceSizeTri;
8368       PetscInt       fVertex, cVertex;
8369 
8370       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
8371           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
8372         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
8373           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
8374             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
8375               faceVertices[fVertex] = origVertices[cVertex];
8376               break;
8377             }
8378           }
8379         }
8380         found = PETSC_TRUE;
8381         break;
8382       }
8383     }
8384     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
8385     if (posOriented) {*posOriented = PETSC_TRUE;}
8386     PetscFunctionReturn(0);
8387   } else if (cellDim == 2 && numCorners == 9) {
8388     /* Quadratic quad (I hate this) */
8389     /* Edges are determined by the first 2 vertices (corners of edges) */
8390     const PetscInt faceSizeQuad = 3;
8391     PetscInt  sortedIndices[3], i, iFace;
8392     PetscBool found = PETSC_FALSE;
8393     PetscInt  faceVerticesQuadSorted[12] = {
8394       0, 1,  4, /* bottom */
8395       1, 2,  5, /* right */
8396       2, 3,  6, /* top */
8397       0, 3,  7, /* left */
8398     };
8399     PetscInt  faceVerticesQuad[12] = {
8400       0, 1,  4, /* bottom */
8401       1, 2,  5, /* right */
8402       2, 3,  6, /* top */
8403       3, 0,  7, /* left */
8404     };
8405 
8406     faceSize = faceSizeQuad;
8407     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
8408     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
8409     for (iFace = 0; iFace < 4; ++iFace) {
8410       const PetscInt ii = iFace*faceSizeQuad;
8411       PetscInt       fVertex, cVertex;
8412 
8413       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
8414           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
8415         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
8416           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
8417             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
8418               faceVertices[fVertex] = origVertices[cVertex];
8419               break;
8420             }
8421           }
8422         }
8423         found = PETSC_TRUE;
8424         break;
8425       }
8426     }
8427     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
8428     if (posOriented) {*posOriented = PETSC_TRUE;}
8429     PetscFunctionReturn(0);
8430   } else if (cellDim == 3 && numCorners == 8) {
8431     /* Hexes
8432        A hex is two oriented quads with the normal of the first
8433        pointing up at the second.
8434 
8435           7---6
8436          /|  /|
8437         4---5 |
8438         | 3-|-2
8439         |/  |/
8440         0---1
8441 
8442         Faces are determined by the first 4 vertices (corners of faces) */
8443     const PetscInt faceSizeHex = 4;
8444     PetscInt  sortedIndices[4], i, iFace;
8445     PetscBool found = PETSC_FALSE;
8446     PetscInt faceVerticesHexSorted[24] = {
8447       0, 1, 2, 3,  /* bottom */
8448       4, 5, 6, 7,  /* top */
8449       0, 1, 4, 5,  /* front */
8450       1, 2, 5, 6,  /* right */
8451       2, 3, 6, 7,  /* back */
8452       0, 3, 4, 7,  /* left */
8453     };
8454     PetscInt faceVerticesHex[24] = {
8455       3, 2, 1, 0,  /* bottom */
8456       4, 5, 6, 7,  /* top */
8457       0, 1, 5, 4,  /* front */
8458       1, 2, 6, 5,  /* right */
8459       2, 3, 7, 6,  /* back */
8460       3, 0, 4, 7,  /* left */
8461     };
8462 
8463     faceSize = faceSizeHex;
8464     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
8465     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
8466     for (iFace = 0; iFace < 6; ++iFace) {
8467       const PetscInt ii = iFace*faceSizeHex;
8468       PetscInt       fVertex, cVertex;
8469 
8470       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
8471           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
8472           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
8473           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
8474         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
8475           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
8476             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
8477               faceVertices[fVertex] = origVertices[cVertex];
8478               break;
8479             }
8480           }
8481         }
8482         found = PETSC_TRUE;
8483         break;
8484       }
8485     }
8486     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
8487     if (posOriented) {*posOriented = PETSC_TRUE;}
8488     PetscFunctionReturn(0);
8489   } else if (cellDim == 3 && numCorners == 10) {
8490     /* Quadratic tet */
8491     /* Faces are determined by the first 3 vertices (corners of faces) */
8492     const PetscInt faceSizeTet = 6;
8493     PetscInt  sortedIndices[6], i, iFace;
8494     PetscBool found = PETSC_FALSE;
8495     PetscInt faceVerticesTetSorted[24] = {
8496       0, 1, 2,  6, 7, 8, /* bottom */
8497       0, 3, 4,  6, 7, 9,  /* front */
8498       1, 4, 5,  7, 8, 9,  /* right */
8499       2, 3, 5,  6, 8, 9,  /* left */
8500     };
8501     PetscInt faceVerticesTet[24] = {
8502       0, 1, 2,  6, 7, 8, /* bottom */
8503       0, 4, 3,  6, 7, 9,  /* front */
8504       1, 5, 4,  7, 8, 9,  /* right */
8505       2, 3, 5,  8, 6, 9,  /* left */
8506     };
8507 
8508     faceSize = faceSizeTet;
8509     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
8510     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
8511     for (iFace=0; iFace < 4; ++iFace) {
8512       const PetscInt ii = iFace*faceSizeTet;
8513       PetscInt       fVertex, cVertex;
8514 
8515       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
8516           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
8517           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
8518           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
8519         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
8520           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
8521             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
8522               faceVertices[fVertex] = origVertices[cVertex];
8523               break;
8524             }
8525           }
8526         }
8527         found = PETSC_TRUE;
8528         break;
8529       }
8530     }
8531     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
8532     if (posOriented) {*posOriented = PETSC_TRUE;}
8533     PetscFunctionReturn(0);
8534   } else if (cellDim == 3 && numCorners == 27) {
8535     /* Quadratic hexes (I hate this)
8536        A hex is two oriented quads with the normal of the first
8537        pointing up at the second.
8538 
8539          7---6
8540         /|  /|
8541        4---5 |
8542        | 3-|-2
8543        |/  |/
8544        0---1
8545 
8546        Faces are determined by the first 4 vertices (corners of faces) */
8547     const PetscInt faceSizeQuadHex = 9;
8548     PetscInt  sortedIndices[9], i, iFace;
8549     PetscBool found = PETSC_FALSE;
8550     PetscInt faceVerticesQuadHexSorted[54] = {
8551       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
8552       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
8553       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
8554       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
8555       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
8556       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
8557     };
8558     PetscInt faceVerticesQuadHex[54] = {
8559       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
8560       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
8561       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
8562       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
8563       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
8564       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
8565     };
8566 
8567     faceSize = faceSizeQuadHex;
8568     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
8569     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
8570     for (iFace = 0; iFace < 6; ++iFace) {
8571       const PetscInt ii = iFace*faceSizeQuadHex;
8572       PetscInt       fVertex, cVertex;
8573 
8574       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
8575           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
8576           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
8577           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
8578         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
8579           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
8580             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
8581               faceVertices[fVertex] = origVertices[cVertex];
8582               break;
8583             }
8584           }
8585         }
8586         found = PETSC_TRUE;
8587         break;
8588       }
8589     }
8590     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
8591     if (posOriented) {*posOriented = PETSC_TRUE;}
8592     PetscFunctionReturn(0);
8593   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
8594   if (!posOrient) {
8595     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
8596     for (f = 0; f < faceSize; ++f) {
8597       faceVertices[f] = origVertices[faceSize-1 - f];
8598     }
8599   } else {
8600     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
8601     for (f = 0; f < faceSize; ++f) {
8602       faceVertices[f] = origVertices[f];
8603     }
8604   }
8605   if (posOriented) {*posOriented = posOrient;}
8606   PetscFunctionReturn(0);
8607 }
8608 
8609 #undef __FUNCT__
8610 #define __FUNCT__ "DMPlexGetOrientedFace"
8611 /*
8612     Given a cell and a face, as a set of vertices,
8613       return the oriented face, as a set of vertices, in faceVertices
8614     The orientation is such that the face normal points out of the cell
8615 */
8616 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
8617 {
8618   const PetscInt *cone = PETSC_NULL;
8619   PetscInt        coneSize, v, f, v2;
8620   PetscInt        oppositeVertex = -1;
8621   PetscErrorCode  ierr;
8622 
8623   PetscFunctionBegin;
8624   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8625   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
8626   for (v = 0, v2 = 0; v < coneSize; ++v) {
8627     PetscBool found  = PETSC_FALSE;
8628 
8629     for (f = 0; f < faceSize; ++f) {
8630       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
8631     }
8632     if (found) {
8633       indices[v2]      = v;
8634       origVertices[v2] = cone[v];
8635       ++v2;
8636     } else {
8637       oppositeVertex = v;
8638     }
8639   }
8640   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
8641   PetscFunctionReturn(0);
8642 }
8643 
8644 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8645 {
8646   switch(i) {
8647   case 0:
8648     switch(j) {
8649     case 0: return 0;
8650     case 1:
8651       switch(k) {
8652       case 0: return 0;
8653       case 1: return 0;
8654       case 2: return 1;
8655       }
8656     case 2:
8657       switch(k) {
8658       case 0: return 0;
8659       case 1: return -1;
8660       case 2: return 0;
8661       }
8662     }
8663   case 1:
8664     switch(j) {
8665     case 0:
8666       switch(k) {
8667       case 0: return 0;
8668       case 1: return 0;
8669       case 2: return -1;
8670       }
8671     case 1: return 0;
8672     case 2:
8673       switch(k) {
8674       case 0: return 1;
8675       case 1: return 0;
8676       case 2: return 0;
8677       }
8678     }
8679   case 2:
8680     switch(j) {
8681     case 0:
8682       switch(k) {
8683       case 0: return 0;
8684       case 1: return 1;
8685       case 2: return 0;
8686       }
8687     case 1:
8688       switch(k) {
8689       case 0: return -1;
8690       case 1: return 0;
8691       case 2: return 0;
8692       }
8693     case 2: return 0;
8694     }
8695   }
8696   return 0;
8697 }
8698 
8699 #undef __FUNCT__
8700 #define __FUNCT__ "DMPlexCreateRigidBody"
8701 /*@C
8702   DMPlexCreateRigidBody - create rigid body modes from coordinates
8703 
8704   Collective on DM
8705 
8706   Input Arguments:
8707 + dm - the DM
8708 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
8709 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
8710 
8711   Output Argument:
8712 . sp - the null space
8713 
8714   Note: This is necessary to take account of Dirichlet conditions on the displacements
8715 
8716   Level: advanced
8717 
8718 .seealso: MatNullSpaceCreate()
8719 @*/
8720 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8721 {
8722   MPI_Comm       comm = ((PetscObject) dm)->comm;
8723   Vec            coordinates, localMode, mode[6];
8724   PetscSection   coordSection;
8725   PetscScalar   *coords;
8726   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8727   PetscErrorCode ierr;
8728 
8729   PetscFunctionBegin;
8730   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8731   if (dim == 1) {
8732     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
8733     PetscFunctionReturn(0);
8734   }
8735   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8736   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8737   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8738   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8739   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8740   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8741   m    = (dim*(dim+1))/2;
8742   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8743   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8744   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8745   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8746   /* Assume P1 */
8747   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8748   for (d = 0; d < dim; ++d) {
8749     PetscScalar values[3] = {0.0, 0.0, 0.0};
8750 
8751     values[d] = 1.0;
8752     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8753     for (v = vStart; v < vEnd; ++v) {
8754       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8755     }
8756     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8757     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8758   }
8759   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8760   for (d = dim; d < dim*(dim+1)/2; ++d) {
8761     PetscInt i, j, k = dim > 2 ? d - dim : d;
8762 
8763     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8764     for (v = vStart; v < vEnd; ++v) {
8765       PetscScalar values[3] = {0.0, 0.0, 0.0};
8766       PetscInt    off;
8767 
8768       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8769       for (i = 0; i < dim; ++i) {
8770         for (j = 0; j < dim; ++j) {
8771           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8772         }
8773       }
8774       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8775     }
8776     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8777     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8778   }
8779   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8780   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8781   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
8782   /* Orthonormalize system */
8783   for (i = dim; i < m; ++i) {
8784     PetscScalar dots[6];
8785 
8786     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8787     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8788     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8789     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
8790   }
8791   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
8792   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
8793   PetscFunctionReturn(0);
8794 }
8795 
8796 #undef __FUNCT__
8797 #define __FUNCT__ "DMPlexGetVTKBounds"
8798 PetscErrorCode DMPlexGetVTKBounds(DM dm, PetscInt *cMax, PetscInt *vMax)
8799 {
8800   DM_Plex *mesh = (DM_Plex *) dm->data;
8801 
8802   PetscFunctionBegin;
8803   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8804   if (cMax) *cMax = mesh->vtkCellMax;
8805   if (vMax) *vMax = mesh->vtkVertexMax;
8806   PetscFunctionReturn(0);
8807 }
8808 
8809 #undef __FUNCT__
8810 #define __FUNCT__ "DMPlexSetVTKBounds"
8811 PetscErrorCode DMPlexSetVTKBounds(DM dm, PetscInt cMax, PetscInt vMax)
8812 {
8813   DM_Plex *mesh = (DM_Plex *) dm->data;
8814 
8815   PetscFunctionBegin;
8816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8817   if (cMax >= 0) mesh->vtkCellMax   = cMax;
8818   if (vMax >= 0) mesh->vtkVertexMax = vMax;
8819   PetscFunctionReturn(0);
8820 }
8821 
8822 #undef __FUNCT__
8823 #define __FUNCT__ "DMPlexGetVTKCellHeight"
8824 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8825 {
8826   DM_Plex *mesh = (DM_Plex *) dm->data;
8827 
8828   PetscFunctionBegin;
8829   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8830   PetscValidPointer(cellHeight, 2);
8831   *cellHeight = mesh->vtkCellHeight;
8832   PetscFunctionReturn(0);
8833 }
8834 
8835 #undef __FUNCT__
8836 #define __FUNCT__ "DMPlexSetVTKCellHeight"
8837 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8838 {
8839   DM_Plex *mesh = (DM_Plex *) dm->data;
8840 
8841   PetscFunctionBegin;
8842   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8843   mesh->vtkCellHeight = cellHeight;
8844   PetscFunctionReturn(0);
8845 }
8846 
8847 #undef __FUNCT__
8848 #define __FUNCT__ "DMPlexInsertFace_Private"
8849 /*
8850   DMPlexInsertFace_Private - Puts a face into the mesh
8851 
8852   Not collective
8853 
8854   Input Parameters:
8855   + dm              - The DMPlex
8856   . numFaceVertex   - The number of vertices in the face
8857   . faceVertices    - The vertices in the face for dm
8858   . subfaceVertices - The vertices in the face for subdm
8859   . numCorners      - The number of vertices in the cell
8860   . cell            - A cell in dm containing the face
8861   . subcell         - A cell in subdm containing the face
8862   . firstFace       - First face in the mesh
8863   - newFacePoint    - Next face in the mesh
8864 
8865   Output Parameters:
8866   . newFacePoint - Contains next face point number on input, updated on output
8867 
8868   Level: developer
8869 */
8870 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)
8871 {
8872   MPI_Comm        comm    = ((PetscObject) dm)->comm;
8873   DM_Plex     *submesh = (DM_Plex *) subdm->data;
8874   const PetscInt *faces;
8875   PetscInt        numFaces, coneSize;
8876   PetscErrorCode  ierr;
8877 
8878   PetscFunctionBegin;
8879   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
8880   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
8881 #if 0
8882   /* Cannot use this because support() has not been constructed yet */
8883   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
8884 #else
8885   {
8886     PetscInt f;
8887 
8888     numFaces = 0;
8889     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
8890     for(f = firstFace; f < *newFacePoint; ++f) {
8891       PetscInt dof, off, d;
8892 
8893       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
8894       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
8895       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
8896       for(d = 0; d < dof; ++d) {
8897         const PetscInt p = submesh->cones[off+d];
8898         PetscInt       v;
8899 
8900         for(v = 0; v < numFaceVertices; ++v) {
8901           if (subfaceVertices[v] == p) break;
8902         }
8903         if (v == numFaceVertices) break;
8904       }
8905       if (d == dof) {
8906         numFaces = 1;
8907         ((PetscInt *) faces)[0] = f;
8908       }
8909     }
8910   }
8911 #endif
8912   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
8913   else if (numFaces == 1) {
8914     /* Add the other cell neighbor for this face */
8915     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
8916   } else {
8917     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
8918     PetscBool posOriented;
8919 
8920     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
8921     origVertices = &orientedVertices[numFaceVertices];
8922     indices      = &orientedVertices[numFaceVertices*2];
8923     orientedSubVertices = &orientedVertices[numFaceVertices*3];
8924     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
8925     /* TODO: I know that routine should return a permutation, not the indices */
8926     for(v = 0; v < numFaceVertices; ++v) {
8927       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
8928       for(ov = 0; ov < numFaceVertices; ++ov) {
8929         if (orientedVertices[ov] == vertex) {
8930           orientedSubVertices[ov] = subvertex;
8931           break;
8932         }
8933       }
8934       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
8935     }
8936     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
8937     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
8938     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
8939     ++(*newFacePoint);
8940   }
8941   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
8942   PetscFunctionReturn(0);
8943 }
8944 
8945 #undef __FUNCT__
8946 #define __FUNCT__ "DMPlexCreateSubmesh"
8947 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
8948 {
8949   MPI_Comm        comm = ((PetscObject) dm)->comm;
8950   DM_Plex     *submesh;
8951   PetscBool       boundaryFaces = PETSC_FALSE;
8952   PetscSection    coordSection, subCoordSection;
8953   Vec             coordinates, subCoordinates;
8954   PetscScalar    *coords, *subCoords;
8955   IS              labelIS;
8956   const PetscInt *subVertices;
8957   PetscInt       *subVerticesActive, *tmpPoints;
8958   PetscInt       *subCells = PETSC_NULL;
8959   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
8960   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
8961   PetscInt        dim; /* Right now, do not specify dimension */
8962   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
8963   PetscErrorCode  ierr;
8964 
8965   PetscFunctionBegin;
8966   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8967   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8968   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8969   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
8970   ierr = DMPlexGetVTKBounds(dm, &cMax, &vMax);CHKERRQ(ierr);
8971   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8972   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
8973   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
8974   subface = &face[maxConeSize];
8975   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
8976   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
8977   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
8978   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
8979   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
8980   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
8981   maxSubCells = numSubVertices;
8982   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
8983   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
8984   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
8985   for(v = 0; v < numSubVertices; ++v) {
8986     const PetscInt vertex = subVertices[v];
8987     PetscInt *star = PETSC_NULL;
8988     PetscInt  starSize, numCells = 0;
8989 
8990     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
8991     for(p = 0; p < starSize*2; p += 2) {
8992       const PetscInt point = star[p];
8993       if ((point >= cStart) && (point < cEnd)) {
8994         star[numCells++] = point;
8995       }
8996     }
8997     numOldSubCells = numSubCells;
8998     for(c = 0; c < numCells; ++c) {
8999       const PetscInt cell    = star[c];
9000       PetscInt      *closure = PETSC_NULL;
9001       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9002       PetscInt       cellLoc;
9003 
9004       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9005       if (cellLoc >= 0) continue;
9006       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9007       for(p = 0; p < closureSize*2; p += 2) {
9008         const PetscInt point = closure[p];
9009         if ((point >= vStart) && (point < vEnd)) {
9010           closure[numCorners++] = point;
9011         }
9012       }
9013       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9014       for(corner = 0; corner < numCorners; ++corner) {
9015         const PetscInt cellVertex = closure[corner];
9016         PetscInt       subVertex;
9017 
9018         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9019         if (subVertex >= 0) { /* contains submesh vertex */
9020           for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9021           if (i == faceSize) {
9022             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9023             face[faceSize]    = cellVertex;
9024             subface[faceSize] = subVertex;
9025             ++faceSize;
9026           }
9027         }
9028       }
9029       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9030       if (faceSize >= nFV) {
9031         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9032         if (numSubCells >= maxSubCells) {
9033           PetscInt *tmpCells;
9034           maxSubCells *= 2;
9035           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9036           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9037           ierr = PetscFree(subCells);CHKERRQ(ierr);
9038           subCells = tmpCells;
9039         }
9040         /* TOOD: Maybe overestimate then squeeze out empty faces */
9041         if (faceSize > nFV) {
9042           /* TODO: This is tricky. Maybe just add all faces */
9043           numSubFaces++;
9044         } else {
9045           numSubFaces++;
9046         }
9047         for(f = 0; f < faceSize; ++f) {
9048           subVerticesActive[subface[f]] = 1;
9049         }
9050         subCells[numSubCells++] = cell;
9051       }
9052     }
9053     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9054     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9055   }
9056   /* Pick out active subvertices */
9057   for(v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9058     if (subVerticesActive[v]) {
9059       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9060     }
9061   }
9062   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9063   /* Set cone sizes */
9064   firstSubVertex = numSubCells;
9065   firstSubFace   = numSubCells+numSubVerticesActive;
9066   newFacePoint   = firstSubFace;
9067   for(c = 0; c < numSubCells; ++c) {
9068     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
9069   }
9070   for(f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9071     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
9072   }
9073   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
9074   /* Create face cones */
9075   for(c = 0; c < numSubCells; ++c) {
9076     const PetscInt cell    = subCells[c];
9077     PetscInt      *closure = PETSC_NULL;
9078     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9079 
9080     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9081     for(p = 0; p < closureSize*2; p += 2) {
9082       const PetscInt point = closure[p];
9083       if ((point >= vStart) && (point < vEnd)) {
9084         closure[numCorners++] = point;
9085       }
9086     }
9087     for(corner = 0; corner < numCorners; ++corner) {
9088       const PetscInt cellVertex = closure[corner];
9089       PetscInt       subVertex;
9090 
9091       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9092       if (subVertex >= 0) { /* contains submesh vertex */
9093         for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9094         if (i == faceSize) {
9095           face[faceSize]    = cellVertex;
9096           subface[faceSize] = numSubCells+subVertex;
9097           ++faceSize;
9098         }
9099       }
9100     }
9101     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9102     if (faceSize >= nFV) {
9103       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9104       // Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron)
9105       //   We have to take all the faces, and discard those in the interior
9106       //   We check the join of the face vertices, which produces 2 cells if in the interior
9107 #if 0
9108       // This object just calls insert on each face that comes from subsets()
9109       // In fact, we can just always acll subsets(), since when we pass a single face it is a single call
9110       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9111       PointArray                          faceVec(face->begin(), face->end());
9112 
9113       subsets(faceVec, nFV, inserter);
9114 #endif
9115       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
9116     }
9117   }
9118   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
9119   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
9120   /* Build coordinates */
9121   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9122   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9123   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
9124   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
9125   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
9126     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
9127   }
9128   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
9129   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
9130   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
9131   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
9132   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
9133   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
9134   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9135   for(v = 0; v < numSubVerticesActive; ++v) {
9136     const PetscInt vertex    = subVerticesActive[v];
9137     const PetscInt subVertex = firstSubVertex+v;
9138     PetscInt dof, off, sdof, soff;
9139 
9140     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
9141     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
9142     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
9143     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
9144     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
9145     for(d = 0; d < dof; ++d) {
9146       subCoords[soff+d] = coords[off+d];
9147     }
9148   }
9149   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
9150   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9151   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
9152   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
9153 
9154   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
9155   /* Create map from submesh points to original mesh points */
9156   submesh = (DM_Plex *) (*subdm)->data;
9157   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
9158   for(c = 0; c < numSubCells; ++c) {
9159     tmpPoints[c] = subCells[c];
9160   }
9161   for(v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
9162     tmpPoints[v] = subVerticesActive[v-numSubCells];
9163   }
9164   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
9165 
9166   ierr = PetscFree(subCells);CHKERRQ(ierr);
9167   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
9168   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
9169   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
9170   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9171   PetscFunctionReturn(0);
9172 }
9173 
9174 #undef __FUNCT__
9175 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9176 /* We can easily have a form that takes an IS instead */
9177 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9178 {
9179   PetscSection   section, globalSection;
9180   PetscInt      *numbers, p;
9181   PetscErrorCode ierr;
9182 
9183   PetscFunctionBegin;
9184   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
9185   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9186   for(p = pStart; p < pEnd; ++p) {
9187     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9188   }
9189   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9190   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9191   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9192   for(p = pStart; p < pEnd; ++p) {
9193     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9194   }
9195   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9196   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9197   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9198   PetscFunctionReturn(0);
9199 }
9200 
9201 #undef __FUNCT__
9202 #define __FUNCT__ "DMPlexGetCellNumbering"
9203 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9204 {
9205   DM_Plex    *mesh = (DM_Plex *) dm->data;
9206   PetscInt       cellHeight, cStart, cEnd, cMax;
9207   PetscErrorCode ierr;
9208 
9209   PetscFunctionBegin;
9210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9211   if (!mesh->globalCellNumbers) {
9212     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9213     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9214     ierr = DMPlexGetVTKBounds(dm, &cMax, PETSC_NULL);CHKERRQ(ierr);
9215     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9216     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9217   }
9218   *globalCellNumbers = mesh->globalCellNumbers;
9219   PetscFunctionReturn(0);
9220 }
9221 
9222 #undef __FUNCT__
9223 #define __FUNCT__ "DMPlexGetVertexNumbering"
9224 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9225 {
9226   DM_Plex    *mesh = (DM_Plex *) dm->data;
9227   PetscInt       vStart, vEnd, vMax;
9228   PetscErrorCode ierr;
9229 
9230   PetscFunctionBegin;
9231   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9232   if (!mesh->globalVertexNumbers) {
9233     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9234     ierr = DMPlexGetVTKBounds(dm, PETSC_NULL, &vMax);CHKERRQ(ierr);
9235     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9236     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9237   }
9238   *globalVertexNumbers = mesh->globalVertexNumbers;
9239   PetscFunctionReturn(0);
9240 }
9241 
9242 #undef __FUNCT__
9243 #define __FUNCT__ "DMPlexGetSubpointMap"
9244 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
9245 {
9246   DM_Plex *mesh = (DM_Plex *) dm->data;
9247 
9248   PetscFunctionBegin;
9249   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9250   PetscValidPointer(subpointMap, 2);
9251   *subpointMap = mesh->subpointMap;
9252   PetscFunctionReturn(0);
9253 }
9254 
9255 #undef __FUNCT__
9256 #define __FUNCT__ "DMPlexSetSubpointMap"
9257 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
9258 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
9259 {
9260   DM_Plex *mesh = (DM_Plex *) dm->data;
9261 
9262   PetscFunctionBegin;
9263   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9264   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
9265   mesh->subpointMap = subpointMap;
9266   PetscFunctionReturn(0);
9267 }
9268 
9269 #undef __FUNCT__
9270 #define __FUNCT__ "DMPlexGetScale"
9271 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9272 {
9273   DM_Plex *mesh = (DM_Plex *) dm->data;
9274 
9275   PetscFunctionBegin;
9276   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9277   PetscValidPointer(scale, 3);
9278   *scale = mesh->scale[unit];
9279   PetscFunctionReturn(0);
9280 }
9281 
9282 #undef __FUNCT__
9283 #define __FUNCT__ "DMPlexSetScale"
9284 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9285 {
9286   DM_Plex *mesh = (DM_Plex *) dm->data;
9287 
9288   PetscFunctionBegin;
9289   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9290   mesh->scale[unit] = scale;
9291   PetscFunctionReturn(0);
9292 }
9293 
9294 
9295 /*******************************************************************************
9296 This should be in a separate Discretization object, but I am not sure how to lay
9297 it out yet, so I am stuffing things here while I experiment.
9298 *******************************************************************************/
9299 #undef __FUNCT__
9300 #define __FUNCT__ "DMPlexSetFEMIntegration"
9301 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9302                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9303                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9304                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9305                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9306                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9307                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9308                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9309                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9310                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9311                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9312                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9313                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9314                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9315                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9316                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9317                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9318 {
9319   DM_Plex *mesh = (DM_Plex *) dm->data;
9320 
9321   PetscFunctionBegin;
9322   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9323   mesh->integrateResidualFEM       = integrateResidualFEM;
9324   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9325   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9326   PetscFunctionReturn(0);
9327 }
9328 
9329 #undef __FUNCT__
9330 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9331 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9332 {
9333   Vec            coordinates;
9334   PetscSection   section, cSection;
9335   PetscInt       dim, vStart, vEnd, v, c, d;
9336   PetscScalar   *values, *cArray;
9337   PetscReal     *coords;
9338   PetscErrorCode ierr;
9339 
9340   PetscFunctionBegin;
9341   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9342   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9343   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9344   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9345   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9346   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9347   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9348   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9349   for (v = vStart; v < vEnd; ++v) {
9350     PetscInt dof, off;
9351 
9352     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9353     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9354     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9355     for(d = 0; d < dof; ++d) {
9356       coords[d] = PetscRealPart(cArray[off+d]);
9357     }
9358     for(c = 0; c < numComp; ++c) {
9359       values[c] = (*funcs[c])(coords);
9360     }
9361     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9362   }
9363   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9364   /* Temporary, must be replaced by a projection on the finite element basis */
9365   {
9366     PetscInt eStart = 0, eEnd = 0, e, depth;
9367 
9368     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9369     --depth;
9370     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9371     for (e = eStart; e < eEnd; ++e) {
9372       const PetscInt *cone = PETSC_NULL;
9373       PetscInt        coneSize, d;
9374       PetscScalar    *coordsA, *coordsB;
9375 
9376       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9377       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9378       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9379       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9380       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9381       for (d = 0; d < dim; ++d) {
9382         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9383       }
9384       for (c = 0; c < numComp; ++c) {
9385         values[c] = (*funcs[c])(coords);
9386       }
9387       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9388     }
9389   }
9390 
9391   ierr = PetscFree(coords);CHKERRQ(ierr);
9392   ierr = PetscFree(values);CHKERRQ(ierr);
9393 #if 0
9394   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9395   PetscReal      detJ;
9396 
9397   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9398   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9399   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV((int) pow(this->_mesh->getSieve()->getMaxConeSize(), dim+1)+1, true);
9400 
9401   for (PetscInt c = cStart; c < cEnd; ++c) {
9402     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9403     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9404     const int                          oSize   = pV.getSize();
9405     int                                v       = 0;
9406 
9407     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
9408     for (PetscInt cl = 0; cl < oSize; ++cl) {
9409       const PetscInt fDim;
9410 
9411       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9412       if (pointDim) {
9413         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9414           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9415         }
9416       }
9417     }
9418     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
9419     pV.clear();
9420   }
9421   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9422   ierr = PetscFree(values);CHKERRQ(ierr);
9423 #endif
9424   PetscFunctionReturn(0);
9425 }
9426 
9427 #undef __FUNCT__
9428 #define __FUNCT__ "DMPlexProjectFunction"
9429 /*@C
9430   DMPlexProjectFunction - This projects the given function into the function space provided.
9431 
9432   Input Parameters:
9433 + dm      - The DM
9434 . numComp - The number of components (functions)
9435 . funcs   - The coordinate functions to evaluate
9436 - mode    - The insertion mode for values
9437 
9438   Output Parameter:
9439 . X - vector
9440 
9441   Level: developer
9442 
9443   Note:
9444   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9445   We will eventually fix it.
9446 
9447 ,seealso: DMPlexComputeL2Diff()
9448 */
9449 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9450 {
9451   Vec            localX;
9452   PetscErrorCode ierr;
9453 
9454   PetscFunctionBegin;
9455   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9456   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9457   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9458   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9459   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9460   PetscFunctionReturn(0);
9461 }
9462 
9463 #undef __FUNCT__
9464 #define __FUNCT__ "DMPlexComputeL2Diff"
9465 /*@C
9466   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9467 
9468   Input Parameters:
9469 + dm    - The DM
9470 . quad  - The PetscQuadrature object for each field
9471 . funcs - The functions to evaluate for each field component
9472 - X     - The coefficient vector u_h
9473 
9474   Output Parameter:
9475 . diff - The diff ||u - u_h||_2
9476 
9477   Level: developer
9478 
9479 .seealso: DMPlexProjectFunction()
9480 */
9481 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff) {
9482   const PetscInt   debug = 0;
9483   PetscSection     section;
9484   Vec              localX;
9485   PetscReal       *coords, *v0, *J, *invJ, detJ;
9486   PetscReal        localDiff = 0.0;
9487   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9488   PetscErrorCode   ierr;
9489 
9490   PetscFunctionBegin;
9491   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9492   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9493   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9494   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9495   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9496   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9497   for (field = 0; field < numFields; ++field) {
9498     numComponents += quad[field].numComponents;
9499   }
9500   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9501   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9502   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9503   for (c = cStart; c < cEnd; ++c) {
9504     const PetscScalar *x;
9505     PetscReal          elemDiff = 0.0;
9506 
9507     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9508     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9509     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
9510 
9511     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9512       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9513       const PetscReal *quadPoints    = quad[field].quadPoints;
9514       const PetscReal *quadWeights   = quad[field].quadWeights;
9515       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9516       const PetscInt   numBasisComps = quad[field].numComponents;
9517       const PetscReal *basis         = quad[field].basis;
9518       PetscInt         q, d, e, fc, f;
9519 
9520       if (debug) {
9521         char title[1024];
9522         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9523         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9524       }
9525       for (q = 0; q < numQuadPoints; ++q) {
9526         for (d = 0; d < dim; d++) {
9527           coords[d] = v0[d];
9528           for (e = 0; e < dim; e++) {
9529             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9530           }
9531         }
9532         for (fc = 0; fc < numBasisComps; ++fc) {
9533           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9534           PetscReal       interpolant = 0.0;
9535           for (f = 0; f < numBasisFuncs; ++f) {
9536             const PetscInt fidx = f*numBasisComps+fc;
9537             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9538           }
9539           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9540           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9541         }
9542       }
9543       comp        += numBasisComps;
9544       fieldOffset += numBasisFuncs*numBasisComps;
9545     }
9546     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
9547     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9548     localDiff += elemDiff;
9549   }
9550   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9551   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9552   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9553   *diff = PetscSqrtReal(*diff);
9554   PetscFunctionReturn(0);
9555 }
9556 
9557 #undef __FUNCT__
9558 #define __FUNCT__ "DMPlexComputeResidualFEM"
9559 /*@
9560   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9561 
9562   Input Parameters:
9563 + dm - The mesh
9564 . X  - Local input vector
9565 - user - The user context
9566 
9567   Output Parameter:
9568 . F  - Local output vector
9569 
9570   Note:
9571   The second member of the user context must be an FEMContext.
9572 
9573   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9574   like a GPU, or vectorize on a multicore machine.
9575 
9576 .seealso: DMPlexComputeJacobianActionFEM()
9577 */
9578 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9579 {
9580   DM_Plex      *mesh = (DM_Plex *) dm->data;
9581   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9582   PetscQuadrature *quad = fem->quad;
9583   PetscSection     section;
9584   PetscReal       *v0, *J, *invJ, *detJ;
9585   PetscScalar     *elemVec, *u;
9586   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9587   PetscInt         cellDof = 0, numComponents = 0;
9588   PetscErrorCode   ierr;
9589 
9590   PetscFunctionBegin;
9591   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9592   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9593   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9594   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9595   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9596   numCells = cEnd - cStart;
9597   for (field = 0; field < numFields; ++field) {
9598     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9599     numComponents += quad[field].numComponents;
9600   }
9601   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9602   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9603   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);
9604   for (c = cStart; c < cEnd; ++c) {
9605     const PetscScalar *x;
9606     PetscInt           i;
9607 
9608     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9609     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9610     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9611 
9612     for (i = 0; i < cellDof; ++i) {
9613       u[c*cellDof+i] = x[i];
9614     }
9615     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9616   }
9617   for (field = 0; field < numFields; ++field) {
9618     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9619     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9620     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9621     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9622     /* Conforming batches */
9623     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9624     PetscInt numBlocks  = 1;
9625     PetscInt batchSize  = numBlocks * blockSize;
9626     PetscInt numBatches = numBatchesTmp;
9627     PetscInt numChunks  = numCells / (numBatches*batchSize);
9628     /* Remainder */
9629     PetscInt numRemainder = numCells % (numBatches * batchSize);
9630     PetscInt offset       = numCells - numRemainder;
9631 
9632     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9633     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9634                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9635   }
9636   for (c = cStart; c < cEnd; ++c) {
9637     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9638     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9639   }
9640   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9641   if (mesh->printFEM) {
9642     PetscMPIInt rank, numProcs;
9643     PetscInt    p;
9644 
9645     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9646     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9647     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9648     for (p = 0; p < numProcs; ++p) {
9649       if (p == rank) {
9650         Vec f;
9651 
9652         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9653         ierr = VecCopy(F, f);CHKERRQ(ierr);
9654         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9655         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9656         ierr = VecDestroy(&f);CHKERRQ(ierr);
9657         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9658       }
9659       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9660     }
9661   }
9662   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9663   PetscFunctionReturn(0);
9664 }
9665 
9666 #undef __FUNCT__
9667 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9668 /*@C
9669   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9670 
9671   Input Parameters:
9672 + dm - The mesh
9673 . J  - The Jacobian shell matrix
9674 . X  - Local input vector
9675 - user - The user context
9676 
9677   Output Parameter:
9678 . F  - Local output vector
9679 
9680   Note:
9681   The second member of the user context must be an FEMContext.
9682 
9683   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9684   like a GPU, or vectorize on a multicore machine.
9685 
9686 .seealso: DMPlexComputeResidualFEM()
9687 */
9688 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9689 {
9690   DM_Plex      *mesh = (DM_Plex *) dm->data;
9691   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9692   PetscQuadrature *quad = fem->quad;
9693   PetscSection     section;
9694   JacActionCtx    *jctx;
9695   PetscReal       *v0, *J, *invJ, *detJ;
9696   PetscScalar     *elemVec, *u, *a;
9697   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9698   PetscInt         cellDof = 0;
9699   PetscErrorCode   ierr;
9700 
9701   PetscFunctionBegin;
9702   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9703   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9704   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9705   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9706   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9707   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9708   numCells = cEnd - cStart;
9709   for (field = 0; field < numFields; ++field) {
9710     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9711   }
9712   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9713   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);
9714   for (c = cStart; c < cEnd; ++c) {
9715     const PetscScalar *x;
9716     PetscInt           i;
9717 
9718     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9719     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9720     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
9721     for (i = 0; i < cellDof; ++i) {
9722       u[c*cellDof+i] = x[i];
9723     }
9724     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
9725     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9726     for (i = 0; i < cellDof; ++i) {
9727       a[c*cellDof+i] = x[i];
9728     }
9729     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9730   }
9731   for (field = 0; field < numFields; ++field) {
9732     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9733     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9734     /* Conforming batches */
9735     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9736     PetscInt numBlocks  = 1;
9737     PetscInt batchSize  = numBlocks * blockSize;
9738     PetscInt numBatches = numBatchesTmp;
9739     PetscInt numChunks  = numCells / (numBatches*batchSize);
9740     /* Remainder */
9741     PetscInt numRemainder = numCells % (numBatches * batchSize);
9742     PetscInt offset       = numCells - numRemainder;
9743 
9744     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);
9745     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],
9746                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9747   }
9748   for (c = cStart; c < cEnd; ++c) {
9749     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9750     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9751   }
9752   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9753   if (mesh->printFEM) {
9754     PetscMPIInt rank, numProcs;
9755     PetscInt    p;
9756 
9757     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9758     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9759     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9760     for (p = 0; p < numProcs; ++p) {
9761       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9762       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9763     }
9764   }
9765   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9766   PetscFunctionReturn(0);
9767 }
9768 
9769 #undef __FUNCT__
9770 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9771 /*@
9772   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9773 
9774   Input Parameters:
9775 + dm - The mesh
9776 . X  - Local input vector
9777 - user - The user context
9778 
9779   Output Parameter:
9780 . Jac  - Jacobian matrix
9781 
9782   Note:
9783   The second member of the user context must be an FEMContext.
9784 
9785   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9786   like a GPU, or vectorize on a multicore machine.
9787 
9788 .seealso: FormFunctionLocal()
9789 */
9790 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9791 {
9792   DM_Plex      *mesh = (DM_Plex *) dm->data;
9793   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9794   PetscQuadrature *quad = fem->quad;
9795   PetscSection     section;
9796   PetscReal       *v0, *J, *invJ, *detJ;
9797   PetscScalar     *elemMat, *u;
9798   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9799   PetscInt         cellDof = 0, numComponents = 0;
9800   PetscBool        isShell;
9801   PetscErrorCode   ierr;
9802 
9803   PetscFunctionBegin;
9804   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9805   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9806   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9807   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9808   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9809   numCells = cEnd - cStart;
9810   for (field = 0; field < numFields; ++field) {
9811     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9812     numComponents += quad[field].numComponents;
9813   }
9814   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9815   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9816   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);
9817   for (c = cStart; c < cEnd; ++c) {
9818     const PetscScalar *x;
9819     PetscInt           i;
9820 
9821     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9822     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9823     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9824 
9825     for (i = 0; i < cellDof; ++i) {
9826       u[c*cellDof+i] = x[i];
9827     }
9828     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9829   }
9830   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9831   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9832     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9833     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9834     PetscInt       fieldJ;
9835 
9836     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9837       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9838       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9839       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9840       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9841       /* Conforming batches */
9842       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9843       PetscInt numBlocks  = 1;
9844       PetscInt batchSize  = numBlocks * blockSize;
9845       PetscInt numBatches = numBatchesTmp;
9846       PetscInt numChunks  = numCells / (numBatches*batchSize);
9847       /* Remainder */
9848       PetscInt numRemainder = numCells % (numBatches * batchSize);
9849       PetscInt offset       = numCells - numRemainder;
9850 
9851       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9852       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9853                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9854     }
9855   }
9856   for (c = cStart; c < cEnd; ++c) {
9857     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9858     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9859   }
9860   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9861 
9862   /* Assemble matrix, using the 2-step process:
9863        MatAssemblyBegin(), MatAssemblyEnd(). */
9864   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9865   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9866 
9867   if (mesh->printFEM) {
9868     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9869     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9870     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9871   }
9872   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9873   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9874   if (isShell) {
9875     JacActionCtx *jctx;
9876 
9877     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9878     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9879   }
9880   *str = SAME_NONZERO_PATTERN;
9881   PetscFunctionReturn(0);
9882 }
9883 
9884 
9885 #undef __FUNCT__
9886 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9887 /*@C
9888   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9889   the local section and an SF describing the section point overlap.
9890 
9891   Input Parameters:
9892   + s - The PetscSection for the local field layout
9893   . sf - The SF describing parallel layout of the section points
9894   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9895   . label - The label specifying the points
9896   - labelValue - The label stratum specifying the points
9897 
9898   Output Parameter:
9899   . gsection - The PetscSection for the global field layout
9900 
9901   Note: This gives negative sizes and offsets to points not owned by this process
9902 
9903   Level: developer
9904 
9905 .seealso: PetscSectionCreate()
9906 @*/
9907 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9908 {
9909   PetscInt      *neg;
9910   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9911   PetscErrorCode ierr;
9912 
9913   PetscFunctionBegin;
9914   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9915   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9916   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9917   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9918   /* Mark ghost points with negative dof */
9919   for (p = pStart; p < pEnd; ++p) {
9920     PetscInt value;
9921 
9922     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9923     if (value != labelValue) continue;
9924     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9925     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9926     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9927     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9928     neg[p-pStart] = -(dof+1);
9929   }
9930   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9931   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
9932   if (nroots >= 0) {
9933     if (nroots > pEnd - pStart) {
9934       PetscInt *tmpDof;
9935       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9936       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9937       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9938       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9939       for (p = pStart; p < pEnd; ++p) {
9940         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
9941       }
9942       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9943     } else {
9944       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9945       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9946     }
9947   }
9948   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9949   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9950     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9951     (*gsection)->atlasOff[p] = off;
9952     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9953   }
9954   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9955   globalOff -= off;
9956   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9957     (*gsection)->atlasOff[p] += globalOff;
9958     neg[p] = -((*gsection)->atlasOff[p]+1);
9959   }
9960   /* Put in negative offsets for ghost points */
9961   if (nroots >= 0) {
9962     if (nroots > pEnd - pStart) {
9963       PetscInt *tmpOff;
9964       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9965       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9966       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9967       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9968       for (p = pStart; p < pEnd; ++p) {
9969         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
9970       }
9971       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9972     } else {
9973       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9974       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9975     }
9976   }
9977   ierr = PetscFree(neg);CHKERRQ(ierr);
9978   PetscFunctionReturn(0);
9979 }
9980