xref: /petsc/src/dm/impls/plex/plex.c (revision 9dbfc18722704d6a1497b9a29671ad8f32ee6572)
1 #include <petsc-private/pleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 
4 /* Logging support */
5 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
6 
7 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
8 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "VecView_Plex_Local"
12 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
13 {
14   DM             dm;
15   PetscBool      isvtk;
16   PetscErrorCode ierr;
17 
18   PetscFunctionBegin;
19   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
20   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
21   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
22   if (isvtk) {
23     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
24     PetscSection            section;
25     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
26 
27     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
28     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
29     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, PETSC_NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, PETSC_NULL);CHKERRQ(ierr);
32     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
33     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
34     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
35     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
36     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
37     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
38       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
39     } else if (cdof && vdof) {
40       SETERRQ(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
41     } else if (cdof) {
42       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
43        * vector or just happens to have the same number of dofs as the dimension. */
44       if (cdof == dim) {
45         ft = PETSC_VTK_CELL_VECTOR_FIELD;
46       } else {
47         ft = PETSC_VTK_CELL_FIELD;
48       }
49     } else if (vdof) {
50       if (vdof == dim) {
51         ft = PETSC_VTK_POINT_VECTOR_FIELD;
52       } else {
53         ft = PETSC_VTK_POINT_FIELD;
54       }
55     } else SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
56 
57     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
58     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
59     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
60   } else {
61     PetscBool isseq;
62 
63     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
64     if (isseq) {
65       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
66     } else {
67       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "VecView_Plex"
75 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
76 {
77   DM             dm;
78   PetscBool      isvtk;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
83   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
84   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
85   if (isvtk) {
86     Vec         locv;
87     const char *name;
88 
89     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
90     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
91     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
92     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
95     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
96   } else {
97     PetscBool isseq;
98 
99     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
100     if (isseq) {
101       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
102     } else {
103       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
104     }
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "DMPlexView_Ascii"
111 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
112 {
113   DM_Plex       *mesh = (DM_Plex *) dm->data;
114   DM                cdm;
115   DMLabel           markers;
116   PetscSection      coordSection;
117   Vec               coordinates;
118   PetscViewerFormat format;
119   PetscErrorCode    ierr;
120 
121   PetscFunctionBegin;
122   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
123   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
124   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
125   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
126   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
127     const char *name;
128     PetscInt    maxConeSize, maxSupportSize;
129     PetscInt    pStart, pEnd, p;
130     PetscMPIInt rank, size;
131 
132     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
133     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
134     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
135     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
136     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
137     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
138     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
142     for (p = pStart; p < pEnd; ++p) {
143       PetscInt dof, off, s;
144 
145       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
146       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
147       for (s = off; s < off+dof; ++s) {
148         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
149       }
150     }
151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
152     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
153     for (p = pStart; p < pEnd; ++p) {
154       PetscInt dof, off, c;
155 
156       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
157       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
158       for (c = off; c < off+dof; ++c) {
159         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
160       }
161     }
162     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
163     ierr = PetscSectionGetChart(coordSection, &pStart, PETSC_NULL);CHKERRQ(ierr);
164     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
165     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
166     if (markers) {
167       ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
168     }
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors = 3;
180     PetscReal    scale = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = PETSC_NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm = ((PetscObject) dm)->comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscMPIInt size;
282 
283     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
284     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
285     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
286     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
287     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
288     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
289     if (depth == 1) {
290       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
291       pEnd = pEnd - pStart;
292       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
293       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
294       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
295       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
296       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
297       pEnd = pEnd - pStart;
298       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
299       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
300       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
301       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
302     } else {
303       for (d = 0; d <= dim; d++) {
304         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
305         pEnd = pEnd - pStart;
306         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
307         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
308         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
309         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
310       }
311     }
312     ierr = PetscFree(sizes);CHKERRQ(ierr);
313   }
314   PetscFunctionReturn(0);
315 }
316 
317 #undef __FUNCT__
318 #define __FUNCT__ "DMView_Plex"
319 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
320 {
321   PetscBool      iascii, isbinary;
322   PetscErrorCode ierr;
323 
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
326   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
327   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
329   if (iascii) {
330     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
331 #if 0
332   } else if (isbinary) {
333     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
334 #endif
335   } else SETERRQ1(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"Viewer type %s not supported by this mesh object", ((PetscObject)viewer)->type_name);
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "DMDestroy_Plex"
341 PetscErrorCode DMDestroy_Plex(DM dm)
342 {
343   DM_Plex    *mesh = (DM_Plex *) dm->data;
344   DMLabel        next = mesh->labels;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   if (--mesh->refct > 0) {PetscFunctionReturn(0);}
349   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
350   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
352   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
353   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
355   while (next) {
356     DMLabel tmp = next->next;
357 
358     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
359     next = tmp;
360   }
361   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
362   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
364   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
365   ierr = PetscFree(mesh);CHKERRQ(ierr);
366   PetscFunctionReturn(0);
367 }
368 
369 #undef __FUNCT__
370 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
371 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
372 {
373   const PetscInt *support = PETSC_NULL;
374   PetscInt        numAdj  = 0, maxAdjSize = *adjSize, supportSize, s;
375   PetscErrorCode  ierr;
376 
377   PetscFunctionBegin;
378   if (useClosure) {
379     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
380     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
381     for (s = 0; s < supportSize; ++s) {
382       const PetscInt *cone = PETSC_NULL;
383       PetscInt        coneSize, c, q;
384 
385       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
386       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
387       for (c = 0; c < coneSize; ++c) {
388         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
389           if (cone[c] == adj[q]) break;
390         }
391         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
392       }
393     }
394   } else {
395     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
396     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
397     for (s = 0; s < supportSize; ++s) {
398       const PetscInt *cone = PETSC_NULL;
399       PetscInt        coneSize, c, q;
400 
401       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
402       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
403       for (c = 0; c < coneSize; ++c) {
404         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
405           if (cone[c] == adj[q]) break;
406         }
407         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
408       }
409     }
410   }
411   *adjSize = numAdj;
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "DMPlexGetAdjacency_Private"
417 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
418 {
419   const PetscInt *star   = tmpClosure;
420   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
421   PetscErrorCode  ierr;
422 
423   PetscFunctionBegin;
424   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt **) &star);CHKERRQ(ierr);
425   for (s = 2; s < starSize*2; s += 2) {
426     const PetscInt *closure = PETSC_NULL;
427     PetscInt        closureSize, c, q;
428 
429     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
430     for (c = 0; c < closureSize*2; c += 2) {
431       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
432         if (closure[c] == adj[q]) break;
433       }
434       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
435     }
436     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
437   }
438   *adjSize = numAdj;
439   PetscFunctionReturn(0);
440 }
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
444 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
445 {
446   DM_Plex *mesh = (DM_Plex *) dm->data;
447 
448   PetscFunctionBegin;
449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
450   mesh->preallocCenterDim = preallocCenterDim;
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "DMPlexPreallocateOperator"
456 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
457 {
458   DM_Plex        *mesh = (DM_Plex *) dm->data;
459   MPI_Comm           comm = ((PetscObject) dm)->comm;
460   PetscSF            sf, sfDof, sfAdj;
461   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
462   PetscInt           nleaves, l, p;
463   const PetscInt    *leaves;
464   const PetscSFNode *remotes;
465   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
466   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
467   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
468   PetscLayout        rLayout;
469   PetscInt           locRows, rStart, rEnd, r;
470   PetscMPIInt        size;
471   PetscBool          useClosure, debug = PETSC_FALSE;
472   PetscErrorCode     ierr;
473 
474   PetscFunctionBegin;
475   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
476   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
477   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
478   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
479   /* Create dof SF based on point SF */
480   if (debug) {
481     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
487   }
488   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
489   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
490   if (debug) {
491     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
492     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
493   }
494   /* Create section for dof adjacency (dof ==> # adj dof) */
495   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
496   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
497   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
498   if (mesh->preallocCenterDim == dim) {
499     useClosure = PETSC_FALSE;
500   } else if (mesh->preallocCenterDim == 0) {
501     useClosure = PETSC_TRUE;
502   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
503 
504   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
505   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
510   /*   Fill in the ghost dofs on the interface */
511   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
512   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
513   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
514   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
515   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
516   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
517 
518   /*
519    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
520     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
521        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
522     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
523        Create sfAdj connecting rootSectionAdj and leafSectionAdj
524     3. Visit unowned points on interface, write adjacencies to adj
525        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
526     4. Visit owned points on interface, write adjacencies to rootAdj
527        Remove redundancy in rootAdj
528    ** The last two traversals use transitive closure
529     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
530        Allocate memory addressed by sectionAdj (cols)
531     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
532    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
533   */
534 
535   for (l = 0; l < nleaves; ++l) {
536     PetscInt dof, off, d, q;
537     PetscInt p = leaves[l], numAdj = maxAdjSize;
538 
539     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
540     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
541     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
542     for (q = 0; q < numAdj; ++q) {
543       PetscInt ndof, ncdof;
544 
545       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
546       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
547       for (d = off; d < off+dof; ++d) {
548         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
549       }
550     }
551   }
552   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
553   if (debug) {
554     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
555     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
556   }
557   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
558   if (size > 1) {
559     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
560     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561   }
562   if (debug) {
563     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
564     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
565   }
566   /* Add in local adjacency sizes for owned dofs on interface (roots) */
567   for (p = pStart; p < pEnd; ++p) {
568     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
569 
570     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
571     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
572     if (!dof) continue;
573     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
574     if (adof <= 0) continue;
575     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
576     for (q = 0; q < numAdj; ++q) {
577       PetscInt ndof, ncdof;
578 
579       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
580       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
581       for (d = off; d < off+dof; ++d) {
582         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
583       }
584     }
585   }
586   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
587   if (debug) {
588     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
589     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
590   }
591   /* Create adj SF based on dof SF */
592   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
593   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
596     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
597   }
598   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
599   /* Create leaf adjacency */
600   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
601   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
602   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
603   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
604   for (l = 0; l < nleaves; ++l) {
605     PetscInt dof, off, d, q;
606     PetscInt p = leaves[l], numAdj = maxAdjSize;
607 
608     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
609     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
610     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
611     for (d = off; d < off+dof; ++d) {
612       PetscInt aoff, i = 0;
613 
614       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
615       for (q = 0; q < numAdj; ++q) {
616         PetscInt  ndof, ncdof, ngoff, nd;
617 
618         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
619         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
620         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
621         for (nd = 0; nd < ndof-ncdof; ++nd) {
622           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
623           ++i;
624         }
625       }
626     }
627   }
628   /* Debugging */
629   if (debug) {
630     IS tmp;
631     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
632     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
633     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
634   }
635   /* Gather adjacenct indices to root */
636   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
637   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
638   for (r = 0; r < adjSize; ++r) {
639     rootAdj[r] = -1;
640   }
641   if (size > 1) {
642     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
643     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
644   }
645   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
646   ierr = PetscFree(adj);CHKERRQ(ierr);
647   /* Debugging */
648   if (debug) {
649     IS tmp;
650     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
651     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
652     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
653   }
654   /* Add in local adjacency indices for owned dofs on interface (roots) */
655   for (p = pStart; p < pEnd; ++p) {
656     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
657 
658     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
659     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
660     if (!dof) continue;
661     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
662     if (adof <= 0) continue;
663     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
664     for (d = off; d < off+dof; ++d) {
665       PetscInt adof, aoff, i;
666 
667       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
668       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
669       i    = adof-1;
670       for (q = 0; q < numAdj; ++q) {
671         PetscInt ndof, ncdof, ngoff, nd;
672 
673         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
674         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
675         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
676         for (nd = 0; nd < ndof-ncdof; ++nd) {
677           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
678           --i;
679         }
680       }
681     }
682   }
683   /* Debugging */
684   if (debug) {
685     IS tmp;
686     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
687     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
688     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
689   }
690   /* Compress indices */
691   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
692   for (p = pStart; p < pEnd; ++p) {
693     PetscInt dof, cdof, off, d;
694     PetscInt adof, aoff;
695 
696     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
697     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
698     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
699     if (!dof) continue;
700     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
701     if (adof <= 0) continue;
702     for (d = off; d < off+dof-cdof; ++d) {
703       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
704       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
705       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
706       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
707     }
708   }
709   /* Debugging */
710   if (debug) {
711     IS tmp;
712     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
713     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
714     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
715     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
716     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
717   }
718   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
719   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
720   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
721   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
722   for (p = pStart; p < pEnd; ++p) {
723     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
724     PetscBool found  = PETSC_TRUE;
725 
726     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
727     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
728     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
729     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
730     for (d = 0; d < dof-cdof; ++d) {
731       PetscInt ldof, rdof;
732 
733       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
734       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
735       if (ldof > 0) {
736         /* We do not own this point */
737       } else if (rdof > 0) {
738         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
739       } else {
740         found = PETSC_FALSE;
741       }
742     }
743     if (found) continue;
744     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
745     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
746     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
747     for (q = 0; q < numAdj; ++q) {
748       PetscInt ndof, ncdof, noff;
749 
750       /* Adjacent points may not be in the section chart */
751       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
752       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
753       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
754       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
755       for (d = goff; d < goff+dof-cdof; ++d) {
756         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
757       }
758     }
759   }
760   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
761   if (debug) {
762     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
763     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
764   }
765   /* Get adjacent indices */
766   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
767   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
768   for (p = pStart; p < pEnd; ++p) {
769     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
770     PetscBool found  = PETSC_TRUE;
771 
772     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
773     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
774     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
775     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
776     for (d = 0; d < dof-cdof; ++d) {
777       PetscInt ldof, rdof;
778 
779       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
780       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
781       if (ldof > 0) {
782         /* We do not own this point */
783       } else if (rdof > 0) {
784         PetscInt aoff, roff;
785 
786         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
787         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
788         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
789       } else {
790         found = PETSC_FALSE;
791       }
792     }
793     if (found) continue;
794     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
795     for (d = goff; d < goff+dof-cdof; ++d) {
796       PetscInt adof, aoff, i = 0;
797 
798       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
799       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
800       for (q = 0; q < numAdj; ++q) {
801         PetscInt        ndof, ncdof, ngoff, nd;
802         const PetscInt *ncind;
803 
804         /* Adjacent points may not be in the section chart */
805         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
806         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
807         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
808         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
809         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
810         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
811           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
812         }
813       }
814       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
815     }
816   }
817   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
818   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
819   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
820   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
821   /* Debugging */
822   if (debug) {
823     IS tmp;
824     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
825     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
826     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
827   }
828   /* Create allocation vectors from adjacency graph */
829   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
830   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
831   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
832   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
833   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
834   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
835   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
836   /* Only loop over blocks of rows */
837   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
838   for (r = rStart/bs; r < rEnd/bs; ++r) {
839     const PetscInt row = r*bs;
840     PetscInt numCols, cStart, c;
841 
842     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
843     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
844     for (c = cStart; c < cStart+numCols; ++c) {
845       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
846         ++dnz[r-rStart];
847         if (cols[c] >= row) {++dnzu[r-rStart];}
848       } else {
849         ++onz[r-rStart];
850         if (cols[c] >= row) {++onzu[r-rStart];}
851       }
852     }
853   }
854   if (bs > 1) {
855     for (r = 0; r < locRows/bs; ++r) {
856       dnz[r]  /= bs;
857       onz[r]  /= bs;
858       dnzu[r] /= bs;
859       onzu[r] /= bs;
860     }
861   }
862   /* Set matrix pattern */
863   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
864   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
865   /* Fill matrix with zeros */
866   if (fillMatrix) {
867     PetscScalar *values;
868     PetscInt     maxRowLen = 0;
869 
870     for (r = rStart; r < rEnd; ++r) {
871       PetscInt len;
872 
873       ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
874       maxRowLen = PetscMax(maxRowLen, len);
875     }
876     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
877     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
878     for (r = rStart; r < rEnd; ++r) {
879       PetscInt numCols, cStart;
880 
881       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
882       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
883       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
884     }
885     ierr = PetscFree(values);CHKERRQ(ierr);
886     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
887     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
888   }
889   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
890   ierr = PetscFree(cols);CHKERRQ(ierr);
891   PetscFunctionReturn(0);
892 }
893 
894 #if 0
895 #undef __FUNCT__
896 #define __FUNCT__ "DMPlexPreallocateOperator_2"
897 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
898 {
899   PetscErrorCode ierr;
900   PetscInt c,cStart,cEnd,pStart,pEnd;
901   PetscInt *tmpClosure,*tmpAdj,*visits;
902 
903   PetscFunctionBegin;
904   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
905   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
906   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
907   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
908   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
911   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
912   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
914   for (c=cStart; c<cEnd; c++) {
915     PetscInt *support = tmpClosure;
916     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
917     for (p=0; p<supportSize; p++) {
918       lvisits[support[p]]++;
919     }
920   }
921   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
923   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
925 
926   ierr = PetscSFGetRanks();CHKERRQ(ierr);
927 
928 
929   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
930   for (c=cStart; c<cEnd; c++) {
931     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
932     /*
933      Depth-first walk of transitive closure.
934      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
935      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
936      */
937   }
938 
939   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
940   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
941   PetscFunctionReturn(0);
942 }
943 #endif
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "DMCreateMatrix_Plex"
947 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
948 {
949   PetscSection   section, sectionGlobal;
950   PetscInt       bs = -1;
951   PetscInt       localSize;
952   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
953   PetscErrorCode ierr;
954 
955   PetscFunctionBegin;
956 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
957   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
958 #endif
959   if (!mtype) mtype = MATAIJ;
960   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
961   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
962   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
963   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
964   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
965   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
966   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
967   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
975   /* Check for symmetric storage */
976   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
977   if (isSymmetric) {
978     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
979   }
980   if (!isShell) {
981     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
982     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal;
983 
984     if (bs < 0) {
985       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
986         PetscInt pStart, pEnd, p, dof;
987 
988         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
989         for (p = pStart; p < pEnd; ++p) {
990           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
991           if (dof) {
992             bs = dof;
993             break;
994           }
995         }
996       } else {
997         bs = 1;
998       }
999       /* Must have same blocksize on all procs (some might have no points) */
1000       bsLocal = bs;
1001       ierr = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1002     }
1003     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1004     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1005     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1006     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1007     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1008     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1009     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1010   }
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 #undef __FUNCT__
1015 #define __FUNCT__ "DMPlexGetDimension"
1016 /*@
1017   DMPlexGetDimension - Return the topological mesh dimension
1018 
1019   Not collective
1020 
1021   Input Parameter:
1022 . mesh - The DMPlex
1023 
1024   Output Parameter:
1025 . dim - The topological mesh dimension
1026 
1027   Level: beginner
1028 
1029 .seealso: DMPlexCreate()
1030 @*/
1031 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1032 {
1033   DM_Plex *mesh = (DM_Plex *) dm->data;
1034 
1035   PetscFunctionBegin;
1036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1037   PetscValidPointer(dim, 2);
1038   *dim = mesh->dim;
1039   PetscFunctionReturn(0);
1040 }
1041 
1042 #undef __FUNCT__
1043 #define __FUNCT__ "DMPlexSetDimension"
1044 /*@
1045   DMPlexSetDimension - Set the topological mesh dimension
1046 
1047   Collective on mesh
1048 
1049   Input Parameters:
1050 + mesh - The DMPlex
1051 - dim - The topological mesh dimension
1052 
1053   Level: beginner
1054 
1055 .seealso: DMPlexCreate()
1056 @*/
1057 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1058 {
1059   DM_Plex *mesh = (DM_Plex *) dm->data;
1060 
1061   PetscFunctionBegin;
1062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1063   PetscValidLogicalCollectiveInt(dm, dim, 2);
1064   mesh->dim = dim;
1065   mesh->preallocCenterDim = dim;
1066   PetscFunctionReturn(0);
1067 }
1068 
1069 #undef __FUNCT__
1070 #define __FUNCT__ "DMPlexGetChart"
1071 /*@
1072   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1073 
1074   Not collective
1075 
1076   Input Parameter:
1077 . mesh - The DMPlex
1078 
1079   Output Parameters:
1080 + pStart - The first mesh point
1081 - pEnd   - The upper bound for mesh points
1082 
1083   Level: beginner
1084 
1085 .seealso: DMPlexCreate(), DMPlexSetChart()
1086 @*/
1087 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1088 {
1089   DM_Plex    *mesh = (DM_Plex *) dm->data;
1090   PetscErrorCode ierr;
1091 
1092   PetscFunctionBegin;
1093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1094   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1095   PetscFunctionReturn(0);
1096 }
1097 
1098 #undef __FUNCT__
1099 #define __FUNCT__ "DMPlexSetChart"
1100 /*@
1101   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1102 
1103   Not collective
1104 
1105   Input Parameters:
1106 + mesh - The DMPlex
1107 . pStart - The first mesh point
1108 - pEnd   - The upper bound for mesh points
1109 
1110   Output Parameters:
1111 
1112   Level: beginner
1113 
1114 .seealso: DMPlexCreate(), DMPlexGetChart()
1115 @*/
1116 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1117 {
1118   DM_Plex    *mesh = (DM_Plex *) dm->data;
1119   PetscErrorCode ierr;
1120 
1121   PetscFunctionBegin;
1122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1123   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1124   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 #undef __FUNCT__
1129 #define __FUNCT__ "DMPlexGetConeSize"
1130 /*@
1131   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1132 
1133   Not collective
1134 
1135   Input Parameters:
1136 + mesh - The DMPlex
1137 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1138 
1139   Output Parameter:
1140 . size - The cone size for point p
1141 
1142   Level: beginner
1143 
1144 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1145 @*/
1146 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1147 {
1148   DM_Plex    *mesh = (DM_Plex *) dm->data;
1149   PetscErrorCode ierr;
1150 
1151   PetscFunctionBegin;
1152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1153   PetscValidPointer(size, 3);
1154   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1155   PetscFunctionReturn(0);
1156 }
1157 
1158 #undef __FUNCT__
1159 #define __FUNCT__ "DMPlexSetConeSize"
1160 /*@
1161   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1162 
1163   Not collective
1164 
1165   Input Parameters:
1166 + mesh - The DMPlex
1167 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1168 - size - The cone size for point p
1169 
1170   Output Parameter:
1171 
1172   Note:
1173   This should be called after DMPlexSetChart().
1174 
1175   Level: beginner
1176 
1177 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1178 @*/
1179 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1180 {
1181   DM_Plex    *mesh = (DM_Plex *) dm->data;
1182   PetscErrorCode ierr;
1183 
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1186   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1187   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1188   PetscFunctionReturn(0);
1189 }
1190 
1191 #undef __FUNCT__
1192 #define __FUNCT__ "DMPlexGetCone"
1193 /*@C
1194   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1195 
1196   Not collective
1197 
1198   Input Parameters:
1199 + mesh - The DMPlex
1200 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1201 
1202   Output Parameter:
1203 . cone - An array of points which are on the in-edges for point p
1204 
1205   Level: beginner
1206 
1207   Note:
1208   This routine is not available in Fortran.
1209 
1210 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1211 @*/
1212 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1213 {
1214   DM_Plex    *mesh = (DM_Plex *) dm->data;
1215   PetscInt       off;
1216   PetscErrorCode ierr;
1217 
1218   PetscFunctionBegin;
1219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1220   PetscValidPointer(cone, 3);
1221   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1222   *cone = &mesh->cones[off];
1223   PetscFunctionReturn(0);
1224 }
1225 
1226 #undef __FUNCT__
1227 #define __FUNCT__ "DMPlexSetCone"
1228 /*@
1229   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1230 
1231   Not collective
1232 
1233   Input Parameters:
1234 + mesh - The DMPlex
1235 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1236 - cone - An array of points which are on the in-edges for point p
1237 
1238   Output Parameter:
1239 
1240   Note:
1241   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1242 
1243   Level: beginner
1244 
1245 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1246 @*/
1247 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1248 {
1249   DM_Plex    *mesh = (DM_Plex *) dm->data;
1250   PetscInt       pStart, pEnd;
1251   PetscInt       dof, off, c;
1252   PetscErrorCode ierr;
1253 
1254   PetscFunctionBegin;
1255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1256   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1257   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1258   if (dof) PetscValidPointer(cone, 3);
1259   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1260   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1261   for (c = 0; c < dof; ++c) {
1262     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1263     mesh->cones[off+c] = cone[c];
1264   }
1265   PetscFunctionReturn(0);
1266 }
1267 
1268 #undef __FUNCT__
1269 #define __FUNCT__ "DMPlexGetConeOrientation"
1270 /*@C
1271   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1272 
1273   Not collective
1274 
1275   Input Parameters:
1276 + mesh - The DMPlex
1277 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1278 
1279   Output Parameter:
1280 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1281                     integer giving the prescription for cone traversal. If it is negative, the cone is
1282                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1283                     the index of the cone point on which to start.
1284 
1285   Level: beginner
1286 
1287   Note:
1288   This routine is not available in Fortran.
1289 
1290 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1291 @*/
1292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1293 {
1294   DM_Plex    *mesh = (DM_Plex *) dm->data;
1295   PetscInt       off;
1296   PetscErrorCode ierr;
1297 
1298   PetscFunctionBegin;
1299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1300 #if defined(PETSC_USE_DEBUG)
1301   {
1302     PetscInt dof;
1303     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1304     if (dof) PetscValidPointer(coneOrientation, 3);
1305   }
1306 #endif
1307   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1308   *coneOrientation = &mesh->coneOrientations[off];
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 #undef __FUNCT__
1313 #define __FUNCT__ "DMPlexSetConeOrientation"
1314 /*@
1315   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1316 
1317   Not collective
1318 
1319   Input Parameters:
1320 + mesh - The DMPlex
1321 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1322 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1323                     integer giving the prescription for cone traversal. If it is negative, the cone is
1324                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1325                     the index of the cone point on which to start.
1326 
1327   Output Parameter:
1328 
1329   Note:
1330   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1331 
1332   Level: beginner
1333 
1334 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1335 @*/
1336 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1337 {
1338   DM_Plex    *mesh = (DM_Plex *) dm->data;
1339   PetscInt       pStart, pEnd;
1340   PetscInt       dof, off, c;
1341   PetscErrorCode ierr;
1342 
1343   PetscFunctionBegin;
1344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1345   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1346   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1347   if (dof) PetscValidPointer(coneOrientation, 3);
1348   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1349   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1350   for (c = 0; c < dof; ++c) {
1351     PetscInt cdof, o = coneOrientation[c];
1352 
1353     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1354     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1355     mesh->coneOrientations[off+c] = o;
1356   }
1357   PetscFunctionReturn(0);
1358 }
1359 
1360 #undef __FUNCT__
1361 #define __FUNCT__ "DMPlexInsertCone"
1362 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1363 {
1364   DM_Plex    *mesh = (DM_Plex *) dm->data;
1365   PetscInt       pStart, pEnd;
1366   PetscInt       dof, off;
1367   PetscErrorCode ierr;
1368 
1369   PetscFunctionBegin;
1370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1371   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1372   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1373   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1374   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1375   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1376   if (conePos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1377   mesh->cones[off+conePos] = conePoint;
1378   PetscFunctionReturn(0);
1379 }
1380 
1381 #undef __FUNCT__
1382 #define __FUNCT__ "DMPlexGetSupportSize"
1383 /*@
1384   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1385 
1386   Not collective
1387 
1388   Input Parameters:
1389 + mesh - The DMPlex
1390 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1391 
1392   Output Parameter:
1393 . size - The support size for point p
1394 
1395   Level: beginner
1396 
1397 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1398 @*/
1399 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1400 {
1401   DM_Plex    *mesh = (DM_Plex *) dm->data;
1402   PetscErrorCode ierr;
1403 
1404   PetscFunctionBegin;
1405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1406   PetscValidPointer(size, 3);
1407   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1408   PetscFunctionReturn(0);
1409 }
1410 
1411 #undef __FUNCT__
1412 #define __FUNCT__ "DMPlexSetSupportSize"
1413 /*@
1414   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1415 
1416   Not collective
1417 
1418   Input Parameters:
1419 + mesh - The DMPlex
1420 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1421 - size - The support size for point p
1422 
1423   Output Parameter:
1424 
1425   Note:
1426   This should be called after DMPlexSetChart().
1427 
1428   Level: beginner
1429 
1430 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1431 @*/
1432 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1433 {
1434   DM_Plex    *mesh = (DM_Plex *) dm->data;
1435   PetscErrorCode ierr;
1436 
1437   PetscFunctionBegin;
1438   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1439   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1440   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1441   PetscFunctionReturn(0);
1442 }
1443 
1444 #undef __FUNCT__
1445 #define __FUNCT__ "DMPlexGetSupport"
1446 /*@C
1447   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1448 
1449   Not collective
1450 
1451   Input Parameters:
1452 + mesh - The DMPlex
1453 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1454 
1455   Output Parameter:
1456 . support - An array of points which are on the out-edges for point p
1457 
1458   Level: beginner
1459 
1460 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1461 @*/
1462 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1463 {
1464   DM_Plex    *mesh = (DM_Plex *) dm->data;
1465   PetscInt       off;
1466   PetscErrorCode ierr;
1467 
1468   PetscFunctionBegin;
1469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1470   PetscValidPointer(support, 3);
1471   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1472   *support = &mesh->supports[off];
1473   PetscFunctionReturn(0);
1474 }
1475 
1476 #undef __FUNCT__
1477 #define __FUNCT__ "DMPlexSetSupport"
1478 /*@
1479   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1480 
1481   Not collective
1482 
1483   Input Parameters:
1484 + mesh - The DMPlex
1485 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1486 - support - An array of points which are on the in-edges for point p
1487 
1488   Output Parameter:
1489 
1490   Note:
1491   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1492 
1493   Level: beginner
1494 
1495 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1496 @*/
1497 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1498 {
1499   DM_Plex    *mesh = (DM_Plex *) dm->data;
1500   PetscInt       pStart, pEnd;
1501   PetscInt       dof, off, c;
1502   PetscErrorCode ierr;
1503 
1504   PetscFunctionBegin;
1505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1506   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1507   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1508   if (dof) PetscValidPointer(support, 3);
1509   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1510   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1511   for (c = 0; c < dof; ++c) {
1512     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1513     mesh->supports[off+c] = support[c];
1514   }
1515   PetscFunctionReturn(0);
1516 }
1517 
1518 #undef __FUNCT__
1519 #define __FUNCT__ "DMPlexInsertSupport"
1520 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1521 {
1522   DM_Plex    *mesh = (DM_Plex *) dm->data;
1523   PetscInt       pStart, pEnd;
1524   PetscInt       dof, off;
1525   PetscErrorCode ierr;
1526 
1527   PetscFunctionBegin;
1528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1529   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1530   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1531   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1532   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1533   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1534   if (supportPos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1535   mesh->supports[off+supportPos] = supportPoint;
1536   PetscFunctionReturn(0);
1537 }
1538 
1539 #undef __FUNCT__
1540 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1541 /*@C
1542   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1543 
1544   Not collective
1545 
1546   Input Parameters:
1547 + mesh - The DMPlex
1548 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1549 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1550 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1551 
1552   Output Parameters:
1553 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1554 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1555 
1556   Note:
1557   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1558 
1559   Level: beginner
1560 
1561 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1562 @*/
1563 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1564 {
1565   DM_Plex     *mesh = (DM_Plex *) dm->data;
1566   PetscInt       *closure, *fifo;
1567   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1568   PetscInt        tmpSize, t;
1569   PetscInt        depth = 0, maxSize;
1570   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1571   PetscErrorCode  ierr;
1572 
1573   PetscFunctionBegin;
1574   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1575   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1576   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1577   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1578   if (*points) {
1579     closure = *points;
1580   } else {
1581     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1582   }
1583   closure[0] = p; closure[1] = 0;
1584   /* This is only 1-level */
1585   if (useCone) {
1586     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1587     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1588     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1589   } else {
1590     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1591     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1592   }
1593   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1594     const PetscInt cp = tmp[t];
1595     const PetscInt co = tmpO ? tmpO[t] : 0;
1596 
1597     closure[closureSize]   = cp;
1598     closure[closureSize+1] = co;
1599     fifo[fifoSize]         = cp;
1600     fifo[fifoSize+1]       = co;
1601   }
1602   while (fifoSize - fifoStart) {
1603     const PetscInt q   = fifo[fifoStart];
1604     const PetscInt o   = fifo[fifoStart+1];
1605     const PetscInt rev = o >= 0 ? 0 : 1;
1606     const PetscInt off = rev ? -(o+1) : o;
1607 
1608     if (useCone) {
1609       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1610       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1611       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1612     } else {
1613       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1614       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1615       tmpO = PETSC_NULL;
1616     }
1617     for (t = 0; t < tmpSize; ++t) {
1618       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1619       const PetscInt cp = tmp[i];
1620       /* Must propogate orientation */
1621       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1622       PetscInt       c;
1623 
1624       /* Check for duplicate */
1625       for (c = 0; c < closureSize; c += 2) {
1626         if (closure[c] == cp) break;
1627       }
1628       if (c == closureSize) {
1629         closure[closureSize]   = cp;
1630         closure[closureSize+1] = co;
1631         fifo[fifoSize]         = cp;
1632         fifo[fifoSize+1]       = co;
1633         closureSize += 2;
1634         fifoSize    += 2;
1635       }
1636     }
1637     fifoStart += 2;
1638   }
1639   if (numPoints) *numPoints = closureSize/2;
1640   if (points)    *points    = closure;
1641   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1642   PetscFunctionReturn(0);
1643 }
1644 
1645 #undef __FUNCT__
1646 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1647 /*@C
1648   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1649 
1650   Not collective
1651 
1652   Input Parameters:
1653 + mesh - The DMPlex
1654 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1655 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1656 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1657 
1658   Output Parameters:
1659 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1660 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1661 
1662   Note:
1663   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1664 
1665   Level: beginner
1666 
1667 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1668 @*/
1669 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1670 {
1671   PetscErrorCode  ierr;
1672 
1673   PetscFunctionBegin;
1674   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1675   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1676   PetscFunctionReturn(0);
1677 }
1678 
1679 #undef __FUNCT__
1680 #define __FUNCT__ "DMPlexGetFaces"
1681 /*
1682   DMPlexGetFaces -
1683 
1684   Note: This will only work for cell-vertex meshes.
1685 */
1686 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1687 {
1688   DM_Plex     *mesh  = (DM_Plex *) dm->data;
1689   const PetscInt *cone  = PETSC_NULL;
1690   PetscInt        depth = 0, dim, coneSize;
1691   PetscErrorCode  ierr;
1692 
1693   PetscFunctionBegin;
1694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1695   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1696   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1697   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1698   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1699   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1700   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1701   switch (dim) {
1702   case 2:
1703     switch (coneSize) {
1704     case 3:
1705       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1706       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1707       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1708       *numFaces = 3;
1709       *faceSize = 2;
1710       *faces    = mesh->facesTmp;
1711       break;
1712     case 4:
1713       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1714       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1715       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1716       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1717       *numFaces = 4;
1718       *faceSize = 2;
1719       *faces    = mesh->facesTmp;
1720       break;
1721     default:
1722       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1723     }
1724     break;
1725   case 3:
1726     switch (coneSize) {
1727     case 3:
1728       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1729       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1730       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1731       *numFaces = 3;
1732       *faceSize = 2;
1733       *faces    = mesh->facesTmp;
1734       break;
1735     case 4:
1736       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1737       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1738       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1739       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1740       *numFaces = 4;
1741       *faceSize = 3;
1742       *faces    = mesh->facesTmp;
1743       break;
1744     default:
1745       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1746     }
1747     break;
1748   default:
1749     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1750   }
1751   PetscFunctionReturn(0);
1752 }
1753 
1754 #undef __FUNCT__
1755 #define __FUNCT__ "DMPlexGetMaxSizes"
1756 /*@
1757   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1758 
1759   Not collective
1760 
1761   Input Parameter:
1762 . mesh - The DMPlex
1763 
1764   Output Parameters:
1765 + maxConeSize - The maximum number of in-edges
1766 - maxSupportSize - The maximum number of out-edges
1767 
1768   Level: beginner
1769 
1770 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1771 @*/
1772 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1773 {
1774   DM_Plex *mesh = (DM_Plex *) dm->data;
1775 
1776   PetscFunctionBegin;
1777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1778   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1779   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1780   PetscFunctionReturn(0);
1781 }
1782 
1783 #undef __FUNCT__
1784 #define __FUNCT__ "DMSetUp_Plex"
1785 PetscErrorCode DMSetUp_Plex(DM dm)
1786 {
1787   DM_Plex    *mesh = (DM_Plex *) dm->data;
1788   PetscInt       size;
1789   PetscErrorCode ierr;
1790 
1791   PetscFunctionBegin;
1792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1793   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1794   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1795   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1796   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1797   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1798   if (mesh->maxSupportSize) {
1799     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1800     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1801     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1802   }
1803   PetscFunctionReturn(0);
1804 }
1805 
1806 #undef __FUNCT__
1807 #define __FUNCT__ "DMCreateSubDM_Plex"
1808 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1809 {
1810   PetscSection   section, sectionGlobal;
1811   PetscInt      *subIndices;
1812   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1813   PetscErrorCode ierr;
1814 
1815   PetscFunctionBegin;
1816   if (!numFields) PetscFunctionReturn(0);
1817   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1818   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1819   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1820   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1821   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1822   if (numFields > nF) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1823   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1824   for (p = pStart; p < pEnd; ++p) {
1825     PetscInt gdof;
1826 
1827     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1828     if (gdof > 0) {
1829       for (f = 0; f < numFields; ++f) {
1830         PetscInt fdof, fcdof;
1831 
1832         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1833         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1834         subSize += fdof-fcdof;
1835       }
1836     }
1837   }
1838   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1839   for (p = pStart; p < pEnd; ++p) {
1840     PetscInt gdof, goff;
1841 
1842     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1843     if (gdof > 0) {
1844       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1845       for (f = 0; f < numFields; ++f) {
1846         PetscInt fdof, fcdof, fc, f2, poff = 0;
1847 
1848         /* Can get rid of this loop by storing field information in the global section */
1849         for (f2 = 0; f2 < fields[f]; ++f2) {
1850           ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1851           ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1852           poff += fdof-fcdof;
1853         }
1854         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1855         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1856         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1857           subIndices[subOff] = goff+poff+fc;
1858         }
1859       }
1860     }
1861   }
1862   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1863   if (subdm) {
1864     PetscSection subsection;
1865     PetscBool    haveNull = PETSC_FALSE;
1866     PetscInt     f, nf = 0;
1867 
1868     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1869     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1870     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1871     for (f = 0; f < numFields; ++f) {
1872       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1873       if ((*subdm)->nullspaceConstructors[f]) {
1874         haveNull = PETSC_TRUE;
1875         nf       = f;
1876       }
1877     }
1878     if (haveNull) {
1879       MatNullSpace nullSpace;
1880 
1881       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1882       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1883       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1884     }
1885     if (dm->fields) {
1886       if (nF != dm->numFields) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1887       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1888       for (f = 0; f < numFields; ++f) {
1889         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1890       }
1891       if (numFields == 1) {
1892         MatNullSpace space;
1893         Mat          pmat;
1894 
1895         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject *) &space);CHKERRQ(ierr);
1896         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1897         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject *) &space);CHKERRQ(ierr);
1898         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1899         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject *) &pmat);CHKERRQ(ierr);
1900         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1901       }
1902     }
1903   }
1904   PetscFunctionReturn(0);
1905 }
1906 
1907 #undef __FUNCT__
1908 #define __FUNCT__ "DMPlexSymmetrize"
1909 /*@
1910   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1911 
1912   Not collective
1913 
1914   Input Parameter:
1915 . mesh - The DMPlex
1916 
1917   Output Parameter:
1918 
1919   Note:
1920   This should be called after all calls to DMPlexSetCone()
1921 
1922   Level: beginner
1923 
1924 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1925 @*/
1926 PetscErrorCode DMPlexSymmetrize(DM dm)
1927 {
1928   DM_Plex    *mesh = (DM_Plex *) dm->data;
1929   PetscInt      *offsets;
1930   PetscInt       supportSize;
1931   PetscInt       pStart, pEnd, p;
1932   PetscErrorCode ierr;
1933 
1934   PetscFunctionBegin;
1935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1936   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1937   /* Calculate support sizes */
1938   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1939   for (p = pStart; p < pEnd; ++p) {
1940     PetscInt dof, off, c;
1941 
1942     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1943     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1944     for (c = off; c < off+dof; ++c) {
1945       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1946     }
1947   }
1948   for (p = pStart; p < pEnd; ++p) {
1949     PetscInt dof;
1950 
1951     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1952     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1953   }
1954   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1955   /* Calculate supports */
1956   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1957   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1958   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1959   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1960   for (p = pStart; p < pEnd; ++p) {
1961     PetscInt dof, off, c;
1962 
1963     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1964     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1965     for (c = off; c < off+dof; ++c) {
1966       const PetscInt q = mesh->cones[c];
1967       PetscInt       offS;
1968 
1969       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1970       mesh->supports[offS+offsets[q]] = p;
1971       ++offsets[q];
1972     }
1973   }
1974   ierr = PetscFree(offsets);CHKERRQ(ierr);
1975   PetscFunctionReturn(0);
1976 }
1977 
1978 #undef __FUNCT__
1979 #define __FUNCT__ "DMPlexSetDepth_Private"
1980 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1981 {
1982   PetscInt       d;
1983   PetscErrorCode ierr;
1984 
1985   PetscFunctionBegin;
1986   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1987   if (d < 0) {
1988     /* We are guaranteed that the point has a cone since the depth was not yet set */
1989     const PetscInt *cone = PETSC_NULL;
1990     PetscInt        dCone;
1991 
1992     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1993     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1994     d    = dCone+1;
1995     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1996   }
1997   *depth = d;
1998   PetscFunctionReturn(0);
1999 }
2000 
2001 #undef __FUNCT__
2002 #define __FUNCT__ "DMPlexStratify"
2003 /*@
2004   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2005   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2006   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2007   the DAG.
2008 
2009   Not collective
2010 
2011   Input Parameter:
2012 . mesh - The DMPlex
2013 
2014   Output Parameter:
2015 
2016   Notes:
2017   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2018   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2019 
2020   This should be called after all calls to DMPlexSymmetrize()
2021 
2022   Level: beginner
2023 
2024 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2025 @*/
2026 PetscErrorCode DMPlexStratify(DM dm)
2027 {
2028   DM_Plex    *mesh = (DM_Plex *) dm->data;
2029   PetscInt       pStart, pEnd, p;
2030   PetscInt       numRoots = 0, numLeaves = 0;
2031   PetscErrorCode ierr;
2032 
2033   PetscFunctionBegin;
2034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2035   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2036   /* Calculate depth */
2037   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2038   /* Initialize roots and count leaves */
2039   for (p = pStart; p < pEnd; ++p) {
2040     PetscInt coneSize, supportSize;
2041 
2042     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2043     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2044     if (!coneSize && supportSize) {
2045       ++numRoots;
2046       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2047     } else if (!supportSize && coneSize) {
2048       ++numLeaves;
2049     } else if (!supportSize && !coneSize) {
2050       /* Isolated points */
2051       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2052     }
2053   }
2054   if (numRoots + numLeaves == (pEnd - pStart)) {
2055     for (p = pStart; p < pEnd; ++p) {
2056       PetscInt coneSize, supportSize;
2057 
2058       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2059       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2060       if (!supportSize && coneSize) {
2061         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2062       }
2063     }
2064   } else {
2065     /* This might be slow since lookup is not fast */
2066     for (p = pStart; p < pEnd; ++p) {
2067       PetscInt depth;
2068 
2069       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2070     }
2071   }
2072   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2073   PetscFunctionReturn(0);
2074 }
2075 
2076 #undef __FUNCT__
2077 #define __FUNCT__ "DMPlexGetJoin"
2078 /*@C
2079   DMPlexGetJoin - Get an array for the join of the set of points
2080 
2081   Not Collective
2082 
2083   Input Parameters:
2084 + dm - The DMPlex object
2085 . numPoints - The number of input points for the join
2086 - points - The input points
2087 
2088   Output Parameters:
2089 + numCoveredPoints - The number of points in the join
2090 - coveredPoints - The points in the join
2091 
2092   Level: intermediate
2093 
2094   Note: Currently, this is restricted to a single level join
2095 
2096 .keywords: mesh
2097 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2098 @*/
2099 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2100 {
2101   DM_Plex    *mesh = (DM_Plex *) dm->data;
2102   PetscInt      *join[2];
2103   PetscInt       joinSize, i = 0;
2104   PetscInt       dof, off, p, c, m;
2105   PetscErrorCode ierr;
2106 
2107   PetscFunctionBegin;
2108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2109   PetscValidPointer(points, 2);
2110   PetscValidPointer(numCoveredPoints, 3);
2111   PetscValidPointer(coveredPoints, 4);
2112   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2113   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2114   /* Copy in support of first point */
2115   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2116   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2117   for (joinSize = 0; joinSize < dof; ++joinSize) {
2118     join[i][joinSize] = mesh->supports[off+joinSize];
2119   }
2120   /* Check each successive support */
2121   for (p = 1; p < numPoints; ++p) {
2122     PetscInt newJoinSize = 0;
2123 
2124     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2125     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2126     for (c = 0; c < dof; ++c) {
2127       const PetscInt point = mesh->supports[off+c];
2128 
2129       for (m = 0; m < joinSize; ++m) {
2130         if (point == join[i][m]) {
2131           join[1-i][newJoinSize++] = point;
2132           break;
2133         }
2134       }
2135     }
2136     joinSize = newJoinSize;
2137     i = 1-i;
2138   }
2139   *numCoveredPoints = joinSize;
2140   *coveredPoints    = join[i];
2141   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2142   PetscFunctionReturn(0);
2143 }
2144 
2145 #undef __FUNCT__
2146 #define __FUNCT__ "DMPlexRestoreJoin"
2147 /*@C
2148   DMPlexRestoreJoin - Restore an array for the join of the set of points
2149 
2150   Not Collective
2151 
2152   Input Parameters:
2153 + dm - The DMPlex object
2154 . numPoints - The number of input points for the join
2155 - points - The input points
2156 
2157   Output Parameters:
2158 + numCoveredPoints - The number of points in the join
2159 - coveredPoints - The points in the join
2160 
2161   Level: intermediate
2162 
2163 .keywords: mesh
2164 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2165 @*/
2166 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2167 {
2168   PetscErrorCode ierr;
2169 
2170   PetscFunctionBegin;
2171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2172   PetscValidPointer(coveredPoints, 4);
2173   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2174   PetscFunctionReturn(0);
2175 }
2176 
2177 #undef __FUNCT__
2178 #define __FUNCT__ "DMPlexGetFullJoin"
2179 /*@C
2180   DMPlexGetFullJoin - Get an array for the join of the set of points
2181 
2182   Not Collective
2183 
2184   Input Parameters:
2185 + dm - The DMPlex object
2186 . numPoints - The number of input points for the join
2187 - points - The input points
2188 
2189   Output Parameters:
2190 + numCoveredPoints - The number of points in the join
2191 - coveredPoints - The points in the join
2192 
2193   Level: intermediate
2194 
2195 .keywords: mesh
2196 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2197 @*/
2198 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2199 {
2200   DM_Plex    *mesh = (DM_Plex *) dm->data;
2201   PetscInt      *offsets, **closures;
2202   PetscInt      *join[2];
2203   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2204   PetscInt       p, d, c, m;
2205   PetscErrorCode ierr;
2206 
2207   PetscFunctionBegin;
2208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2209   PetscValidPointer(points, 2);
2210   PetscValidPointer(numCoveredPoints, 3);
2211   PetscValidPointer(coveredPoints, 4);
2212 
2213   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2214   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2215   ierr = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2216   ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2217   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2218   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2219   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2220 
2221   for (p = 0; p < numPoints; ++p) {
2222     PetscInt closureSize;
2223 
2224     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2225     offsets[p*(depth+2)+0] = 0;
2226     for (d = 0; d < depth+1; ++d) {
2227       PetscInt pStart, pEnd, i;
2228 
2229       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2230       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2231         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2232           offsets[p*(depth+2)+d+1] = i;
2233           break;
2234         }
2235       }
2236       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2237     }
2238     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2239   }
2240   for (d = 0; d < depth+1; ++d) {
2241     PetscInt dof;
2242 
2243     /* Copy in support of first point */
2244     dof = offsets[d+1] - offsets[d];
2245     for (joinSize = 0; joinSize < dof; ++joinSize) {
2246       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2247     }
2248     /* Check each successive cone */
2249     for (p = 1; p < numPoints && joinSize; ++p) {
2250       PetscInt newJoinSize = 0;
2251 
2252       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2253       for (c = 0; c < dof; ++c) {
2254         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2255 
2256         for (m = 0; m < joinSize; ++m) {
2257           if (point == join[i][m]) {
2258             join[1-i][newJoinSize++] = point;
2259             break;
2260           }
2261         }
2262       }
2263       joinSize = newJoinSize;
2264       i = 1-i;
2265     }
2266     if (joinSize) break;
2267   }
2268   *numCoveredPoints = joinSize;
2269   *coveredPoints    = join[i];
2270   for (p = 0; p < numPoints; ++p) {
2271     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2272   }
2273   ierr = PetscFree(closures);CHKERRQ(ierr);
2274   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2275   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2276   PetscFunctionReturn(0);
2277 }
2278 
2279 #undef __FUNCT__
2280 #define __FUNCT__ "DMPlexGetMeet"
2281 /*@C
2282   DMPlexGetMeet - Get an array for the meet of the set of points
2283 
2284   Not Collective
2285 
2286   Input Parameters:
2287 + dm - The DMPlex object
2288 . numPoints - The number of input points for the meet
2289 - points - The input points
2290 
2291   Output Parameters:
2292 + numCoveredPoints - The number of points in the meet
2293 - coveredPoints - The points in the meet
2294 
2295   Level: intermediate
2296 
2297   Note: Currently, this is restricted to a single level meet
2298 
2299 .keywords: mesh
2300 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2301 @*/
2302 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2303 {
2304   DM_Plex    *mesh = (DM_Plex *) dm->data;
2305   PetscInt      *meet[2];
2306   PetscInt       meetSize, i = 0;
2307   PetscInt       dof, off, p, c, m;
2308   PetscErrorCode ierr;
2309 
2310   PetscFunctionBegin;
2311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2312   PetscValidPointer(points, 2);
2313   PetscValidPointer(numCoveringPoints, 3);
2314   PetscValidPointer(coveringPoints, 4);
2315   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2316   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2317   /* Copy in cone of first point */
2318   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2319   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2320   for (meetSize = 0; meetSize < dof; ++meetSize) {
2321     meet[i][meetSize] = mesh->cones[off+meetSize];
2322   }
2323   /* Check each successive cone */
2324   for (p = 1; p < numPoints; ++p) {
2325     PetscInt newMeetSize = 0;
2326 
2327     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2328     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2329     for (c = 0; c < dof; ++c) {
2330       const PetscInt point = mesh->cones[off+c];
2331 
2332       for (m = 0; m < meetSize; ++m) {
2333         if (point == meet[i][m]) {
2334           meet[1-i][newMeetSize++] = point;
2335           break;
2336         }
2337       }
2338     }
2339     meetSize = newMeetSize;
2340     i = 1-i;
2341   }
2342   *numCoveringPoints = meetSize;
2343   *coveringPoints    = meet[i];
2344   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2345   PetscFunctionReturn(0);
2346 }
2347 
2348 #undef __FUNCT__
2349 #define __FUNCT__ "DMPlexRestoreMeet"
2350 /*@C
2351   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2352 
2353   Not Collective
2354 
2355   Input Parameters:
2356 + dm - The DMPlex object
2357 . numPoints - The number of input points for the meet
2358 - points - The input points
2359 
2360   Output Parameters:
2361 + numCoveredPoints - The number of points in the meet
2362 - coveredPoints - The points in the meet
2363 
2364   Level: intermediate
2365 
2366 .keywords: mesh
2367 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2368 @*/
2369 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2370 {
2371   PetscErrorCode ierr;
2372 
2373   PetscFunctionBegin;
2374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2375   PetscValidPointer(coveredPoints, 4);
2376   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2377   PetscFunctionReturn(0);
2378 }
2379 
2380 #undef __FUNCT__
2381 #define __FUNCT__ "DMPlexGetFullMeet"
2382 /*@C
2383   DMPlexGetFullMeet - Get an array for the meet of the set of points
2384 
2385   Not Collective
2386 
2387   Input Parameters:
2388 + dm - The DMPlex object
2389 . numPoints - The number of input points for the meet
2390 - points - The input points
2391 
2392   Output Parameters:
2393 + numCoveredPoints - The number of points in the meet
2394 - coveredPoints - The points in the meet
2395 
2396   Level: intermediate
2397 
2398 .keywords: mesh
2399 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2400 @*/
2401 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2402 {
2403   DM_Plex    *mesh = (DM_Plex *) dm->data;
2404   PetscInt      *offsets, **closures;
2405   PetscInt      *meet[2];
2406   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2407   PetscInt       p, h, c, m;
2408   PetscErrorCode ierr;
2409 
2410   PetscFunctionBegin;
2411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2412   PetscValidPointer(points, 2);
2413   PetscValidPointer(numCoveredPoints, 3);
2414   PetscValidPointer(coveredPoints, 4);
2415 
2416   ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2417   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2418   ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2419   maxSize = PetscPowInt(mesh->maxConeSize,height);
2420   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2421   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2422 
2423   for (p = 0; p < numPoints; ++p) {
2424     PetscInt closureSize;
2425 
2426     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2427     offsets[p*(height+2)+0] = 0;
2428     for (h = 0; h < height+1; ++h) {
2429       PetscInt pStart, pEnd, i;
2430 
2431       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2432       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2433         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2434           offsets[p*(height+2)+h+1] = i;
2435           break;
2436         }
2437       }
2438       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2439     }
2440     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2441   }
2442   for (h = 0; h < height+1; ++h) {
2443     PetscInt dof;
2444 
2445     /* Copy in cone of first point */
2446     dof = offsets[h+1] - offsets[h];
2447     for (meetSize = 0; meetSize < dof; ++meetSize) {
2448       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2449     }
2450     /* Check each successive cone */
2451     for (p = 1; p < numPoints && meetSize; ++p) {
2452       PetscInt newMeetSize = 0;
2453 
2454       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2455       for (c = 0; c < dof; ++c) {
2456         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2457 
2458         for (m = 0; m < meetSize; ++m) {
2459           if (point == meet[i][m]) {
2460             meet[1-i][newMeetSize++] = point;
2461             break;
2462           }
2463         }
2464       }
2465       meetSize = newMeetSize;
2466       i = 1-i;
2467     }
2468     if (meetSize) break;
2469   }
2470   *numCoveredPoints = meetSize;
2471   *coveredPoints    = meet[i];
2472   for (p = 0; p < numPoints; ++p) {
2473     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2474   }
2475   ierr = PetscFree(closures);CHKERRQ(ierr);
2476   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2477   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2478   PetscFunctionReturn(0);
2479 }
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2483 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2484 {
2485   MPI_Comm       comm = ((PetscObject) dm)->comm;
2486   PetscInt       cellDim;
2487   PetscErrorCode ierr;
2488 
2489   PetscFunctionBegin;
2490   PetscValidPointer(numFaceVertices,3);
2491   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2492   switch (cellDim) {
2493   case 0:
2494     *numFaceVertices = 0;
2495     break;
2496   case 1:
2497     *numFaceVertices = 1;
2498     break;
2499   case 2:
2500     switch (numCorners) {
2501     case 3: /* triangle */
2502       *numFaceVertices = 2; /* Edge has 2 vertices */
2503       break;
2504     case 4: /* quadrilateral */
2505       *numFaceVertices = 2; /* Edge has 2 vertices */
2506       break;
2507     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2508       *numFaceVertices = 3; /* Edge has 3 vertices */
2509       break;
2510     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2511       *numFaceVertices = 3; /* Edge has 3 vertices */
2512       break;
2513     default:
2514       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2515     }
2516     break;
2517   case 3:
2518     switch (numCorners) {
2519     case 4: /* tetradehdron */
2520       *numFaceVertices = 3; /* Face has 3 vertices */
2521       break;
2522     case 6: /* tet cohesive cells */
2523       *numFaceVertices = 4; /* Face has 4 vertices */
2524       break;
2525     case 8: /* hexahedron */
2526       *numFaceVertices = 4; /* Face has 4 vertices */
2527       break;
2528     case 9: /* tet cohesive Lagrange cells */
2529       *numFaceVertices = 6; /* Face has 6 vertices */
2530       break;
2531     case 10: /* quadratic tetrahedron */
2532       *numFaceVertices = 6; /* Face has 6 vertices */
2533       break;
2534     case 12: /* hex cohesive Lagrange cells */
2535       *numFaceVertices = 6; /* Face has 6 vertices */
2536       break;
2537     case 18: /* quadratic tet cohesive Lagrange cells */
2538       *numFaceVertices = 6; /* Face has 6 vertices */
2539       break;
2540     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2541       *numFaceVertices = 9; /* Face has 9 vertices */
2542       break;
2543     default:
2544       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2545     }
2546     break;
2547   default:
2548     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2549   }
2550   PetscFunctionReturn(0);
2551 }
2552 
2553 #undef __FUNCT__
2554 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2555 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2556 {
2557   const PetscInt maxFaceCases = 30;
2558   PetscInt       numFaceCases = 0;
2559   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2560   PetscInt      *off, *adj;
2561   PetscInt      *neighborCells, *tmpClosure;
2562   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2563   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2564   PetscErrorCode ierr;
2565 
2566   PetscFunctionBegin;
2567   /* For parallel partitioning, I think you have to communicate supports */
2568   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2569   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2570   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2571   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2572   if (cEnd - cStart == 0) {
2573     if (numVertices) *numVertices = 0;
2574     if (offsets)     *offsets     = PETSC_NULL;
2575     if (adjacency)   *adjacency   = PETSC_NULL;
2576     PetscFunctionReturn(0);
2577   }
2578   numCells = cEnd - cStart;
2579   /* Setup face recognition */
2580   {
2581     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
2582 
2583     for (c = cStart; c < cEnd; ++c) {
2584       PetscInt corners;
2585 
2586       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2587       if (!cornersSeen[corners]) {
2588         PetscInt nFV;
2589 
2590         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2591         cornersSeen[corners] = 1;
2592         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2593         numFaceVertices[numFaceCases++] = nFV;
2594       }
2595     }
2596   }
2597   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2598   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2599   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2600   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2601   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2602   /* Count neighboring cells */
2603   for (cell = cStart; cell < cEnd; ++cell) {
2604     PetscInt numNeighbors = maxNeighbors, n;
2605 
2606     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2607     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2608     for (n = 0; n < numNeighbors; ++n) {
2609       PetscInt        cellPair[2] = {cell, neighborCells[n]};
2610       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2611       PetscInt        meetSize    = 0;
2612       const PetscInt *meet        = PETSC_NULL;
2613 
2614       if (cellPair[0] == cellPair[1]) continue;
2615       if (!found) {
2616         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2617         if (meetSize) {
2618           PetscInt f;
2619 
2620           for (f = 0; f < numFaceCases; ++f) {
2621             if (numFaceVertices[f] == meetSize) {
2622               found = PETSC_TRUE;
2623               break;
2624             }
2625           }
2626         }
2627         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2628       }
2629       if (found) {
2630         ++off[cell-cStart+1];
2631       }
2632     }
2633   }
2634   /* Prefix sum */
2635   for (cell = 1; cell <= numCells; ++cell) {
2636     off[cell] += off[cell-1];
2637   }
2638   if (adjacency) {
2639     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2640     /* Get neighboring cells */
2641     for (cell = cStart; cell < cEnd; ++cell) {
2642       PetscInt numNeighbors = maxNeighbors, n;
2643       PetscInt cellOffset   = 0;
2644 
2645       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2646       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2647       for (n = 0; n < numNeighbors; ++n) {
2648         PetscInt        cellPair[2] = {cell, neighborCells[n]};
2649         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2650         PetscInt        meetSize    = 0;
2651         const PetscInt *meet        = PETSC_NULL;
2652 
2653         if (cellPair[0] == cellPair[1]) continue;
2654         if (!found) {
2655           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2656           if (meetSize) {
2657             PetscInt f;
2658 
2659             for (f = 0; f < numFaceCases; ++f) {
2660               if (numFaceVertices[f] == meetSize) {
2661                 found = PETSC_TRUE;
2662                 break;
2663               }
2664             }
2665           }
2666           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2667         }
2668         if (found) {
2669           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2670           ++cellOffset;
2671         }
2672       }
2673     }
2674   }
2675   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2676   if (numVertices) *numVertices = numCells;
2677   if (offsets)     *offsets     = off;
2678   if (adjacency)   *adjacency   = adj;
2679   PetscFunctionReturn(0);
2680 }
2681 
2682 #if defined(PETSC_HAVE_CHACO)
2683 #if defined(PETSC_HAVE_UNISTD_H)
2684 #include <unistd.h>
2685 #endif
2686 /* Chaco does not have an include file */
2687 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2688                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2689                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2690                        int mesh_dims[3], double *goal, int global_method, int local_method,
2691                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2692 
2693 extern int FREE_GRAPH;
2694 
2695 #undef __FUNCT__
2696 #define __FUNCT__ "DMPlexPartition_Chaco"
2697 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2698 {
2699   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2700   MPI_Comm comm = ((PetscObject) dm)->comm;
2701   int nvtxs = numVertices;                /* number of vertices in full graph */
2702   int *vwgts = NULL;                      /* weights for all vertices */
2703   float *ewgts = NULL;                    /* weights for all edges */
2704   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2705   char *outassignname = NULL;             /*  name of assignment output file */
2706   char *outfilename = NULL;               /* output file name */
2707   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2708   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2709   int mesh_dims[3];                       /* dimensions of mesh of processors */
2710   double *goal = NULL;                    /* desired set sizes for each set */
2711   int global_method = 1;                  /* global partitioning algorithm */
2712   int local_method = 1;                   /* local partitioning algorithm */
2713   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2714   int vmax = 200;                         /* how many vertices to coarsen down to? */
2715   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2716   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2717   long seed = 123636512;                  /* for random graph mutations */
2718   short int *assignment;                  /* Output partition */
2719   int fd_stdout, fd_pipe[2];
2720   PetscInt      *points;
2721   PetscMPIInt    commSize;
2722   int            i, v, p;
2723   PetscErrorCode ierr;
2724 
2725   PetscFunctionBegin;
2726   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2727   if (!numVertices) {
2728     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2729     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2730     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2731     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2732     PetscFunctionReturn(0);
2733   }
2734   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2735   for (i = 0; i < start[numVertices]; ++i) {
2736     ++adjacency[i];
2737   }
2738   if (global_method == INERTIAL_METHOD) {
2739     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2740     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2741   }
2742   mesh_dims[0] = commSize;
2743   mesh_dims[1] = 1;
2744   mesh_dims[2] = 1;
2745   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2746   /* Chaco outputs to stdout. We redirect this to a buffer. */
2747   /* TODO: check error codes for UNIX calls */
2748 #if defined(PETSC_HAVE_UNISTD_H)
2749   {
2750     int piperet;
2751     piperet = pipe(fd_pipe);
2752     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2753     fd_stdout = dup(1);
2754     close(1);
2755     dup2(fd_pipe[1], 1);
2756   }
2757 #endif
2758   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2759                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2760                    vmax, ndims, eigtol, seed);
2761 #if defined(PETSC_HAVE_UNISTD_H)
2762   {
2763     char msgLog[10000];
2764     int  count;
2765 
2766     fflush(stdout);
2767     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2768     if (count < 0) count = 0;
2769     msgLog[count] = 0;
2770     close(1);
2771     dup2(fd_stdout, 1);
2772     close(fd_stdout);
2773     close(fd_pipe[0]);
2774     close(fd_pipe[1]);
2775     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2776   }
2777 #endif
2778   /* Convert to PetscSection+IS */
2779   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2780   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2781   for (v = 0; v < nvtxs; ++v) {
2782     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2783   }
2784   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2785   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2786   for (p = 0, i = 0; p < commSize; ++p) {
2787     for (v = 0; v < nvtxs; ++v) {
2788       if (assignment[v] == p) points[i++] = v;
2789     }
2790   }
2791   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2792   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2793   if (global_method == INERTIAL_METHOD) {
2794     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2795   }
2796   ierr = PetscFree(assignment);CHKERRQ(ierr);
2797   for (i = 0; i < start[numVertices]; ++i) {
2798     --adjacency[i];
2799   }
2800   PetscFunctionReturn(0);
2801 }
2802 #endif
2803 
2804 #if defined(PETSC_HAVE_PARMETIS)
2805 #undef __FUNCT__
2806 #define __FUNCT__ "DMPlexPartition_ParMetis"
2807 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2808 {
2809   PetscFunctionBegin;
2810   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2811   PetscFunctionReturn(0);
2812 }
2813 #endif
2814 
2815 #undef __FUNCT__
2816 #define __FUNCT__ "DMPlexEnlargePartition"
2817 /* Expand the partition by BFS on the adjacency graph */
2818 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2819 {
2820   PetscHashI      h;
2821   const PetscInt *points;
2822   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2823   PetscInt        pStart, pEnd, part, q;
2824   PetscErrorCode  ierr;
2825 
2826   PetscFunctionBegin;
2827   PetscHashICreate(h);
2828   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2829   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2830   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2831   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2832   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2833   for (part = pStart; part < pEnd; ++part) {
2834     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2835 
2836     PetscHashIClear(h);
2837     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2838     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2839     /* Add all existing points to h */
2840     for (p = 0; p < numPoints; ++p) {
2841       const PetscInt point = points[off+p];
2842       PetscHashIAdd(h, point, 1);
2843     }
2844     PetscHashISize(h, nP);
2845     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2846     /* Add all points in next BFS level */
2847     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2848     for (p = 0; p < numPoints; ++p) {
2849       const PetscInt point = points[off+p];
2850       PetscInt s = start[point], e = start[point+1], a;
2851 
2852       for (a = s; a < e; ++a) {
2853         PetscHashIAdd(h, adjacency[a], 1);
2854       }
2855     }
2856     PetscHashISize(h, numNewPoints);
2857     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2858     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2859     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2860     totPoints += numNewPoints;
2861   }
2862   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2863   PetscHashIDestroy(h);
2864   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2865   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2866   for (part = pStart, q = 0; part < pEnd; ++part) {
2867     PetscInt numPoints, p;
2868 
2869     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2870     for (p = 0; p < numPoints; ++p, ++q) {
2871       newPoints[q] = tmpPoints[part][p];
2872     }
2873     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2874   }
2875   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2876   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2877   PetscFunctionReturn(0);
2878 }
2879 
2880 #undef __FUNCT__
2881 #define __FUNCT__ "DMPlexCreatePartition"
2882 /*
2883   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2884 
2885   Collective on DM
2886 
2887   Input Parameters:
2888   + dm - The DM
2889   . height - The height for points in the partition
2890   - enlarge - Expand each partition with neighbors
2891 
2892   Output Parameters:
2893   + partSection - The PetscSection giving the division of points by partition
2894   . partition - The list of points by partition
2895   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2896   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2897 
2898   Level: developer
2899 
2900 .seealso DMPlexDistribute()
2901 */
2902 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2903 {
2904   PetscMPIInt    size;
2905   PetscErrorCode ierr;
2906 
2907   PetscFunctionBegin;
2908   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2909   *origPartSection = PETSC_NULL;
2910   *origPartition   = PETSC_NULL;
2911   if (size == 1) {
2912     PetscInt *points;
2913     PetscInt  cStart, cEnd, c;
2914 
2915     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2916     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2917     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2918     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2919     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2920     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2921     for (c = cStart; c < cEnd; ++c) {
2922       points[c] = c;
2923     }
2924     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2925     PetscFunctionReturn(0);
2926   }
2927   if (height == 0) {
2928     PetscInt  numVertices;
2929     PetscInt *start     = PETSC_NULL;
2930     PetscInt *adjacency = PETSC_NULL;
2931 
2932     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2933     if (1) {
2934 #if defined(PETSC_HAVE_CHACO)
2935       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2936 #endif
2937     } else {
2938 #if defined(PETSC_HAVE_PARMETIS)
2939       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2940 #endif
2941     }
2942     if (enlarge) {
2943       *origPartSection = *partSection;
2944       *origPartition   = *partition;
2945       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2946     }
2947     ierr = PetscFree(start);CHKERRQ(ierr);
2948     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2949 # if 0
2950   } else if (height == 1) {
2951     /* Build the dual graph for faces and partition the hypergraph */
2952     PetscInt numEdges;
2953 
2954     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2955     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2956     destroyCSR(numEdges, start, adjacency);
2957 #endif
2958   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2959   PetscFunctionReturn(0);
2960 }
2961 
2962 #undef __FUNCT__
2963 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2964 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2965 {
2966   /* const PetscInt  height = 0; */
2967   const PetscInt *partArray;
2968   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2969   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2970   PetscErrorCode  ierr;
2971 
2972   PetscFunctionBegin;
2973   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2974   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2975   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2976   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2977   for (rank = rStart; rank < rEnd; ++rank) {
2978     PetscInt partSize = 0;
2979     PetscInt numPoints, offset, p;
2980 
2981     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2982     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2983     for (p = 0; p < numPoints; ++p) {
2984       PetscInt  point   = partArray[offset+p], closureSize, c;
2985       PetscInt *closure = PETSC_NULL;
2986 
2987       /* TODO Include support for height > 0 case */
2988       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2989       /* Merge into existing points */
2990       if (partSize+closureSize > maxPartSize) {
2991         PetscInt *tmpPoints;
2992 
2993         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2994         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2995         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2996         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2997         partPoints = tmpPoints;
2998       }
2999       for (c = 0; c < closureSize; ++c) {
3000         partPoints[partSize+c] = closure[c*2];
3001       }
3002       partSize += closureSize;
3003       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3004       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3005     }
3006     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3007   }
3008   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3009   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3010   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3011 
3012   for (rank = rStart; rank < rEnd; ++rank) {
3013     PetscInt partSize = 0, newOffset;
3014     PetscInt numPoints, offset, p;
3015 
3016     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3017     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3018     for (p = 0; p < numPoints; ++p) {
3019       PetscInt  point   = partArray[offset+p], closureSize, c;
3020       PetscInt *closure = PETSC_NULL;
3021 
3022       /* TODO Include support for height > 0 case */
3023       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3024       /* Merge into existing points */
3025       for (c = 0; c < closureSize; ++c) {
3026         partPoints[partSize+c] = closure[c*2];
3027       }
3028       partSize += closureSize;
3029       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3030       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3031     }
3032     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3033     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3034   }
3035   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3036   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3037   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3038   PetscFunctionReturn(0);
3039 }
3040 
3041 #undef __FUNCT__
3042 #define __FUNCT__ "DMPlexDistributeField"
3043 /*
3044   Input Parameters:
3045 . originalSection
3046 , originalVec
3047 
3048   Output Parameters:
3049 . newSection
3050 . newVec
3051 */
3052 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3053 {
3054   PetscSF         fieldSF;
3055   PetscInt       *remoteOffsets, fieldSize;
3056   PetscScalar    *originalValues, *newValues;
3057   PetscErrorCode  ierr;
3058 
3059   PetscFunctionBegin;
3060   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3061 
3062   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3063   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3064   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3065 
3066   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3067   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3068   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3069   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3070   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3071   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3072   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3073   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3074   PetscFunctionReturn(0);
3075 }
3076 
3077 #undef __FUNCT__
3078 #define __FUNCT__ "DMPlexDistribute"
3079 /*@C
3080   DMPlexDistribute - Distributes the mesh and any associated sections.
3081 
3082   Not Collective
3083 
3084   Input Parameter:
3085 + dm  - The original DMPlex object
3086 . partitioner - The partitioning package, or NULL for the default
3087 - overlap - The overlap of partitions, 0 is the default
3088 
3089   Output Parameter:
3090 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3091 
3092   Note: If the mesh was not distributed, the return value is PETSC_NULL
3093 
3094   Level: intermediate
3095 
3096 .keywords: mesh, elements
3097 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3098 @*/
3099 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3100 {
3101   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3102   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3103   const PetscInt height = 0;
3104   PetscInt       dim, numRemoteRanks;
3105   IS             origCellPart,        cellPart,        part;
3106   PetscSection   origCellPartSection, cellPartSection, partSection;
3107   PetscSFNode   *remoteRanks;
3108   PetscSF        partSF, pointSF, coneSF;
3109   ISLocalToGlobalMapping renumbering;
3110   PetscSection   originalConeSection, newConeSection;
3111   PetscInt      *remoteOffsets;
3112   PetscInt      *cones, *newCones, newConesSize;
3113   PetscBool      flg;
3114   PetscMPIInt    rank, numProcs, p;
3115   PetscErrorCode ierr;
3116 
3117   PetscFunctionBegin;
3118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3119   PetscValidPointer(dmParallel,4);
3120   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3121   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3122   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3123   *dmParallel = PETSC_NULL;
3124   if (numProcs == 1) PetscFunctionReturn(0);
3125 
3126   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3127   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3128   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3129   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3130   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3131   if (!rank) {
3132     numRemoteRanks = numProcs;
3133   } else {
3134     numRemoteRanks = 0;
3135   }
3136   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3137   for (p = 0; p < numRemoteRanks; ++p) {
3138     remoteRanks[p].rank  = p;
3139     remoteRanks[p].index = 0;
3140   }
3141   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3142   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3143   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3144   if (flg) {
3145     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3146     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3147     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3148     if (origCellPart) {
3149       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3150       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3151       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3152     }
3153     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3154   }
3155   /* Close the partition over the mesh */
3156   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3157   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3158   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3159   /* Create new mesh */
3160   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3161   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3162   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3163   pmesh = (DM_Plex *) (*dmParallel)->data;
3164   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3165   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3166   if (flg) {
3167     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3168     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3169     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3170     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3171     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3172     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3173   }
3174   /* Distribute cone section */
3175   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3176   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3177   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3178   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3179   {
3180     PetscInt pStart, pEnd, p;
3181 
3182     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3183     for (p = pStart; p < pEnd; ++p) {
3184       PetscInt coneSize;
3185       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3186       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3187     }
3188   }
3189   /* Communicate and renumber cones */
3190   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3191   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3192   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3193   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3194   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3195   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3196   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3197   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3198   if (flg) {
3199     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3200     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3201     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3202     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3203     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3204   }
3205   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3206   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3207   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3208   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3209   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3210   /* Create supports and stratify sieve */
3211   {
3212     PetscInt pStart, pEnd;
3213 
3214     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3215     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3216   }
3217   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3218   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3219   /* Distribute Coordinates */
3220   {
3221     PetscSection originalCoordSection, newCoordSection;
3222     Vec          originalCoordinates, newCoordinates;
3223     const char  *name;
3224 
3225     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3226     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3227     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3228     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3229     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3230     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3231 
3232     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3233     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3234     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3235   }
3236   /* Distribute labels */
3237   {
3238     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3239     PetscInt   numLabels = 0, l;
3240 
3241     /* Bcast number of labels */
3242     while (next) {++numLabels; next = next->next;}
3243     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3244     next = mesh->labels;
3245     for (l = 0; l < numLabels; ++l) {
3246       DMLabel         newLabel;
3247       const PetscInt *partArray;
3248       char           *name;
3249       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3250       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3251       PetscInt        nameSize, s, p;
3252       PetscBool       isdepth;
3253       size_t          len = 0;
3254 
3255       /* Bcast name (could filter for no points) */
3256       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3257       nameSize = len;
3258       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3259       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3260       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3261       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3262       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3263       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3264       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3265       newLabel->name = name;
3266       /* Bcast numStrata (could filter for no points in stratum) */
3267       if (!rank) {newLabel->numStrata = next->numStrata;}
3268       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3269       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3270                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3271                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3272       /* Bcast stratumValues (could filter for no points in stratum) */
3273       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3274       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3275       /* Find size on each process and Scatter */
3276       if (!rank) {
3277         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3278         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3279         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3280         for (s = 0; s < next->numStrata; ++s) {
3281           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3282             const PetscInt point = next->points[p];
3283             PetscInt       proc;
3284 
3285             for (proc = 0; proc < numProcs; ++proc) {
3286               PetscInt dof, off, pPart;
3287 
3288               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3289               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3290               for (pPart = off; pPart < off+dof; ++pPart) {
3291                 if (partArray[pPart] == point) {
3292                   ++stratumSizes[proc*next->numStrata+s];
3293                   break;
3294                 }
3295               }
3296             }
3297           }
3298         }
3299         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3300       }
3301       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3302       /* Calculate stratumOffsets */
3303       newLabel->stratumOffsets[0] = 0;
3304       for (s = 0; s < newLabel->numStrata; ++s) {
3305         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3306       }
3307       /* Pack points and Scatter */
3308       if (!rank) {
3309         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3310         displs[0] = 0;
3311         for (p = 0; p < numProcs; ++p) {
3312           sendcnts[p] = 0;
3313           for (s = 0; s < next->numStrata; ++s) {
3314             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3315           }
3316           offsets[p]  = displs[p];
3317           displs[p+1] = displs[p] + sendcnts[p];
3318         }
3319         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3320         for (s = 0; s < next->numStrata; ++s) {
3321           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3322             const PetscInt point = next->points[p];
3323             PetscInt       proc;
3324 
3325             for (proc = 0; proc < numProcs; ++proc) {
3326               PetscInt dof, off, pPart;
3327 
3328               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3329               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3330               for (pPart = off; pPart < off+dof; ++pPart) {
3331                 if (partArray[pPart] == point) {
3332                   points[offsets[proc]++] = point;
3333                   break;
3334                 }
3335               }
3336             }
3337           }
3338         }
3339       }
3340       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3341       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3342       ierr = PetscFree(points);CHKERRQ(ierr);
3343       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3344       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3345       /* Renumber points */
3346       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3347       /* Sort points */
3348       for (s = 0; s < newLabel->numStrata; ++s) {
3349         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3350       }
3351       /* Insert into list */
3352       if (newNext) {
3353         newNext->next = newLabel;
3354       } else {
3355         pmesh->labels = newLabel;
3356       }
3357       newNext = newLabel;
3358       if (!rank) {next = next->next;}
3359     }
3360   }
3361   /* Cleanup Partition */
3362   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3363   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3364   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3365   ierr = ISDestroy(&part);CHKERRQ(ierr);
3366   /* Create point SF for parallel mesh */
3367   {
3368     const PetscInt *leaves;
3369     PetscSFNode    *remotePoints, *rowners, *lowners;
3370     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3371     PetscInt        pStart, pEnd;
3372 
3373     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3374     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3375     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3376     for (p=0; p<numRoots; p++) {
3377       rowners[p].rank = -1;
3378       rowners[p].index = -1;
3379     }
3380     if (origCellPart) {
3381       /* Make sure cells in the original partition are not assigned to other procs */
3382       const PetscInt *origCells;
3383 
3384       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3385       for (p = 0; p < numProcs; ++p) {
3386         PetscInt dof, off, d;
3387 
3388         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3389         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3390         for (d = off; d < off+dof; ++d) {
3391           rowners[origCells[d]].rank = p;
3392         }
3393       }
3394       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3395     }
3396     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3397     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3398 
3399     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3400     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3401     for (p = 0; p < numLeaves; ++p) {
3402       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3403         lowners[p].rank = rank;
3404         lowners[p].index = leaves ? leaves[p] : p;
3405       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3406         lowners[p].rank = -2;
3407         lowners[p].index = -2;
3408       }
3409     }
3410     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3411       rowners[p].rank = -3;
3412       rowners[p].index = -3;
3413     }
3414     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3415     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3416     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3417     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3418     for (p = 0; p < numLeaves; ++p) {
3419       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3420       if (lowners[p].rank != rank) ++numGhostPoints;
3421     }
3422     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3423     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3424     for (p = 0, gp = 0; p < numLeaves; ++p) {
3425       if (lowners[p].rank != rank) {
3426         ghostPoints[gp]       = leaves ? leaves[p] : p;
3427         remotePoints[gp].rank  = lowners[p].rank;
3428         remotePoints[gp].index = lowners[p].index;
3429         ++gp;
3430       }
3431     }
3432     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3433     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3434     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3435   }
3436   /* Cleanup */
3437   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3438   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3439   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3440   PetscFunctionReturn(0);
3441 }
3442 
3443 #undef __FUNCT__
3444 #define __FUNCT__ "DMPlexRenumber_Private"
3445 /*
3446   Reasons to renumber:
3447 
3448   1) Permute points, e.g. bandwidth reduction (Renumber)
3449 
3450     a) Must not mix strata
3451 
3452   2) Shift numbers for point insertion (Shift)
3453 
3454     a) Want operation brken into parts so that insertion can be interleaved
3455 
3456   renumbering - An IS which provides the new numbering
3457 */
3458 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3459 {
3460   PetscFunctionBegin;
3461   PetscFunctionReturn(0);
3462 }
3463 
3464 #undef __FUNCT__
3465 #define __FUNCT__ "DMPlexShiftPoint_Private"
3466 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3467 {
3468   if (depth < 0) return p;
3469   /* Cells    */ if (p < depthEnd[depth])   return p;
3470   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3471   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3472   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3473 }
3474 
3475 #undef __FUNCT__
3476 #define __FUNCT__ "DMPlexShiftSizes_Private"
3477 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3478 {
3479   PetscInt      *depthEnd;
3480   PetscInt       depth = 0, d, pStart, pEnd, p;
3481   PetscErrorCode ierr;
3482 
3483   PetscFunctionBegin;
3484   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3485   if (depth < 0) PetscFunctionReturn(0);
3486   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3487   /* Step 1: Expand chart */
3488   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3489   for (d = 0; d <= depth; ++d) {
3490     pEnd += depthShift[d];
3491     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3492   }
3493   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3494   /* Step 2: Set cone and support sizes */
3495   for (d = 0; d <= depth; ++d) {
3496     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3497     for (p = pStart; p < pEnd; ++p) {
3498       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3499       PetscInt size;
3500 
3501       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3502       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3503       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3504       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3505     }
3506   }
3507   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3508   PetscFunctionReturn(0);
3509 }
3510 
3511 #undef __FUNCT__
3512 #define __FUNCT__ "DMPlexShiftPoints_Private"
3513 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3514 {
3515   PetscInt      *depthEnd, *newpoints;
3516   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3517   PetscErrorCode ierr;
3518 
3519   PetscFunctionBegin;
3520   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3521   if (depth < 0) PetscFunctionReturn(0);
3522   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3523   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3524   for (d = 0; d <= depth; ++d) {
3525     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3526   }
3527   /* Step 5: Set cones and supports */
3528   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3529   for (p = pStart; p < pEnd; ++p) {
3530     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3531     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3532 
3533     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3534     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3535     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3536     for (i = 0; i < size; ++i) {
3537       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3538     }
3539     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3540     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3541     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3542     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3543     for (i = 0; i < size; ++i) {
3544       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3545     }
3546     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3547   }
3548   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3549   PetscFunctionReturn(0);
3550 }
3551 
3552 #undef __FUNCT__
3553 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3554 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3555 {
3556   PetscSection   coordSection, newCoordSection;
3557   Vec            coordinates;
3558   PetscInt      *depthEnd;
3559   PetscInt       dim, depth = 0, d, vStart, vEnd, v;
3560   PetscErrorCode ierr;
3561 
3562   PetscFunctionBegin;
3563   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3564   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3565   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3566   for (d = 0; d <= depth; ++d) {
3567     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3568   }
3569   /* Step 8: Convert coordinates */
3570   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3571   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3572   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3573   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3574   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3575   ierr = PetscSectionSetChart(newCoordSection, DMPlexShiftPoint_Private(vStart, depth, depthEnd, depthShift), DMPlexShiftPoint_Private(vEnd, depth, depthEnd, depthShift));CHKERRQ(ierr);
3576   for (v = vStart; v < vEnd; ++v) {
3577     const PetscInt newv = DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift);
3578     ierr = PetscSectionSetDof(newCoordSection, newv, dim);CHKERRQ(ierr);
3579     ierr = PetscSectionSetFieldDof(newCoordSection, newv, 0, dim);CHKERRQ(ierr);
3580   }
3581   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3582   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3583   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3584   ierr = DMSetCoordinatesLocal(dmNew, coordinates);CHKERRQ(ierr);
3585   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3586   PetscFunctionReturn(0);
3587 }
3588 
3589 #undef __FUNCT__
3590 #define __FUNCT__ "DMPlexShiftSF_Private"
3591 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3592 {
3593   PetscInt          *depthEnd;
3594   PetscInt           depth = 0, d;
3595   PetscSF            sfPoint, sfPointNew;
3596   const PetscSFNode *remotePoints;
3597   PetscSFNode       *gremotePoints;
3598   const PetscInt    *localPoints;
3599   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3600   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3601   PetscMPIInt        numProcs;
3602   PetscErrorCode     ierr;
3603 
3604   PetscFunctionBegin;
3605   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3606   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3607   for (d = 0; d <= depth; ++d) {
3608     totShift += depthShift[d];
3609     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3610   }
3611   /* Step 9: Convert pointSF */
3612   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3613   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3614   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3615   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3616   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3617   if (numRoots >= 0) {
3618     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3619     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3620     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3621     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3622     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3623     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3624     for (l = 0; l < numLeaves; ++l) {
3625       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3626       gremotePoints[l].rank  = remotePoints[l].rank;
3627       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3628     }
3629     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3630     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3631   }
3632   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3633   PetscFunctionReturn(0);
3634 }
3635 
3636 #undef __FUNCT__
3637 #define __FUNCT__ "DMPlexShiftLabels_Private"
3638 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3639 {
3640   PetscSF        sfPoint;
3641   DMLabel        vtkLabel, ghostLabel;
3642   PetscInt      *depthEnd;
3643   const PetscSFNode *leafRemote;
3644   const PetscInt    *leafLocal;
3645   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3646   PetscMPIInt    rank;
3647   PetscErrorCode ierr;
3648 
3649   PetscFunctionBegin;
3650   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3651   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3652   for (d = 0; d <= depth; ++d) {
3653     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3654   }
3655   /* Step 10: Convert labels */
3656   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3657   for (l = 0; l < numLabels; ++l) {
3658     DMLabel         label, newlabel;
3659     const char     *lname;
3660     PetscBool       isDepth;
3661     IS              valueIS;
3662     const PetscInt *values;
3663     PetscInt        numValues, val;
3664 
3665     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3666     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3667     if (isDepth) continue;
3668     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3669     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3670     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3671     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3672     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3673     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3674     for (val = 0; val < numValues; ++val) {
3675       IS              pointIS;
3676       const PetscInt *points;
3677       PetscInt        numPoints, p;
3678 
3679       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3680       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3681       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3682       for (p = 0; p < numPoints; ++p) {
3683         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3684 
3685         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3686       }
3687       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3688       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3689     }
3690     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3691     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3692   }
3693   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3694   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3695   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3696   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3697   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3698   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3699   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3700   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3701   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3702   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3703   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3704     for (; c < leafLocal[l] && c < cEnd; ++c) {
3705       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3706     }
3707     if (leafLocal[l] >= cEnd) break;
3708     if (leafRemote[l].rank == rank) {
3709       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3710     } else {
3711       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3712     }
3713   }
3714   for (; c < cEnd; ++c) {
3715     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3716   }
3717   if (0) {
3718     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3719     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3720     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3721   }
3722   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3723   for (f = fStart; f < fEnd; ++f) {
3724     PetscInt numCells;
3725 
3726     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3727     if (numCells < 2) {
3728       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3729     } else {
3730       const PetscInt *cells = PETSC_NULL;
3731       PetscInt        vA, vB;
3732 
3733       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3734       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3735       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3736       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3737     }
3738   }
3739   if (0) {
3740     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3741     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3742     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3743   }
3744   PetscFunctionReturn(0);
3745 }
3746 
3747 #undef __FUNCT__
3748 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3749 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3750 {
3751   DMLabel         label;
3752   IS              valueIS;
3753   const PetscInt *values;
3754   PetscInt       *depthShift;
3755   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3756   PetscErrorCode  ierr;
3757 
3758   PetscFunctionBegin;
3759   /* Count ghost cells */
3760   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3761   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3762   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3763   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3764   *numGhostCells = 0;
3765   for (fs = 0; fs < numFS; ++fs) {
3766     PetscInt numBdFaces;
3767 
3768     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3769     *numGhostCells += numBdFaces;
3770   }
3771   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3772   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3773   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3774   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3775   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3776   /* Step 3: Set cone/support sizes for new points */
3777   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3778   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3779     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3780   }
3781   for (fs = 0; fs < numFS; ++fs) {
3782     IS              faceIS;
3783     const PetscInt *faces;
3784     PetscInt        numFaces, f;
3785 
3786     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3787     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3788     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3789     for (f = 0; f < numFaces; ++f) {
3790       PetscInt size;
3791 
3792       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3793       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3794       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3795     }
3796     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3797     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3798   }
3799   /* Step 4: Setup ghosted DM */
3800   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3801   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3802   /* Step 6: Set cones and supports for new points */
3803   ghostCell = cEnd;
3804   for (fs = 0; fs < numFS; ++fs) {
3805     IS              faceIS;
3806     const PetscInt *faces;
3807     PetscInt        numFaces, f;
3808 
3809     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3810     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3811     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3812     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3813       PetscInt newFace = faces[f] + *numGhostCells;
3814 
3815       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3816       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3817     }
3818     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3819     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3820   }
3821   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3822   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3823   /* Step 7: Stratify */
3824   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3825   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3826   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3827   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3828   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3829   PetscFunctionReturn(0);
3830 }
3831 
3832 #undef __FUNCT__
3833 #define __FUNCT__ "DMPlexConstructGhostCells"
3834 /*@C
3835   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3836 
3837   Collective on dm
3838 
3839   Input Parameters:
3840 + dm - The original DM
3841 - labelName - The label specifying the boundary faces (this could be auto-generated)
3842 
3843   Output Parameters:
3844 + numGhostCells - The number of ghost cells added to the DM
3845 - dmGhosted - The new DM
3846 
3847   Level: developer
3848 
3849 .seealso: DMCreate()
3850 */
3851 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3852 {
3853   DM             gdm;
3854   PetscInt       dim;
3855   PetscErrorCode ierr;
3856 
3857   PetscFunctionBegin;
3858   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3859   PetscValidPointer(numGhostCells, 3);
3860   PetscValidPointer(dmGhosted, 4);
3861   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3862   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3863   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3864   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3865   switch (dim) {
3866   case 2:
3867     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3868     break;
3869   default:
3870     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3871   }
3872   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3873   *dmGhosted = gdm;
3874   PetscFunctionReturn(0);
3875 }
3876 
3877 #undef __FUNCT__
3878 #define __FUNCT__ "DMPlexConstructCohesiveCells_2D"
3879 PetscErrorCode DMPlexConstructCohesiveCells_2D(DM dm, const char labelName[], DM sdm)
3880 {
3881   MPI_Comm        comm = ((PetscObject) dm)->comm;
3882   DMLabel         label;
3883   IS              valueIS, svIS, seIS;
3884   const PetscInt *values, *splitVertices, *splitEdges;
3885   PetscInt       *depthShift, *depthCumShift, *pMaxNew, *coneNew, *supportNew;
3886   PetscInt        shift = 100, depth = 0, dim, d, numSP, sp, maxConeSize, maxSupportSize, numSplitVertices, numSplitEdges;
3887   PetscErrorCode  ierr;
3888 
3889   PetscFunctionBegin;
3890   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3891   /* Count split points and add cohesive cells */
3892   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3893   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3894   ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3895   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3896   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3897   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3898   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthCumShift,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3899   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3900   for(d = 0; d <= dim; ++d) {
3901     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3902   }
3903   for(sp = 0; sp < numSP; ++sp) {
3904     if ((values[sp] < 0) || (values[sp] > depth)) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Invalid depth %d in label, not in [0, %d]", values[sp], depth);
3905     ierr = DMLabelGetStratumSize(label, values[sp], &depthShift[values[sp]]);CHKERRQ(ierr);
3906   }
3907   depthShift[dim] = depthShift[dim-1]; /* There is a cohesive cell for every split face   */
3908   depthShift[1]  += depthShift[0];     /* There is a cohesive edge for every split vertex */
3909   pMaxNew[0]   += depthShift[dim];
3910   if (dim > 1) {pMaxNew[1]   += depthShift[dim] + depthShift[0];}
3911   if (dim > 2) {pMaxNew[2]   += depthShift[dim] + depthShift[0] + depthShift[1];}
3912   depthCumShift[dim] = depthShift[dim];
3913   depthCumShift[0]   = depthCumShift[dim] + depthShift[0];
3914   if (dim > 1) {depthCumShift[1]   = depthCumShift[0] + depthShift[1];}
3915   if (dim > 2) {depthCumShift[2]   = depthCumShift[1] + depthShift[2];}
3916   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3917   ierr = DMLabelGetStratumIS(label, 0, &svIS);CHKERRQ(ierr);
3918   ierr = DMLabelGetStratumIS(label, 1, &seIS);CHKERRQ(ierr);
3919   ierr = ISGetIndices(svIS, &splitVertices);CHKERRQ(ierr);
3920   ierr = ISGetIndices(seIS, &splitEdges);CHKERRQ(ierr);
3921   /* Step 3: Set cone/support sizes for new points */
3922   for(sp = 0; sp < numSP; ++sp) {
3923     const PetscInt  dep = values[sp];
3924     const PetscInt *points;
3925     IS              dimIS;
3926     PetscInt        numPoints, p;
3927 
3928     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
3929     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
3930     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
3931     for(p = 0; p < numPoints; ++p) {
3932       const PetscInt *support;
3933       PetscInt        coneSize, supportSize, q, e;
3934 
3935       ierr = DMPlexGetConeSize(dm, points[p], &coneSize);CHKERRQ(ierr);
3936       ierr = DMPlexSetConeSize(sdm, pMaxNew[dep] + p, coneSize);CHKERRQ(ierr);
3937       ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
3938       ierr = DMPlexSetSupportSize(sdm, pMaxNew[dep] + p, supportSize);CHKERRQ(ierr);
3939       if (dep == dim-1) {
3940         /* Add cohesive cells, they are prisms */
3941         ierr = DMPlexSetConeSize(sdm, pMaxNew[dim] + p, 2 + coneSize);CHKERRQ(ierr);
3942       } else if (dep == 0) {
3943         ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
3944         /* Split old vertex: Edges in old split faces and new cohesive edge */
3945         for(e = 0, q = 0; e < supportSize; ++e) {
3946           PetscInt val;
3947 
3948           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3949           if ((val == 1) || (val == (shift + 1))) ++q;
3950         }
3951         ierr = DMPlexSetSupportSize(sdm, points[p], q);CHKERRQ(ierr);
3952         /* Split new vertex: Edges in new split faces and new cohesive edge */
3953         for(e = 0, q = 0; e < supportSize; ++e) {
3954           PetscInt val;
3955 
3956           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3957           if ((val == 1) || (val == -(shift + 1))) ++q;
3958         }
3959         ierr = DMPlexSetSupportSize(sdm, pMaxNew[dep] + p, q);CHKERRQ(ierr);
3960         /* Add cohesive edges */
3961         ierr = DMPlexSetConeSize(sdm, pMaxNew[1] + (depthShift[1] - depthShift[0]) + p, 2);CHKERRQ(ierr);
3962         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3963       }
3964     }
3965     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
3966     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
3967   }
3968   /* Step 4: Setup ghosted DM */
3969   ierr = DMSetUp(sdm);CHKERRQ(ierr);
3970   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3971   /* Step 6: Set cones and supports for new points */
3972   for(sp = 0; sp < numSP; ++sp) {
3973     const PetscInt  dep = values[sp];
3974     const PetscInt *points;
3975     IS              dimIS;
3976     PetscInt        numPoints, p;
3977 
3978     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
3979     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
3980     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
3981     for(p = 0; p < numPoints; ++p) {
3982       const PetscInt *cone, *support;
3983       PetscInt        coneSize, supportSize, q, v, e;
3984 
3985       ierr = DMPlexGetConeSize(dm, points[p], &coneSize);CHKERRQ(ierr);
3986       ierr = DMPlexGetCone(dm, points[p], &cone);CHKERRQ(ierr);
3987       ierr = DMPlexGetConeSize(dm, points[p], &supportSize);CHKERRQ(ierr);
3988       ierr = DMPlexGetCone(dm, points[p], &support);CHKERRQ(ierr);
3989       if (dep == dim-1) {
3990         /* Split old face:   Replace negative side cell with cohesive cell, old vertices in cone */
3991         ierr = DMPlexSetCone(sdm, depthCumShift[dep] + points[p], cone);CHKERRQ(ierr);
3992         /* Split new face:   Replace positive side cell with cohesive cell, new vertices in cone */
3993         for(q = 0; q < coneSize; ++q) {
3994           ierr = PetscFindInt(cone[q], numSplitVertices, splitVertices, &v);CHKERRQ(ierr);
3995           coneNew[2+q] = pMaxNew[0] + v;
3996         }
3997         ierr = DMPlexSetCone(sdm, pMaxNew[dep] + p, &coneNew[2]);CHKERRQ(ierr);
3998         /* Cohesive cell:    Old and new split face, then new cohesive edges */
3999         coneNew[0] = points[p];
4000         coneNew[1] = pMaxNew[dep] + p;
4001         for(q = 0; q < coneSize; ++q) {
4002           coneNew[2+q] = (pMaxNew[1] - pMaxNew[0]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4003         }
4004         ierr = DMPlexSetCone(sdm, pMaxNew[dim] + p, coneNew);CHKERRQ(ierr);
4005       } else if (dep == 0) {
4006         /* Split old vertex: Edges in old split faces and new cohesive edge */
4007         for(e = 0, q = 0; e < supportSize; ++e) {
4008           PetscInt val;
4009 
4010           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4011           if ((val == 1) || (val == (shift + 1))) {
4012             supportNew[q++] = support[e];
4013           }
4014         }
4015         ierr = DMPlexSetSupport(sdm, points[p], supportNew);CHKERRQ(ierr);
4016         /* Split new vertex: Edges in new split faces and new cohesive edge */
4017         for(e = 0, q = 0; e < supportSize; ++e) {
4018           PetscInt val, edge;
4019 
4020           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4021           if (val == 1) {
4022             ierr = PetscFindInt(support[e], numSplitEdges, splitEdges, &edge);CHKERRQ(ierr);
4023             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4024             supportNew[q++] = pMaxNew[1] + edge;
4025           } else if (val == -(shift + 1)) {
4026             supportNew[q++] = support[e];
4027           }
4028         }
4029         ierr = DMPlexSetSupport(sdm, pMaxNew[dep] + p, supportNew);CHKERRQ(ierr);
4030         /* Cohesive edge:    Old and new split vertex, punting on support */
4031         coneNew[0] = points[p];
4032         coneNew[1] = pMaxNew[dep] + p;
4033         ierr = DMPlexSetCone(sdm, pMaxNew[1] + (depthShift[1] - depthShift[0]) + p, coneNew);CHKERRQ(ierr);
4034       }
4035     }
4036     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4037     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4038   }
4039   /* Replace new faces in cells on the positive side */
4040   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4041   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4042   /* Step 7: Stratify */
4043   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4044   /* TODO Put new vertices in coordinates */
4045   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4046   /* TODO Put new edges and faces in SF */
4047   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4048   /* TODO Put new cells, edges and faces in labels */
4049   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4050   ierr = ISRestoreIndices(svIS, &splitVertices);CHKERRQ(ierr);
4051   ierr = ISRestoreIndices(seIS, &splitEdges);CHKERRQ(ierr);
4052   ierr = ISDestroy(&svIS);CHKERRQ(ierr);
4053   ierr = ISDestroy(&seIS);CHKERRQ(ierr);
4054   ierr = PetscFree5(depthShift, depthCumShift, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4055   PetscFunctionReturn(0);
4056 }
4057 
4058 #undef __FUNCT__
4059 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4060 /*@C
4061   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4062 
4063   Collective on dm
4064 
4065   Input Parameters:
4066 + dm - The original DM
4067 - labelName - The label specifying the boundary faces (this could be auto-generated)
4068 
4069   Output Parameters:
4070 - dmSplit - The new DM
4071 
4072   Level: developer
4073 
4074 .seealso: DMCreate()
4075 */
4076 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4077 {
4078   DM             sdm;
4079   PetscInt       dim;
4080   PetscErrorCode ierr;
4081 
4082   PetscFunctionBegin;
4083   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4084   PetscValidPointer(dmSplit, 4);
4085   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4086   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4087   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4088   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4089   switch(dim) {
4090   case 2:
4091     ierr = DMPlexConstructCohesiveCells_2D(dm, labelName, sdm);CHKERRQ(ierr);
4092     break;
4093   default:
4094     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4095   }
4096   ierr = DMSetFromOptions(sdm);CHKERRQ(ierr);
4097   *dmSplit = sdm;
4098   PetscFunctionReturn(0);
4099 }
4100 
4101 #undef __FUNCT__
4102 #define __FUNCT__ "DMLabelCohesiveComplete"
4103 PetscErrorCode DMLabelCohesiveComplete(DMLabel label)
4104 {
4105   PetscFunctionBegin;
4106   PetscFunctionReturn(0);
4107 }
4108 
4109 #undef __FUNCT__
4110 #define __FUNCT__ "DMPlexInterpolate_2D"
4111 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4112 {
4113   DM             idm;
4114   DM_Plex    *mesh;
4115   PetscHashIJ    edgeTable;
4116   PetscInt      *off;
4117   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4118   PetscInt       numEdges, firstEdge, edge, e;
4119   PetscErrorCode ierr;
4120 
4121   PetscFunctionBegin;
4122   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4123   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4124   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4125   numCells    = cEnd - cStart;
4126   numVertices = vEnd - vStart;
4127   firstEdge   = numCells + numVertices;
4128   numEdges    = 0 ;
4129   /* Count edges using algorithm from CreateNeighborCSR */
4130   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4131   if (off) {
4132     PetscInt numCorners = 0;
4133 
4134     numEdges = off[numCells]/2;
4135 #if 0
4136     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4137     numEdges += 3*numCells - off[numCells];
4138 #else
4139     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4140     for (c = cStart; c < cEnd; ++c) {
4141       PetscInt coneSize;
4142 
4143       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4144       numCorners += coneSize;
4145     }
4146     numEdges += numCorners - off[numCells];
4147 #endif
4148   }
4149 #if 0
4150   /* Check Euler characteristic V - E + F = 1 */
4151   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4152 #endif
4153   /* Create interpolated mesh */
4154   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4155   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4156   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4157   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4158   for (c = 0; c < numCells; ++c) {
4159     PetscInt numCorners;
4160 
4161     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4162     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4163   }
4164   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4165     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4166   }
4167   ierr = DMSetUp(idm);CHKERRQ(ierr);
4168   /* Get edge cones from subsets of cell vertices */
4169   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4170   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4171 
4172   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4173     const PetscInt *cellFaces;
4174     PetscInt        numCellFaces, faceSize, cf;
4175 
4176     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4177     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4178     for (cf = 0; cf < numCellFaces; ++cf) {
4179 #if 1
4180       PetscHashIJKey key = {PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]),
4181                             PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1])};
4182 
4183       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4184       if (e < 0) {
4185         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4186         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4187         e    = edge++;
4188       }
4189 #else
4190       PetscBool found = PETSC_FALSE;
4191 
4192       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4193       for (e = firstEdge; e < edge; ++e) {
4194         const PetscInt *cone;
4195 
4196         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4197         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4198             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4199           found = PETSC_TRUE;
4200           break;
4201         }
4202       }
4203       if (!found) {
4204         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4205         ++edge;
4206       }
4207 #endif
4208       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4209     }
4210   }
4211   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4212   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4213   ierr = PetscFree(off);CHKERRQ(ierr);
4214   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4215   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4216   mesh = (DM_Plex *) (idm)->data;
4217   /* Orient edges */
4218   for (c = 0; c < numCells; ++c) {
4219     const PetscInt *cone = PETSC_NULL, *cellFaces;
4220     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4221 
4222     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4223     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4224     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4225     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4226     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4227     for (cf = 0; cf < numCellFaces; ++cf) {
4228       const PetscInt *econe = PETSC_NULL;
4229       PetscInt        esize;
4230 
4231       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4232       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4233       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]);
4234       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4235         /* Correctly oriented */
4236         mesh->coneOrientations[coff+cf] = 0;
4237       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4238         /* Start at index 1, and reverse orientation */
4239         mesh->coneOrientations[coff+cf] = -(1+1);
4240       }
4241     }
4242   }
4243   *dmInt  = idm;
4244   PetscFunctionReturn(0);
4245 }
4246 
4247 #undef __FUNCT__
4248 #define __FUNCT__ "DMPlexInterpolate_3D"
4249 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4250 {
4251   DM             idm, fdm;
4252   DM_Plex    *mesh;
4253   PetscInt      *off;
4254   const PetscInt numCorners = 4;
4255   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4256   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4257   PetscErrorCode ierr;
4258 
4259   PetscFunctionBegin;
4260   {
4261     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4262     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4263     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4264   }
4265   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4266   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4267   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4268   numCells    = cEnd - cStart;
4269   numVertices = vEnd - vStart;
4270   firstFace   = numCells + numVertices;
4271   numFaces    = 0 ;
4272   /* Count faces using algorithm from CreateNeighborCSR */
4273   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4274   if (off) {
4275     numFaces = off[numCells]/2;
4276     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4277     numFaces += 4*numCells - off[numCells];
4278   }
4279   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4280   firstEdge = firstFace + numFaces;
4281   numEdges  = numVertices + numFaces - numCells - 1;
4282   /* Create interpolated mesh */
4283   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4284   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4285   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4286   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4287   for (c = 0; c < numCells; ++c) {
4288     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4289   }
4290   for (f = firstFace; f < firstFace+numFaces; ++f) {
4291     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4292   }
4293   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4294     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4295   }
4296   ierr = DMSetUp(idm);CHKERRQ(ierr);
4297   /* Get face cones from subsets of cell vertices */
4298   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4299   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4300   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4301   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4302   for (f = firstFace; f < firstFace+numFaces; ++f) {
4303     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4304   }
4305   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4306   for (c = 0, face = firstFace; c < numCells; ++c) {
4307     const PetscInt *cellFaces;
4308     PetscInt        numCellFaces, faceSize, cf;
4309 
4310     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4311     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4312     for (cf = 0; cf < numCellFaces; ++cf) {
4313       PetscBool found = PETSC_FALSE;
4314 
4315       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4316       for (f = firstFace; f < face; ++f) {
4317         const PetscInt *cone = PETSC_NULL;
4318 
4319         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4320         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4321             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4322             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4323             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4324             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4325             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4326           found = PETSC_TRUE;
4327           break;
4328         }
4329       }
4330       if (!found) {
4331         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4332         /* Save the vertices for orientation calculation */
4333         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4334         ++face;
4335       }
4336       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4337     }
4338   }
4339   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4340   /* Get edge cones from subsets of face vertices */
4341   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4342     const PetscInt *cellFaces;
4343     PetscInt        numCellFaces, faceSize, cf;
4344 
4345     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4346     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4347     for (cf = 0; cf < numCellFaces; ++cf) {
4348       PetscBool found = PETSC_FALSE;
4349 
4350       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4351       for (e = firstEdge; e < edge; ++e) {
4352         const PetscInt *cone = PETSC_NULL;
4353 
4354         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4355         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4356             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4357           found = PETSC_TRUE;
4358           break;
4359         }
4360       }
4361       if (!found) {
4362         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4363         ++edge;
4364       }
4365       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4366     }
4367   }
4368   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4369   ierr = PetscFree(off);CHKERRQ(ierr);
4370   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4371   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4372   mesh = (DM_Plex *) (idm)->data;
4373   /* Orient edges */
4374   for (f = firstFace; f < firstFace+numFaces; ++f) {
4375     const PetscInt *cone, *cellFaces;
4376     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4377 
4378     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4379     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4380     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4381     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4382     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4383     for (cf = 0; cf < numCellFaces; ++cf) {
4384       const PetscInt *econe;
4385       PetscInt        esize;
4386 
4387       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4388       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4389       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]);
4390       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4391         /* Correctly oriented */
4392         mesh->coneOrientations[coff+cf] = 0;
4393       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4394         /* Start at index 1, and reverse orientation */
4395         mesh->coneOrientations[coff+cf] = -(1+1);
4396       }
4397     }
4398   }
4399   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4400   /* Orient faces */
4401   for (c = 0; c < numCells; ++c) {
4402     const PetscInt *cone, *cellFaces;
4403     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4404 
4405     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4406     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4407     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4408     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4409     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4410     for (cf = 0; cf < numCellFaces; ++cf) {
4411       PetscInt *origClosure = PETSC_NULL, *closure;
4412       PetscInt  closureSize, i;
4413 
4414       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4415       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4416       for (i = 4; i < 7; ++i) {
4417         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);
4418       }
4419       closure = &origClosure[4*2];
4420       /* Remember that this is the orientation for edges, not vertices */
4421       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4422         /* Correctly oriented */
4423         mesh->coneOrientations[coff+cf] = 0;
4424       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4425         /* Shifted by 1 */
4426         mesh->coneOrientations[coff+cf] = 1;
4427       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4428         /* Shifted by 2 */
4429         mesh->coneOrientations[coff+cf] = 2;
4430       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4431         /* Start at edge 1, and reverse orientation */
4432         mesh->coneOrientations[coff+cf] = -(1+1);
4433       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4434         /* Start at index 0, and reverse orientation */
4435         mesh->coneOrientations[coff+cf] = -(0+1);
4436       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4437         /* Start at index 2, and reverse orientation */
4438         mesh->coneOrientations[coff+cf] = -(2+1);
4439       } 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);
4440       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4441     }
4442   }
4443   {
4444     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4445     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4446     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4447   }
4448   *dmInt  = idm;
4449   PetscFunctionReturn(0);
4450 }
4451 
4452 #undef __FUNCT__
4453 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4454 /*
4455   This takes as input the common mesh generator output, a list of the vertices for each cell
4456 */
4457 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4458 {
4459   PetscInt      *cone, c, p;
4460   PetscErrorCode ierr;
4461 
4462   PetscFunctionBegin;
4463   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4464   for (c = 0; c < numCells; ++c) {
4465     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4466   }
4467   ierr = DMSetUp(dm);CHKERRQ(ierr);
4468   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4469   for (c = 0; c < numCells; ++c) {
4470     for (p = 0; p < numCorners; ++p) {
4471       cone[p] = cells[c*numCorners+p]+numCells;
4472     }
4473     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4474   }
4475   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4476   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4477   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4478   PetscFunctionReturn(0);
4479 }
4480 
4481 #undef __FUNCT__
4482 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4483 /*
4484   This takes as input the coordinates for each vertex
4485 */
4486 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4487 {
4488   PetscSection   coordSection;
4489   Vec            coordinates;
4490   PetscScalar   *coords;
4491   PetscInt       coordSize, v, d;
4492   PetscErrorCode ierr;
4493 
4494   PetscFunctionBegin;
4495   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4496   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4497   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4498   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4499   for (v = numCells; v < numCells+numVertices; ++v) {
4500     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4501     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4502   }
4503   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4504   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4505   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4506   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4507   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4508   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4509   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4510   for (v = 0; v < numVertices; ++v) {
4511     for (d = 0; d < spaceDim; ++d) {
4512       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4513     }
4514   }
4515   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4516   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4517   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4518   PetscFunctionReturn(0);
4519 }
4520 
4521 #undef __FUNCT__
4522 #define __FUNCT__ "DMPlexCreateFromCellList"
4523 /*
4524   This takes as input the common mesh generator output, a list of the vertices for each cell
4525 */
4526 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4527 {
4528   PetscErrorCode ierr;
4529 
4530   PetscFunctionBegin;
4531   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4532   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4533   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4534   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4535   if (interpolate) {
4536     DM idm;
4537 
4538     switch (dim) {
4539     case 2:
4540       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4541     case 3:
4542       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4543     default:
4544       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4545     }
4546     ierr = DMDestroy(dm);CHKERRQ(ierr);
4547     *dm  = idm;
4548   }
4549   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4550   PetscFunctionReturn(0);
4551 }
4552 
4553 #if defined(PETSC_HAVE_TRIANGLE)
4554 #include <triangle.h>
4555 
4556 #undef __FUNCT__
4557 #define __FUNCT__ "InitInput_Triangle"
4558 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4559 {
4560   PetscFunctionBegin;
4561   inputCtx->numberofpoints = 0;
4562   inputCtx->numberofpointattributes = 0;
4563   inputCtx->pointlist = PETSC_NULL;
4564   inputCtx->pointattributelist = PETSC_NULL;
4565   inputCtx->pointmarkerlist = PETSC_NULL;
4566   inputCtx->numberofsegments = 0;
4567   inputCtx->segmentlist = PETSC_NULL;
4568   inputCtx->segmentmarkerlist = PETSC_NULL;
4569   inputCtx->numberoftriangleattributes = 0;
4570   inputCtx->trianglelist = PETSC_NULL;
4571   inputCtx->numberofholes = 0;
4572   inputCtx->holelist = PETSC_NULL;
4573   inputCtx->numberofregions = 0;
4574   inputCtx->regionlist = PETSC_NULL;
4575   PetscFunctionReturn(0);
4576 }
4577 
4578 #undef __FUNCT__
4579 #define __FUNCT__ "InitOutput_Triangle"
4580 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4581 {
4582   PetscFunctionBegin;
4583   outputCtx->numberofpoints = 0;
4584   outputCtx->pointlist = PETSC_NULL;
4585   outputCtx->pointattributelist = PETSC_NULL;
4586   outputCtx->pointmarkerlist = PETSC_NULL;
4587   outputCtx->numberoftriangles = 0;
4588   outputCtx->trianglelist = PETSC_NULL;
4589   outputCtx->triangleattributelist = PETSC_NULL;
4590   outputCtx->neighborlist = PETSC_NULL;
4591   outputCtx->segmentlist = PETSC_NULL;
4592   outputCtx->segmentmarkerlist = PETSC_NULL;
4593   outputCtx->numberofedges = 0;
4594   outputCtx->edgelist = PETSC_NULL;
4595   outputCtx->edgemarkerlist = PETSC_NULL;
4596   PetscFunctionReturn(0);
4597 }
4598 
4599 #undef __FUNCT__
4600 #define __FUNCT__ "FiniOutput_Triangle"
4601 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4602 {
4603   PetscFunctionBegin;
4604   free(outputCtx->pointmarkerlist);
4605   free(outputCtx->edgelist);
4606   free(outputCtx->edgemarkerlist);
4607   free(outputCtx->trianglelist);
4608   free(outputCtx->neighborlist);
4609   PetscFunctionReturn(0);
4610 }
4611 
4612 #undef __FUNCT__
4613 #define __FUNCT__ "DMPlexGenerate_Triangle"
4614 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4615 {
4616   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4617   PetscInt             dim              = 2;
4618   const PetscBool      createConvexHull = PETSC_FALSE;
4619   const PetscBool      constrained      = PETSC_FALSE;
4620   struct triangulateio in;
4621   struct triangulateio out;
4622   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4623   PetscMPIInt          rank;
4624   PetscErrorCode       ierr;
4625 
4626   PetscFunctionBegin;
4627   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4628   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4629   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4630   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4631   in.numberofpoints = vEnd - vStart;
4632   if (in.numberofpoints > 0) {
4633     PetscSection coordSection;
4634     Vec          coordinates;
4635     PetscScalar *array;
4636 
4637     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4638     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4639     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4640     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4641     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4642     for (v = vStart; v < vEnd; ++v) {
4643       const PetscInt idx = v - vStart;
4644       PetscInt       off, d;
4645 
4646       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4647       for (d = 0; d < dim; ++d) {
4648         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4649       }
4650       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4651     }
4652     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4653   }
4654   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4655   in.numberofsegments = eEnd - eStart;
4656   if (in.numberofsegments > 0) {
4657     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4658     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4659     for (e = eStart; e < eEnd; ++e) {
4660       const PetscInt  idx = e - eStart;
4661       const PetscInt *cone;
4662 
4663       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4664       in.segmentlist[idx*2+0] = cone[0] - vStart;
4665       in.segmentlist[idx*2+1] = cone[1] - vStart;
4666       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4667     }
4668   }
4669 #if 0 /* Do not currently support holes */
4670   PetscReal *holeCoords;
4671   PetscInt   h, d;
4672 
4673   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4674   if (in.numberofholes > 0) {
4675     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4676     for (h = 0; h < in.numberofholes; ++h) {
4677       for (d = 0; d < dim; ++d) {
4678         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4679       }
4680     }
4681   }
4682 #endif
4683   if (!rank) {
4684     char args[32];
4685 
4686     /* Take away 'Q' for verbose output */
4687     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4688     if (createConvexHull) {
4689       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4690     }
4691     if (constrained) {
4692       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4693     }
4694     triangulate(args, &in, &out, PETSC_NULL);
4695   }
4696   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4697   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4698   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4699   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4700   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4701 
4702   {
4703     const PetscInt numCorners  = 3;
4704     const PetscInt numCells    = out.numberoftriangles;
4705     const PetscInt numVertices = out.numberofpoints;
4706     const int     *cells       = out.trianglelist;
4707     const double  *meshCoords  = out.pointlist;
4708 
4709     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4710     /* Set labels */
4711     for (v = 0; v < numVertices; ++v) {
4712       if (out.pointmarkerlist[v]) {
4713         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4714       }
4715     }
4716     if (interpolate) {
4717       for (e = 0; e < out.numberofedges; e++) {
4718         if (out.edgemarkerlist[e]) {
4719           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4720           const PetscInt *edges;
4721           PetscInt        numEdges;
4722 
4723           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4724           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4725           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4726           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4727         }
4728       }
4729     }
4730     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4731   }
4732 #if 0 /* Do not currently support holes */
4733   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4734 #endif
4735   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4736   PetscFunctionReturn(0);
4737 }
4738 
4739 #undef __FUNCT__
4740 #define __FUNCT__ "DMPlexRefine_Triangle"
4741 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4742 {
4743   MPI_Comm             comm = ((PetscObject) dm)->comm;
4744   PetscInt             dim  = 2;
4745   struct triangulateio in;
4746   struct triangulateio out;
4747   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4748   PetscMPIInt          rank;
4749   PetscErrorCode       ierr;
4750 
4751   PetscFunctionBegin;
4752   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4753   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4754   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4755   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4756   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4757   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4758   in.numberofpoints = vEnd - vStart;
4759   if (in.numberofpoints > 0) {
4760     PetscSection coordSection;
4761     Vec          coordinates;
4762     PetscScalar *array;
4763 
4764     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4765     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4766     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4767     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4768     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4769     for (v = vStart; v < vEnd; ++v) {
4770       const PetscInt idx = v - vStart;
4771       PetscInt       off, d;
4772 
4773       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4774       for (d = 0; d < dim; ++d) {
4775         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4776       }
4777       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4778     }
4779     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4780   }
4781   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4782   in.numberofcorners   = 3;
4783   in.numberoftriangles = cEnd - cStart;
4784   in.trianglearealist  = (double *) maxVolumes;
4785   if (in.numberoftriangles > 0) {
4786     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4787     for (c = cStart; c < cEnd; ++c) {
4788       const PetscInt idx     = c - cStart;
4789       PetscInt      *closure = PETSC_NULL;
4790       PetscInt       closureSize;
4791 
4792       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4793       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4794       for (v = 0; v < 3; ++v) {
4795         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4796       }
4797       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4798     }
4799   }
4800   /* TODO: Segment markers are missing on input */
4801 #if 0 /* Do not currently support holes */
4802   PetscReal *holeCoords;
4803   PetscInt   h, d;
4804 
4805   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4806   if (in.numberofholes > 0) {
4807     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4808     for (h = 0; h < in.numberofholes; ++h) {
4809       for (d = 0; d < dim; ++d) {
4810         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4811       }
4812     }
4813   }
4814 #endif
4815   if (!rank) {
4816     char args[32];
4817 
4818     /* Take away 'Q' for verbose output */
4819     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4820     triangulate(args, &in, &out, PETSC_NULL);
4821   }
4822   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4823   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4824   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4825   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4826   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4827 
4828   {
4829     const PetscInt numCorners  = 3;
4830     const PetscInt numCells    = out.numberoftriangles;
4831     const PetscInt numVertices = out.numberofpoints;
4832     const int     *cells       = out.trianglelist;
4833     const double  *meshCoords  = out.pointlist;
4834     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4835 
4836     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4837     /* Set labels */
4838     for (v = 0; v < numVertices; ++v) {
4839       if (out.pointmarkerlist[v]) {
4840         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4841       }
4842     }
4843     if (interpolate) {
4844       PetscInt e;
4845 
4846       for (e = 0; e < out.numberofedges; e++) {
4847         if (out.edgemarkerlist[e]) {
4848           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4849           const PetscInt *edges;
4850           PetscInt        numEdges;
4851 
4852           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4853           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4854           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4855           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4856         }
4857       }
4858     }
4859     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4860   }
4861 #if 0 /* Do not currently support holes */
4862   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4863 #endif
4864   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4865   PetscFunctionReturn(0);
4866 }
4867 #endif
4868 
4869 #if defined(PETSC_HAVE_TETGEN)
4870 #include <tetgen.h>
4871 #undef __FUNCT__
4872 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4873 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4874 {
4875   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4876   const PetscInt dim  = 3;
4877   ::tetgenio     in;
4878   ::tetgenio     out;
4879   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4880   PetscMPIInt    rank;
4881   PetscErrorCode ierr;
4882 
4883   PetscFunctionBegin;
4884   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4885   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4886   in.numberofpoints = vEnd - vStart;
4887   if (in.numberofpoints > 0) {
4888     PetscSection coordSection;
4889     Vec          coordinates;
4890     PetscScalar *array;
4891 
4892     in.pointlist       = new double[in.numberofpoints*dim];
4893     in.pointmarkerlist = new int[in.numberofpoints];
4894     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4895     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4896     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4897     for (v = vStart; v < vEnd; ++v) {
4898       const PetscInt idx = v - vStart;
4899       PetscInt       off, d;
4900 
4901       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4902       for (d = 0; d < dim; ++d) {
4903         in.pointlist[idx*dim + d] = array[off+d];
4904       }
4905       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4906     }
4907     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4908   }
4909   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4910   in.numberoffacets = fEnd - fStart;
4911   if (in.numberoffacets > 0) {
4912     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4913     in.facetmarkerlist = new int[in.numberoffacets];
4914     for (f = fStart; f < fEnd; ++f) {
4915       const PetscInt idx    = f - fStart;
4916       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
4917 
4918       in.facetlist[idx].numberofpolygons = 1;
4919       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4920       in.facetlist[idx].numberofholes    = 0;
4921       in.facetlist[idx].holelist         = NULL;
4922 
4923       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4924       for (p = 0; p < numPoints*2; p += 2) {
4925         const PetscInt point = points[p];
4926         if ((point >= vStart) && (point < vEnd)) {
4927           points[numVertices++] = point;
4928         }
4929       }
4930 
4931       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4932       poly->numberofvertices = numVertices;
4933       poly->vertexlist       = new int[poly->numberofvertices];
4934       for (v = 0; v < numVertices; ++v) {
4935         const PetscInt vIdx = points[v] - vStart;
4936         poly->vertexlist[v] = vIdx;
4937       }
4938       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4939       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4940     }
4941   }
4942   if (!rank) {
4943     char args[32];
4944 
4945     /* Take away 'Q' for verbose output */
4946     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4947     ::tetrahedralize(args, &in, &out);
4948   }
4949   {
4950     const PetscInt numCorners  = 4;
4951     const PetscInt numCells    = out.numberoftetrahedra;
4952     const PetscInt numVertices = out.numberofpoints;
4953     const int     *cells       = out.tetrahedronlist;
4954     const double  *meshCoords  = out.pointlist;
4955 
4956     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4957     /* Set labels */
4958     for (v = 0; v < numVertices; ++v) {
4959       if (out.pointmarkerlist[v]) {
4960         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4961       }
4962     }
4963     if (interpolate) {
4964       PetscInt e;
4965 
4966       for (e = 0; e < out.numberofedges; e++) {
4967         if (out.edgemarkerlist[e]) {
4968           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4969           const PetscInt *edges;
4970           PetscInt        numEdges;
4971 
4972           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4973           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4974           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4975           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4976         }
4977       }
4978       for (f = 0; f < out.numberoftrifaces; f++) {
4979         if (out.trifacemarkerlist[f]) {
4980           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4981           const PetscInt *faces;
4982           PetscInt        numFaces;
4983 
4984           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4985           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4986           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4987           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4988         }
4989       }
4990     }
4991     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4992   }
4993   PetscFunctionReturn(0);
4994 }
4995 
4996 #undef __FUNCT__
4997 #define __FUNCT__ "DMPlexRefine_Tetgen"
4998 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4999 {
5000   MPI_Comm       comm = ((PetscObject) dm)->comm;
5001   const PetscInt dim  = 3;
5002   ::tetgenio     in;
5003   ::tetgenio     out;
5004   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5005   PetscMPIInt    rank;
5006   PetscErrorCode ierr;
5007 
5008   PetscFunctionBegin;
5009   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5010   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5011   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5012   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5013   in.numberofpoints = vEnd - vStart;
5014   if (in.numberofpoints > 0) {
5015     PetscSection coordSection;
5016     Vec          coordinates;
5017     PetscScalar *array;
5018 
5019     in.pointlist       = new double[in.numberofpoints*dim];
5020     in.pointmarkerlist = new int[in.numberofpoints];
5021     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5022     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5023     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5024     for (v = vStart; v < vEnd; ++v) {
5025       const PetscInt idx = v - vStart;
5026       PetscInt       off, d;
5027 
5028       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5029       for (d = 0; d < dim; ++d) {
5030         in.pointlist[idx*dim + d] = array[off+d];
5031       }
5032       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5033     }
5034     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5035   }
5036   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5037   in.numberofcorners       = 4;
5038   in.numberoftetrahedra    = cEnd - cStart;
5039   in.tetrahedronvolumelist = (double *) maxVolumes;
5040   if (in.numberoftetrahedra > 0) {
5041     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5042     for (c = cStart; c < cEnd; ++c) {
5043       const PetscInt idx     = c - cStart;
5044       PetscInt      *closure = PETSC_NULL;
5045       PetscInt       closureSize;
5046 
5047       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5048       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5049       for (v = 0; v < 4; ++v) {
5050         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5051       }
5052       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5053     }
5054   }
5055   /* TODO: Put in boundary faces with markers */
5056   if (!rank) {
5057     char args[32];
5058 
5059     /* Take away 'Q' for verbose output */
5060     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5061     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5062     ::tetrahedralize(args, &in, &out);
5063   }
5064   in.tetrahedronvolumelist = NULL;
5065 
5066   {
5067     const PetscInt numCorners  = 4;
5068     const PetscInt numCells    = out.numberoftetrahedra;
5069     const PetscInt numVertices = out.numberofpoints;
5070     const int     *cells       = out.tetrahedronlist;
5071     const double  *meshCoords  = out.pointlist;
5072     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5073 
5074     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5075     /* Set labels */
5076     for (v = 0; v < numVertices; ++v) {
5077       if (out.pointmarkerlist[v]) {
5078         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5079       }
5080     }
5081     if (interpolate) {
5082       PetscInt e, f;
5083 
5084       for (e = 0; e < out.numberofedges; e++) {
5085         if (out.edgemarkerlist[e]) {
5086           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5087           const PetscInt *edges;
5088           PetscInt        numEdges;
5089 
5090           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5091           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5092           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5093           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5094         }
5095       }
5096       for (f = 0; f < out.numberoftrifaces; f++) {
5097         if (out.trifacemarkerlist[f]) {
5098           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5099           const PetscInt *faces;
5100           PetscInt        numFaces;
5101 
5102           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5103           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5104           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5105           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5106         }
5107       }
5108     }
5109     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5110   }
5111   PetscFunctionReturn(0);
5112 }
5113 #endif
5114 
5115 #if defined(PETSC_HAVE_CTETGEN)
5116 #include "ctetgen.h"
5117 
5118 #undef __FUNCT__
5119 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5120 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5121 {
5122   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5123   const PetscInt dim  = 3;
5124   PLC           *in, *out;
5125   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5126   PetscMPIInt    rank;
5127   PetscErrorCode ierr;
5128 
5129   PetscFunctionBegin;
5130   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5131   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5132   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5133   ierr = PLCCreate(&in);CHKERRQ(ierr);
5134   ierr = PLCCreate(&out);CHKERRQ(ierr);
5135   in->numberofpoints = vEnd - vStart;
5136   if (in->numberofpoints > 0) {
5137     PetscSection coordSection;
5138     Vec          coordinates;
5139     PetscScalar *array;
5140 
5141     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5142     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5143     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5144     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5145     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5146     for (v = vStart; v < vEnd; ++v) {
5147       const PetscInt idx = v - vStart;
5148       PetscInt       off, d, m;
5149 
5150       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5151       for (d = 0; d < dim; ++d) {
5152         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5153       }
5154       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5155       in->pointmarkerlist[idx] = (int) m;
5156     }
5157     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5158   }
5159   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5160   in->numberoffacets = fEnd - fStart;
5161   if (in->numberoffacets > 0) {
5162     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5163     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5164     for (f = fStart; f < fEnd; ++f) {
5165       const PetscInt idx    = f - fStart;
5166       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5167       polygon       *poly;
5168 
5169       in->facetlist[idx].numberofpolygons = 1;
5170       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5171       in->facetlist[idx].numberofholes    = 0;
5172       in->facetlist[idx].holelist         = PETSC_NULL;
5173 
5174       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5175       for (p = 0; p < numPoints*2; p += 2) {
5176         const PetscInt point = points[p];
5177         if ((point >= vStart) && (point < vEnd)) {
5178           points[numVertices++] = point;
5179         }
5180       }
5181 
5182       poly = in->facetlist[idx].polygonlist;
5183       poly->numberofvertices = numVertices;
5184       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5185       for (v = 0; v < numVertices; ++v) {
5186         const PetscInt vIdx = points[v] - vStart;
5187         poly->vertexlist[v] = vIdx;
5188       }
5189       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5190       in->facetmarkerlist[idx] = (int) m;
5191       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5192     }
5193   }
5194   if (!rank) {
5195     TetGenOpts t;
5196 
5197     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5198     t.in        = boundary; /* Should go away */
5199     t.plc       = 1;
5200     t.quality   = 1;
5201     t.edgesout  = 1;
5202     t.zeroindex = 1;
5203     t.quiet     = 1;
5204     t.verbose   = verbose;
5205     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5206     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5207   }
5208   {
5209     const PetscInt numCorners  = 4;
5210     const PetscInt numCells    = out->numberoftetrahedra;
5211     const PetscInt numVertices = out->numberofpoints;
5212     const int     *cells       = out->tetrahedronlist;
5213     const double  *meshCoords  = out->pointlist;
5214 
5215     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5216     /* Set labels */
5217     for (v = 0; v < numVertices; ++v) {
5218       if (out->pointmarkerlist[v]) {
5219         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5220       }
5221     }
5222     if (interpolate) {
5223       PetscInt e;
5224 
5225       for (e = 0; e < out->numberofedges; e++) {
5226         if (out->edgemarkerlist[e]) {
5227           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5228           const PetscInt *edges;
5229           PetscInt        numEdges;
5230 
5231           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5232           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5233           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5234           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5235         }
5236       }
5237       for (f = 0; f < out->numberoftrifaces; f++) {
5238         if (out->trifacemarkerlist[f]) {
5239           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5240           const PetscInt *faces;
5241           PetscInt        numFaces;
5242 
5243           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5244           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5245           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5246           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5247         }
5248       }
5249     }
5250     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5251   }
5252 
5253   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5254   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5255   PetscFunctionReturn(0);
5256 }
5257 
5258 #undef __FUNCT__
5259 #define __FUNCT__ "DMPlexRefine_CTetgen"
5260 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5261 {
5262   MPI_Comm       comm = ((PetscObject) dm)->comm;
5263   const PetscInt dim  = 3;
5264   PLC           *in, *out;
5265   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5266   PetscMPIInt    rank;
5267   PetscErrorCode ierr;
5268 
5269   PetscFunctionBegin;
5270   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5271   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5272   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5273   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5274   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5275   ierr = PLCCreate(&in);CHKERRQ(ierr);
5276   ierr = PLCCreate(&out);CHKERRQ(ierr);
5277   in->numberofpoints = vEnd - vStart;
5278   if (in->numberofpoints > 0) {
5279     PetscSection coordSection;
5280     Vec          coordinates;
5281     PetscScalar *array;
5282 
5283     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5284     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5285     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5286     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5287     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5288     for (v = vStart; v < vEnd; ++v) {
5289       const PetscInt idx = v - vStart;
5290       PetscInt       off, d, m;
5291 
5292       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5293       for (d = 0; d < dim; ++d) {
5294         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5295       }
5296       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5297       in->pointmarkerlist[idx] = (int) m;
5298     }
5299     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5300   }
5301   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5302   in->numberofcorners       = 4;
5303   in->numberoftetrahedra    = cEnd - cStart;
5304   in->tetrahedronvolumelist = maxVolumes;
5305   if (in->numberoftetrahedra > 0) {
5306     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5307     for (c = cStart; c < cEnd; ++c) {
5308       const PetscInt idx     = c - cStart;
5309       PetscInt      *closure = PETSC_NULL;
5310       PetscInt       closureSize;
5311 
5312       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5313       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5314       for (v = 0; v < 4; ++v) {
5315         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5316       }
5317       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5318     }
5319   }
5320   if (!rank) {
5321     TetGenOpts t;
5322 
5323     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5324     t.in        = dm; /* Should go away */
5325     t.refine    = 1;
5326     t.varvolume = 1;
5327     t.quality   = 1;
5328     t.edgesout  = 1;
5329     t.zeroindex = 1;
5330     t.quiet     = 1;
5331     t.verbose   = verbose; /* Change this */
5332     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5333     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5334   }
5335   {
5336     const PetscInt numCorners  = 4;
5337     const PetscInt numCells    = out->numberoftetrahedra;
5338     const PetscInt numVertices = out->numberofpoints;
5339     const int     *cells       = out->tetrahedronlist;
5340     const double  *meshCoords  = out->pointlist;
5341     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5342 
5343     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5344     /* Set labels */
5345     for (v = 0; v < numVertices; ++v) {
5346       if (out->pointmarkerlist[v]) {
5347         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5348       }
5349     }
5350     if (interpolate) {
5351       PetscInt e, f;
5352 
5353       for (e = 0; e < out->numberofedges; e++) {
5354         if (out->edgemarkerlist[e]) {
5355           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5356           const PetscInt *edges;
5357           PetscInt        numEdges;
5358 
5359           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5360           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5361           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5362           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5363         }
5364       }
5365       for (f = 0; f < out->numberoftrifaces; f++) {
5366         if (out->trifacemarkerlist[f]) {
5367           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5368           const PetscInt *faces;
5369           PetscInt        numFaces;
5370 
5371           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5372           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5373           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5374           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5375         }
5376       }
5377     }
5378     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5379   }
5380   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5381   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5382   PetscFunctionReturn(0);
5383 }
5384 #endif
5385 
5386 #undef __FUNCT__
5387 #define __FUNCT__ "DMPlexGenerate"
5388 /*@C
5389   DMPlexGenerate - Generates a mesh.
5390 
5391   Not Collective
5392 
5393   Input Parameters:
5394 + boundary - The DMPlex boundary object
5395 . name - The mesh generation package name
5396 - interpolate - Flag to create intermediate mesh elements
5397 
5398   Output Parameter:
5399 . mesh - The DMPlex object
5400 
5401   Level: intermediate
5402 
5403 .keywords: mesh, elements
5404 .seealso: DMPlexCreate(), DMRefine()
5405 @*/
5406 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5407 {
5408   PetscInt       dim;
5409   char           genname[1024];
5410   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5411   PetscErrorCode ierr;
5412 
5413   PetscFunctionBegin;
5414   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5415   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5416   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5417   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5418   if (flg) {name = genname;}
5419   if (name) {
5420     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5421     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5422     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5423   }
5424   switch (dim) {
5425   case 1:
5426     if (!name || isTriangle) {
5427 #if defined(PETSC_HAVE_TRIANGLE)
5428       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5429 #else
5430       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5431 #endif
5432     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5433     break;
5434   case 2:
5435     if (!name || isCTetgen) {
5436 #if defined(PETSC_HAVE_CTETGEN)
5437       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5438 #else
5439       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5440 #endif
5441     } else if (isTetgen) {
5442 #if defined(PETSC_HAVE_TETGEN)
5443       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5444 #else
5445       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5446 #endif
5447     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5448     break;
5449   default:
5450     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5451   }
5452   PetscFunctionReturn(0);
5453 }
5454 
5455 typedef PetscInt CellRefiner;
5456 
5457 #undef __FUNCT__
5458 #define __FUNCT__ "GetDepthStart_Private"
5459 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5460 {
5461   PetscFunctionBegin;
5462   if (cStart) *cStart = 0;
5463   if (vStart) *vStart = depthSize[depth];
5464   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5465   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5466   PetscFunctionReturn(0);
5467 }
5468 
5469 #undef __FUNCT__
5470 #define __FUNCT__ "GetDepthEnd_Private"
5471 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5472 {
5473   PetscFunctionBegin;
5474   if (cEnd) *cEnd = depthSize[depth];
5475   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5476   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5477   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5478   PetscFunctionReturn(0);
5479 }
5480 
5481 #undef __FUNCT__
5482 #define __FUNCT__ "CellRefinerGetSizes"
5483 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5484 {
5485   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5486   PetscErrorCode ierr;
5487 
5488   PetscFunctionBegin;
5489   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5490   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5491   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5492   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5493   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5494   switch (refiner) {
5495   case 1:
5496     /* Simplicial 2D */
5497     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5498     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5499     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5500     break;
5501   case 3:
5502     /* Hybrid 2D */
5503     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5504     cMax = PetscMin(cEnd, cMax);
5505     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5506     fMax = PetscMin(fEnd, fMax);
5507     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5508     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
5509     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5510     break;
5511   case 2:
5512     /* Hex 2D */
5513     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5514     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5515     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5516     break;
5517   default:
5518     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5519   }
5520   PetscFunctionReturn(0);
5521 }
5522 
5523 #undef __FUNCT__
5524 #define __FUNCT__ "CellRefinerSetConeSizes"
5525 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5526 {
5527   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5528   PetscErrorCode ierr;
5529 
5530   PetscFunctionBegin;
5531   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5532   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5533   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5534   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5535   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5536   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5537   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5538   switch (refiner) {
5539   case 1:
5540     /* Simplicial 2D */
5541     /* All cells have 3 faces */
5542     for (c = cStart; c < cEnd; ++c) {
5543       for (r = 0; r < 4; ++r) {
5544         const PetscInt newp = (c - cStart)*4 + r;
5545 
5546         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5547       }
5548     }
5549     /* Split faces have 2 vertices and the same cells as the parent */
5550     for (f = fStart; f < fEnd; ++f) {
5551       for (r = 0; r < 2; ++r) {
5552         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5553         PetscInt       size;
5554 
5555         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5556         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5557         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5558       }
5559     }
5560     /* Interior faces have 2 vertices and 2 cells */
5561     for (c = cStart; c < cEnd; ++c) {
5562       for (r = 0; r < 3; ++r) {
5563         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5564 
5565         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5566         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5567       }
5568     }
5569     /* Old vertices have identical supports */
5570     for (v = vStart; v < vEnd; ++v) {
5571       const PetscInt newp = vStartNew + (v - vStart);
5572       PetscInt       size;
5573 
5574       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5575       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5576     }
5577     /* Face vertices have 2 + cells*2 supports */
5578     for (f = fStart; f < fEnd; ++f) {
5579       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5580       PetscInt       size;
5581 
5582       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5583       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5584     }
5585     break;
5586   case 2:
5587     /* Hex 2D */
5588     /* All cells have 4 faces */
5589     for (c = cStart; c < cEnd; ++c) {
5590       for (r = 0; r < 4; ++r) {
5591         const PetscInt newp = (c - cStart)*4 + r;
5592 
5593         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5594       }
5595     }
5596     /* Split faces have 2 vertices and the same cells as the parent */
5597     for (f = fStart; f < fEnd; ++f) {
5598       for (r = 0; r < 2; ++r) {
5599         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5600         PetscInt       size;
5601 
5602         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5603         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5604         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5605       }
5606     }
5607     /* Interior faces have 2 vertices and 2 cells */
5608     for (c = cStart; c < cEnd; ++c) {
5609       for (r = 0; r < 4; ++r) {
5610         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5611 
5612         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5613         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5614       }
5615     }
5616     /* Old vertices have identical supports */
5617     for (v = vStart; v < vEnd; ++v) {
5618       const PetscInt newp = vStartNew + (v - vStart);
5619       PetscInt       size;
5620 
5621       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5622       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5623     }
5624     /* Face vertices have 2 + cells supports */
5625     for (f = fStart; f < fEnd; ++f) {
5626       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5627       PetscInt       size;
5628 
5629       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5630       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5631     }
5632     /* Cell vertices have 4 supports */
5633     for (c = cStart; c < cEnd; ++c) {
5634       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5635 
5636       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5637     }
5638     break;
5639   case 3:
5640     /* Hybrid 2D */
5641     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5642     cMax = PetscMin(cEnd, cMax);
5643     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5644     fMax = PetscMin(fEnd, fMax);
5645     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5646     /* Interior cells have 3 faces */
5647     for (c = cStart; c < cMax; ++c) {
5648       for (r = 0; r < 4; ++r) {
5649         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5650 
5651         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5652       }
5653     }
5654     /* Hybrid cells have 4 faces */
5655     for (c = cMax; c < cEnd; ++c) {
5656       for (r = 0; r < 2; ++r) {
5657         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5658 
5659         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5660       }
5661     }
5662     /* Interior split faces have 2 vertices and the same cells as the parent */
5663     for (f = fStart; f < fMax; ++f) {
5664       for (r = 0; r < 2; ++r) {
5665         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5666         PetscInt       size;
5667 
5668         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5669         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5670         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5671       }
5672     }
5673     /* Interior cell faces have 2 vertices and 2 cells */
5674     for (c = cStart; c < cMax; ++c) {
5675       for (r = 0; r < 3; ++r) {
5676         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5677 
5678         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5679         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5680       }
5681     }
5682     /* Hybrid faces have 2 vertices and the same cells */
5683     for (f = fMax; f < fEnd; ++f) {
5684       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5685       PetscInt       size;
5686 
5687       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5688       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5689       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5690     }
5691     /* Hybrid cell faces have 2 vertices and 2 cells */
5692     for (c = cMax; c < cEnd; ++c) {
5693       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5694 
5695       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5696       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5697     }
5698     /* Old vertices have identical supports */
5699     for (v = vStart; v < vEnd; ++v) {
5700       const PetscInt newp = vStartNew + (v - vStart);
5701       PetscInt       size;
5702 
5703       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5704       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5705     }
5706     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5707     for (f = fStart; f < fMax; ++f) {
5708       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5709       const PetscInt *support;
5710       PetscInt        size, newSize = 2, s;
5711 
5712       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5713       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5714       for (s = 0; s < size; ++s) {
5715         if (support[s] >= cMax) {
5716           newSize += 1;
5717         } else {
5718           newSize += 2;
5719         }
5720       }
5721       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5722     }
5723     break;
5724   default:
5725     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5726   }
5727   PetscFunctionReturn(0);
5728 }
5729 
5730 #undef __FUNCT__
5731 #define __FUNCT__ "CellRefinerSetCones"
5732 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5733 {
5734   PetscInt       depth, cStart, cEnd, cMax, cStartNew, cEndNew, c, vStart, vEnd, vMax, vStartNew, vEndNew, v, fStart, fEnd, fMax, fStartNew, fEndNew, f, eStart, eEnd, eMax, eStartNew, eEndNew, r, p;
5735   PetscInt       maxSupportSize, *supportRef;
5736   PetscErrorCode ierr;
5737 
5738   PetscFunctionBegin;
5739   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5740   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5741   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5742   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5743   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5744   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5745   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5746   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5747   switch (refiner) {
5748   case 1:
5749     /* Simplicial 2D */
5750     /*
5751      2
5752      |\
5753      | \
5754      |  \
5755      |   \
5756      | C  \
5757      |     \
5758      |      \
5759      2---1---1
5760      |\  D  / \
5761      | 2   0   \
5762      |A \ /  B  \
5763      0---0-------1
5764      */
5765     /* All cells have 3 faces */
5766     for (c = cStart; c < cEnd; ++c) {
5767       const PetscInt  newp = cStartNew + (c - cStart)*4;
5768       const PetscInt *cone, *ornt;
5769       PetscInt        coneNew[3], orntNew[3];
5770 
5771       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5772       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5773       /* A triangle */
5774       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5775       orntNew[0] = ornt[0];
5776       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5777       orntNew[1] = -2;
5778       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5779       orntNew[2] = ornt[2];
5780       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5781       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5782 #if 1
5783       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);
5784       for (p = 0; p < 3; ++p) {
5785         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);
5786       }
5787 #endif
5788       /* B triangle */
5789       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5790       orntNew[0] = ornt[0];
5791       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5792       orntNew[1] = ornt[1];
5793       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5794       orntNew[2] = -2;
5795       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5796       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5797 #if 1
5798       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);
5799       for (p = 0; p < 3; ++p) {
5800         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);
5801       }
5802 #endif
5803       /* C triangle */
5804       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5805       orntNew[0] = -2;
5806       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5807       orntNew[1] = ornt[1];
5808       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5809       orntNew[2] = ornt[2];
5810       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5811       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5812 #if 1
5813       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);
5814       for (p = 0; p < 3; ++p) {
5815         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);
5816       }
5817 #endif
5818       /* D triangle */
5819       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5820       orntNew[0] = 0;
5821       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5822       orntNew[1] = 0;
5823       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5824       orntNew[2] = 0;
5825       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5826       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5827 #if 1
5828       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);
5829       for (p = 0; p < 3; ++p) {
5830         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);
5831       }
5832 #endif
5833     }
5834     /* Split faces have 2 vertices and the same cells as the parent */
5835     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5836     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5837     for (f = fStart; f < fEnd; ++f) {
5838       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5839 
5840       for (r = 0; r < 2; ++r) {
5841         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5842         const PetscInt *cone, *support;
5843         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5844 
5845         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5846         coneNew[0] = vStartNew + (cone[0] - vStart);
5847         coneNew[1] = vStartNew + (cone[1] - vStart);
5848         coneNew[(r+1)%2] = newv;
5849         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5850 #if 1
5851         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5852         for (p = 0; p < 2; ++p) {
5853           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);
5854         }
5855 #endif
5856         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5857         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5858         for (s = 0; s < supportSize; ++s) {
5859           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5860           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5861           for (c = 0; c < coneSize; ++c) {
5862             if (cone[c] == f) {
5863               break;
5864             }
5865           }
5866           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5867         }
5868         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5869 #if 1
5870         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5871         for (p = 0; p < supportSize; ++p) {
5872           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);
5873         }
5874 #endif
5875       }
5876     }
5877     /* Interior faces have 2 vertices and 2 cells */
5878     for (c = cStart; c < cEnd; ++c) {
5879       const PetscInt *cone;
5880 
5881       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5882       for (r = 0; r < 3; ++r) {
5883         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5884         PetscInt       coneNew[2];
5885         PetscInt       supportNew[2];
5886 
5887         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5888         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5889         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5890 #if 1
5891         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5892         for (p = 0; p < 2; ++p) {
5893           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);
5894         }
5895 #endif
5896         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5897         supportNew[1] = (c - cStart)*4 + 3;
5898         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5899 #if 1
5900         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5901         for (p = 0; p < 2; ++p) {
5902           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);
5903         }
5904 #endif
5905       }
5906     }
5907     /* Old vertices have identical supports */
5908     for (v = vStart; v < vEnd; ++v) {
5909       const PetscInt  newp = vStartNew + (v - vStart);
5910       const PetscInt *support, *cone;
5911       PetscInt        size, s;
5912 
5913       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5914       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5915       for (s = 0; s < size; ++s) {
5916         PetscInt r = 0;
5917 
5918         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5919         if (cone[1] == v) r = 1;
5920         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5921       }
5922       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5923 #if 1
5924       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5925       for (p = 0; p < size; ++p) {
5926         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);
5927       }
5928 #endif
5929     }
5930     /* Face vertices have 2 + cells*2 supports */
5931     for (f = fStart; f < fEnd; ++f) {
5932       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5933       const PetscInt *cone, *support;
5934       PetscInt        size, s;
5935 
5936       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5937       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5938       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5939       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5940       for (s = 0; s < size; ++s) {
5941         PetscInt r = 0;
5942 
5943         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5944         if      (cone[1] == f) r = 1;
5945         else if (cone[2] == f) r = 2;
5946         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5947         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5948       }
5949       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5950 #if 1
5951       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5952       for (p = 0; p < 2+size*2; ++p) {
5953         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);
5954       }
5955 #endif
5956     }
5957     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5958     break;
5959   case 2:
5960     /* Hex 2D */
5961     /*
5962      3---------2---------2
5963      |         |         |
5964      |    D    2    C    |
5965      |         |         |
5966      3----3----0----1----1
5967      |         |         |
5968      |    A    0    B    |
5969      |         |         |
5970      0---------0---------1
5971      */
5972     /* All cells have 4 faces */
5973     for (c = cStart; c < cEnd; ++c) {
5974       const PetscInt  newp = (c - cStart)*4;
5975       const PetscInt *cone, *ornt;
5976       PetscInt        coneNew[4], orntNew[4];
5977 
5978       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5979       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5980       /* A quad */
5981       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5982       orntNew[0] = ornt[0];
5983       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5984       orntNew[1] = 0;
5985       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5986       orntNew[2] = -2;
5987       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5988       orntNew[3] = ornt[3];
5989       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5990       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5991 #if 1
5992       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);
5993       for (p = 0; p < 4; ++p) {
5994         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);
5995       }
5996 #endif
5997       /* B quad */
5998       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5999       orntNew[0] = ornt[0];
6000       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6001       orntNew[1] = ornt[1];
6002       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6003       orntNew[2] = 0;
6004       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6005       orntNew[3] = -2;
6006       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6007       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6008 #if 1
6009       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);
6010       for (p = 0; p < 4; ++p) {
6011         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);
6012       }
6013 #endif
6014       /* C quad */
6015       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6016       orntNew[0] = -2;
6017       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6018       orntNew[1] = ornt[1];
6019       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6020       orntNew[2] = ornt[2];
6021       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6022       orntNew[3] = 0;
6023       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6024       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6025 #if 1
6026       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);
6027       for (p = 0; p < 4; ++p) {
6028         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);
6029       }
6030 #endif
6031       /* D quad */
6032       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6033       orntNew[0] = 0;
6034       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6035       orntNew[1] = -2;
6036       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6037       orntNew[2] = ornt[2];
6038       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6039       orntNew[3] = ornt[3];
6040       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6041       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6042 #if 1
6043       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);
6044       for (p = 0; p < 4; ++p) {
6045         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);
6046       }
6047 #endif
6048     }
6049     /* Split faces have 2 vertices and the same cells as the parent */
6050     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6051     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6052     for (f = fStart; f < fEnd; ++f) {
6053       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6054 
6055       for (r = 0; r < 2; ++r) {
6056         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6057         const PetscInt *cone, *support;
6058         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6059 
6060         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6061         coneNew[0] = vStartNew + (cone[0] - vStart);
6062         coneNew[1] = vStartNew + (cone[1] - vStart);
6063         coneNew[(r+1)%2] = newv;
6064         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6065 #if 1
6066         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6067         for (p = 0; p < 2; ++p) {
6068           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);
6069         }
6070 #endif
6071         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6072         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6073         for (s = 0; s < supportSize; ++s) {
6074           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6075           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6076           for (c = 0; c < coneSize; ++c) {
6077             if (cone[c] == f) {
6078               break;
6079             }
6080           }
6081           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6082         }
6083         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6084 #if 1
6085         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6086         for (p = 0; p < supportSize; ++p) {
6087           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);
6088         }
6089 #endif
6090       }
6091     }
6092     /* Interior faces have 2 vertices and 2 cells */
6093     for (c = cStart; c < cEnd; ++c) {
6094       const PetscInt *cone;
6095       PetscInt        coneNew[2], supportNew[2];
6096 
6097       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6098       for (r = 0; r < 4; ++r) {
6099         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6100 
6101         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6102         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6103         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6104 #if 1
6105         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6106         for (p = 0; p < 2; ++p) {
6107           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);
6108         }
6109 #endif
6110         supportNew[0] = (c - cStart)*4 + r;
6111         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6112         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6113 #if 1
6114         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6115         for (p = 0; p < 2; ++p) {
6116           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);
6117         }
6118 #endif
6119       }
6120     }
6121     /* Old vertices have identical supports */
6122     for (v = vStart; v < vEnd; ++v) {
6123       const PetscInt  newp = vStartNew + (v - vStart);
6124       const PetscInt *support, *cone;
6125       PetscInt        size, s;
6126 
6127       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6128       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6129       for (s = 0; s < size; ++s) {
6130         PetscInt r = 0;
6131 
6132         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6133         if (cone[1] == v) r = 1;
6134         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6135       }
6136       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6137 #if 1
6138       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6139       for (p = 0; p < size; ++p) {
6140         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);
6141       }
6142 #endif
6143     }
6144     /* Face vertices have 2 + cells supports */
6145     for (f = fStart; f < fEnd; ++f) {
6146       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6147       const PetscInt *cone, *support;
6148       PetscInt        size, s;
6149 
6150       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6151       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6152       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6153       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6154       for (s = 0; s < size; ++s) {
6155         PetscInt r = 0;
6156 
6157         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6158         if      (cone[1] == f) r = 1;
6159         else if (cone[2] == f) r = 2;
6160         else if (cone[3] == f) r = 3;
6161         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6162       }
6163       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6164 #if 1
6165       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6166       for (p = 0; p < 2+size; ++p) {
6167         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);
6168       }
6169 #endif
6170     }
6171     /* Cell vertices have 4 supports */
6172     for (c = cStart; c < cEnd; ++c) {
6173       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6174       PetscInt       supportNew[4];
6175 
6176       for (r = 0; r < 4; ++r) {
6177         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6178       }
6179       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6180     }
6181     break;
6182   case 3:
6183     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6184     cMax = PetscMin(cEnd, cMax);
6185     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6186     fMax = PetscMin(fEnd, fMax);
6187     /* Interior cells have 3 faces */
6188     for (c = cStart; c < cMax; ++c) {
6189       const PetscInt  newp = cStartNew + (c - cStart)*4;
6190       const PetscInt *cone, *ornt;
6191       PetscInt        coneNew[3], orntNew[3];
6192 
6193       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6194       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6195       /* A triangle */
6196       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6197       orntNew[0] = ornt[0];
6198       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6199       orntNew[1] = -2;
6200       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6201       orntNew[2] = ornt[2];
6202       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6203       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6204 #if 1
6205       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);
6206       for (p = 0; p < 3; ++p) {
6207         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);
6208       }
6209 #endif
6210       /* B triangle */
6211       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6212       orntNew[0] = ornt[0];
6213       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6214       orntNew[1] = ornt[1];
6215       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6216       orntNew[2] = -2;
6217       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6218       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6219 #if 1
6220       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);
6221       for (p = 0; p < 3; ++p) {
6222         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);
6223       }
6224 #endif
6225       /* C triangle */
6226       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6227       orntNew[0] = -2;
6228       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6229       orntNew[1] = ornt[1];
6230       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6231       orntNew[2] = ornt[2];
6232       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6233       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6234 #if 1
6235       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);
6236       for (p = 0; p < 3; ++p) {
6237         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);
6238       }
6239 #endif
6240       /* D triangle */
6241       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6242       orntNew[0] = 0;
6243       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6244       orntNew[1] = 0;
6245       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6246       orntNew[2] = 0;
6247       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6248       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6249 #if 1
6250       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);
6251       for (p = 0; p < 3; ++p) {
6252         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);
6253       }
6254 #endif
6255     }
6256     /*
6257      2----3----3
6258      |         |
6259      |    B    |
6260      |         |
6261      0----4--- 1
6262      |         |
6263      |    A    |
6264      |         |
6265      0----2----1
6266      */
6267     /* Hybrid cells have 4 faces */
6268     for (c = cMax; c < cEnd; ++c) {
6269       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6270       const PetscInt *cone, *ornt;
6271       PetscInt        coneNew[4], orntNew[4];
6272 
6273       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6274       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6275       /* A quad */
6276       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6277       orntNew[0] = ornt[0];
6278       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6279       orntNew[1] = ornt[1];
6280       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6281       orntNew[2] = 0;
6282       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6283       orntNew[3] = 0;
6284       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6285       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6286 #if 1
6287       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);
6288       for (p = 0; p < 4; ++p) {
6289         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);
6290       }
6291 #endif
6292       /* B quad */
6293       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6294       orntNew[0] = ornt[0];
6295       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6296       orntNew[1] = ornt[1];
6297       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6298       orntNew[2] = 0;
6299       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6300       orntNew[3] = 0;
6301       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6302       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6303 #if 1
6304       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);
6305       for (p = 0; p < 4; ++p) {
6306         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);
6307       }
6308 #endif
6309     }
6310     /* Interior split faces have 2 vertices and the same cells as the parent */
6311     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6312     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6313     for (f = fStart; f < fMax; ++f) {
6314       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6315 
6316       for (r = 0; r < 2; ++r) {
6317         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6318         const PetscInt *cone, *support;
6319         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6320 
6321         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6322         coneNew[0] = vStartNew + (cone[0] - vStart);
6323         coneNew[1] = vStartNew + (cone[1] - vStart);
6324         coneNew[(r+1)%2] = newv;
6325         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6326 #if 1
6327         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6328         for (p = 0; p < 2; ++p) {
6329           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);
6330         }
6331 #endif
6332         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6333         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6334         for (s = 0; s < supportSize; ++s) {
6335           if (support[s] >= cMax) {
6336             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6337           } else {
6338             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6339             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6340             for (c = 0; c < coneSize; ++c) {
6341               if (cone[c] == f) {
6342                 break;
6343               }
6344             }
6345             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6346           }
6347         }
6348         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6349 #if 1
6350         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6351         for (p = 0; p < supportSize; ++p) {
6352           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);
6353         }
6354 #endif
6355       }
6356     }
6357     /* Interior cell faces have 2 vertices and 2 cells */
6358     for (c = cStart; c < cMax; ++c) {
6359       const PetscInt *cone;
6360 
6361       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6362       for (r = 0; r < 3; ++r) {
6363         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6364         PetscInt       coneNew[2];
6365         PetscInt       supportNew[2];
6366 
6367         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6368         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6369         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6370 #if 1
6371         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6372         for (p = 0; p < 2; ++p) {
6373           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);
6374         }
6375 #endif
6376         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6377         supportNew[1] = (c - cStart)*4 + 3;
6378         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6379 #if 1
6380         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6381         for (p = 0; p < 2; ++p) {
6382           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);
6383         }
6384 #endif
6385       }
6386     }
6387     /* Interior hybrid faces have 2 vertices and the same cells */
6388     for (f = fMax; f < fEnd; ++f) {
6389       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6390       const PetscInt *cone;
6391       const PetscInt *support;
6392       PetscInt        coneNew[2];
6393       PetscInt        supportNew[2];
6394       PetscInt        size, s, r;
6395 
6396       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6397       coneNew[0] = vStartNew + (cone[0] - vStart);
6398       coneNew[1] = vStartNew + (cone[1] - vStart);
6399       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6400 #if 1
6401       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6402       for (p = 0; p < 2; ++p) {
6403         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);
6404       }
6405 #endif
6406       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6407       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6408       for (s = 0; s < size; ++s) {
6409         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6410         for (r = 0; r < 2; ++r) {
6411           if (cone[r+2] == f) break;
6412         }
6413         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6414       }
6415       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6416 #if 1
6417       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6418       for (p = 0; p < size; ++p) {
6419         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);
6420       }
6421 #endif
6422     }
6423     /* Cell hybrid faces have 2 vertices and 2 cells */
6424     for (c = cMax; c < cEnd; ++c) {
6425       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6426       const PetscInt *cone;
6427       PetscInt        coneNew[2];
6428       PetscInt        supportNew[2];
6429 
6430       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6431       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6432       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6433       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6434 #if 1
6435       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6436       for (p = 0; p < 2; ++p) {
6437         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);
6438       }
6439 #endif
6440       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6441       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6442       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6443 #if 1
6444       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6445       for (p = 0; p < 2; ++p) {
6446         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);
6447       }
6448 #endif
6449     }
6450     /* Old vertices have identical supports */
6451     for (v = vStart; v < vEnd; ++v) {
6452       const PetscInt  newp = vStartNew + (v - vStart);
6453       const PetscInt *support, *cone;
6454       PetscInt        size, s;
6455 
6456       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6457       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6458       for (s = 0; s < size; ++s) {
6459         if (support[s] >= fMax) {
6460           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6461         } else {
6462           PetscInt r = 0;
6463 
6464           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6465           if (cone[1] == v) r = 1;
6466           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6467         }
6468       }
6469       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6470 #if 1
6471       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6472       for (p = 0; p < size; ++p) {
6473         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);
6474       }
6475 #endif
6476     }
6477     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6478     for (f = fStart; f < fMax; ++f) {
6479       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6480       const PetscInt *cone, *support;
6481       PetscInt        size, newSize = 2, s;
6482 
6483       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6484       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6485       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6486       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6487       for (s = 0; s < size; ++s) {
6488         PetscInt r = 0;
6489 
6490         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6491         if (support[s] >= cMax) {
6492           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6493           newSize += 1;
6494         } else {
6495           if      (cone[1] == f) r = 1;
6496           else if (cone[2] == f) r = 2;
6497           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6498           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6499           newSize += 2;
6500         }
6501       }
6502       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6503 #if 1
6504       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6505       for (p = 0; p < newSize; ++p) {
6506         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);
6507       }
6508 #endif
6509     }
6510     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6511     break;
6512   default:
6513     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6514   }
6515   PetscFunctionReturn(0);
6516 }
6517 
6518 #undef __FUNCT__
6519 #define __FUNCT__ "CellRefinerSetCoordinates"
6520 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6521 {
6522   PetscSection   coordSection, coordSectionNew;
6523   Vec            coordinates, coordinatesNew;
6524   PetscScalar   *coords, *coordsNew;
6525   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6526   PetscErrorCode ierr;
6527 
6528   PetscFunctionBegin;
6529   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6530   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6531   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6532   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6533   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6534   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6535   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6536   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6537   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6538   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6539   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6540   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6541   if (fMax < 0) fMax = fEnd;
6542   switch (refiner) {
6543   case 1:
6544   case 2:
6545   case 3:
6546     /* Simplicial and Hex 2D */
6547     /* All vertices have the dim coordinates */
6548     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6549       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6550       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6551     }
6552     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6553     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6554     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6555     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6556     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6557     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6558     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6559     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6560     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6561     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6562     /* Old vertices have the same coordinates */
6563     for (v = vStart; v < vEnd; ++v) {
6564       const PetscInt newv = vStartNew + (v - vStart);
6565       PetscInt       off, offnew, d;
6566 
6567       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6568       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6569       for (d = 0; d < dim; ++d) {
6570         coordsNew[offnew+d] = coords[off+d];
6571       }
6572     }
6573     /* Face vertices have the average of endpoint coordinates */
6574     for (f = fStart; f < fMax; ++f) {
6575       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6576       const PetscInt *cone;
6577       PetscInt        coneSize, offA, offB, offnew, d;
6578 
6579       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6580       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6581       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6582       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6583       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6584       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6585       for (d = 0; d < dim; ++d) {
6586         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6587       }
6588     }
6589     /* Just Hex 2D */
6590     if (refiner == 2) {
6591       /* Cell vertices have the average of corner coordinates */
6592       for (c = cStart; c < cEnd; ++c) {
6593         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6594         PetscInt      *cone = PETSC_NULL;
6595         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6596 
6597         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6598         for (p = 0; p < closureSize*2; p += 2) {
6599           const PetscInt point = cone[p];
6600           if ((point >= vStart) && (point < vEnd)) {
6601             cone[coneSize++] = point;
6602           }
6603         }
6604         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6605         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6606         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6607         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6608         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6609         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6610         for (d = 0; d < dim; ++d) {
6611           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6612         }
6613         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6614       }
6615     }
6616     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6617     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6618     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6619     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6620     break;
6621   default:
6622     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6623   }
6624   PetscFunctionReturn(0);
6625 }
6626 
6627 #undef __FUNCT__
6628 #define __FUNCT__ "DMPlexCreateProcessSF"
6629 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6630 {
6631   PetscInt           numRoots, numLeaves, l;
6632   const PetscInt    *localPoints;
6633   const PetscSFNode *remotePoints;
6634   PetscInt          *localPointsNew;
6635   PetscSFNode       *remotePointsNew;
6636   PetscInt          *ranks, *ranksNew;
6637   PetscErrorCode     ierr;
6638 
6639   PetscFunctionBegin;
6640   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6641   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6642   for (l = 0; l < numLeaves; ++l) {
6643     ranks[l] = remotePoints[l].rank;
6644   }
6645   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6646   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6647   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6648   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6649   for (l = 0; l < numLeaves; ++l) {
6650     ranksNew[l]              = ranks[l];
6651     localPointsNew[l]        = l;
6652     remotePointsNew[l].index = 0;
6653     remotePointsNew[l].rank  = ranksNew[l];
6654   }
6655   ierr = PetscFree(ranks);CHKERRQ(ierr);
6656   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6657   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6658   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6659   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6660   PetscFunctionReturn(0);
6661 }
6662 
6663 #undef __FUNCT__
6664 #define __FUNCT__ "CellRefinerCreateSF"
6665 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6666 {
6667   PetscSF            sf, sfNew, sfProcess;
6668   IS                 processRanks;
6669   MPI_Datatype       depthType;
6670   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6671   const PetscInt    *localPoints, *neighbors;
6672   const PetscSFNode *remotePoints;
6673   PetscInt          *localPointsNew;
6674   PetscSFNode       *remotePointsNew;
6675   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6676   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6677   PetscErrorCode     ierr;
6678 
6679   PetscFunctionBegin;
6680   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6681   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6682   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6683   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6684   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6685   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6686   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6687   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6688   switch (refiner) {
6689   case 3:
6690     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6691     cMax = PetscMin(cEnd, cMax);
6692     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6693     fMax = PetscMin(fEnd, fMax);
6694   }
6695   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6696   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6697   /* Caculate size of new SF */
6698   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6699   if (numRoots < 0) PetscFunctionReturn(0);
6700   for (l = 0; l < numLeaves; ++l) {
6701     const PetscInt p = localPoints[l];
6702 
6703     switch (refiner) {
6704     case 1:
6705       /* Simplicial 2D */
6706       if ((p >= vStart) && (p < vEnd)) {
6707         /* Old vertices stay the same */
6708         ++numLeavesNew;
6709       } else if ((p >= fStart) && (p < fEnd)) {
6710         /* Old faces add new faces and vertex */
6711         numLeavesNew += 1 + 2;
6712       } else if ((p >= cStart) && (p < cEnd)) {
6713         /* Old cells add new cells and interior faces */
6714         numLeavesNew += 4 + 3;
6715       }
6716       break;
6717     case 2:
6718       /* Hex 2D */
6719       if ((p >= vStart) && (p < vEnd)) {
6720         /* Old vertices stay the same */
6721         ++numLeavesNew;
6722       } else if ((p >= fStart) && (p < fEnd)) {
6723         /* Old faces add new faces and vertex */
6724         numLeavesNew += 1 + 2;
6725       } else if ((p >= cStart) && (p < cEnd)) {
6726         /* Old cells add new cells and interior faces */
6727         numLeavesNew += 4 + 4;
6728       }
6729       break;
6730     default:
6731       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6732     }
6733   }
6734   /* Communicate depthSizes for each remote rank */
6735   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6736   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6737   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6738   ierr = PetscMalloc7(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthMaxOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);CHKERRQ(ierr);
6739   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6740   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6741   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6742   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6743   for (n = 0; n < numNeighbors; ++n) {
6744     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6745   }
6746   depthSizeOld[depth]   = cMax;
6747   depthSizeOld[0]       = vMax;
6748   depthSizeOld[depth-1] = fMax;
6749   depthSizeOld[1]       = eMax;
6750   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6751   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6752   depthSizeOld[depth]   = cEnd - cStart;
6753   depthSizeOld[0]       = vEnd - vStart;
6754   depthSizeOld[depth-1] = fEnd - fStart;
6755   depthSizeOld[1]       = eEnd - eStart;
6756   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6757   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6758   for (n = 0; n < numNeighbors; ++n) {
6759     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6760   }
6761   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6762   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6763   /* Calculate new point SF */
6764   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6765   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6766   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6767   for (l = 0, m = 0; l < numLeaves; ++l) {
6768     PetscInt    p     = localPoints[l];
6769     PetscInt    rp    = remotePoints[l].index, n;
6770     PetscMPIInt rrank = remotePoints[l].rank;
6771 
6772     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6773     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6774     switch (refiner) {
6775     case 1:
6776       /* Simplicial 2D */
6777       if ((p >= vStart) && (p < vEnd)) {
6778         /* Old vertices stay the same */
6779         localPointsNew[m]        = vStartNew     + (p  - vStart);
6780         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6781         remotePointsNew[m].rank  = rrank;
6782         ++m;
6783       } else if ((p >= fStart) && (p < fEnd)) {
6784         /* Old faces add new faces and vertex */
6785         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6786         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6787         remotePointsNew[m].rank  = rrank;
6788         ++m;
6789         for (r = 0; r < 2; ++r, ++m) {
6790           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6791           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6792           remotePointsNew[m].rank  = rrank;
6793         }
6794       } else if ((p >= cStart) && (p < cEnd)) {
6795         /* Old cells add new cells and interior faces */
6796         for (r = 0; r < 4; ++r, ++m) {
6797           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6798           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6799           remotePointsNew[m].rank  = rrank;
6800         }
6801         for (r = 0; r < 3; ++r, ++m) {
6802           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6803           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6804           remotePointsNew[m].rank  = rrank;
6805         }
6806       }
6807       break;
6808     case 2:
6809       /* Hex 2D */
6810       if ((p >= vStart) && (p < vEnd)) {
6811         /* Old vertices stay the same */
6812         localPointsNew[m]        = vStartNew     + (p  - vStart);
6813         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6814         remotePointsNew[m].rank  = rrank;
6815         ++m;
6816       } else if ((p >= fStart) && (p < fEnd)) {
6817         /* Old faces add new faces and vertex */
6818         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6819         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6820         remotePointsNew[m].rank  = rrank;
6821         ++m;
6822         for (r = 0; r < 2; ++r, ++m) {
6823           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6824           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6825           remotePointsNew[m].rank  = rrank;
6826         }
6827       } else if ((p >= cStart) && (p < cEnd)) {
6828         /* Old cells add new cells and interior faces */
6829         for (r = 0; r < 4; ++r, ++m) {
6830           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6831           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6832           remotePointsNew[m].rank  = rrank;
6833         }
6834         for (r = 0; r < 4; ++r, ++m) {
6835           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6836           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6837           remotePointsNew[m].rank  = rrank;
6838         }
6839       }
6840       break;
6841     case 3:
6842       /* Hybrid simplicial 2D */
6843       if ((p >= vStart) && (p < vEnd)) {
6844         /* Old vertices stay the same */
6845         localPointsNew[m]        = vStartNew     + (p  - vStart);
6846         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6847         remotePointsNew[m].rank  = rrank;
6848         ++m;
6849       } else if ((p >= fStart) && (p < fMax)) {
6850         /* Old interior faces add new faces and vertex */
6851         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6852         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6853         remotePointsNew[m].rank  = rrank;
6854         ++m;
6855         for (r = 0; r < 2; ++r, ++m) {
6856           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6857           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6858           remotePointsNew[m].rank  = rrank;
6859         }
6860       } else if ((p >= fMax) && (p < fEnd)) {
6861         /* Old hybrid faces stay the same */
6862         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6863         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6864         remotePointsNew[m].rank  = rrank;
6865         ++m;
6866       } else if ((p >= cStart) && (p < cMax)) {
6867         /* Old interior cells add new cells and interior faces */
6868         for (r = 0; r < 4; ++r, ++m) {
6869           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6870           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6871           remotePointsNew[m].rank  = rrank;
6872         }
6873         for (r = 0; r < 3; ++r, ++m) {
6874           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6875           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6876           remotePointsNew[m].rank  = rrank;
6877         }
6878       } else if ((p >= cStart) && (p < cMax)) {
6879         /* Old hybrid cells add new cells and hybrid face */
6880         for (r = 0; r < 2; ++r, ++m) {
6881           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6882           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6883           remotePointsNew[m].rank  = rrank;
6884         }
6885         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6886         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
6887         remotePointsNew[m].rank  = rrank;
6888         ++m;
6889       }
6890       break;
6891     default:
6892       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6893     }
6894   }
6895   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6896   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6897   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6898   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6899   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6900   PetscFunctionReturn(0);
6901 }
6902 
6903 #undef __FUNCT__
6904 #define __FUNCT__ "CellRefinerCreateLabels"
6905 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6906 {
6907   PetscInt       numLabels, l;
6908   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6909   PetscErrorCode ierr;
6910 
6911   PetscFunctionBegin;
6912   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6913   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6914   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6915   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6916   cStartNew = 0;
6917   vStartNew = depthSize[2];
6918   fStartNew = depthSize[2] + depthSize[0];
6919   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6920   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6921   switch (refiner) {
6922   case 3:
6923     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6924     cMax = PetscMin(cEnd, cMax);
6925     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6926     fMax = PetscMin(fEnd, fMax);
6927   }
6928   for (l = 0; l < numLabels; ++l) {
6929     DMLabel         label, labelNew;
6930     const char     *lname;
6931     PetscBool       isDepth;
6932     IS              valueIS;
6933     const PetscInt *values;
6934     PetscInt        numValues, val;
6935 
6936     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6937     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6938     if (isDepth) continue;
6939     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6940     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6941     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6942     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6943     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6944     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6945     for (val = 0; val < numValues; ++val) {
6946       IS              pointIS;
6947       const PetscInt *points;
6948       PetscInt        numPoints, n;
6949 
6950       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6951       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6952       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6953       for (n = 0; n < numPoints; ++n) {
6954         const PetscInt p = points[n];
6955         switch (refiner) {
6956         case 1:
6957           /* Simplicial 2D */
6958           if ((p >= vStart) && (p < vEnd)) {
6959             /* Old vertices stay the same */
6960             newp = vStartNew + (p - vStart);
6961             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6962           } else if ((p >= fStart) && (p < fEnd)) {
6963             /* Old faces add new faces and vertex */
6964             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6965             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6966             for (r = 0; r < 2; ++r) {
6967               newp = fStartNew + (p - fStart)*2 + r;
6968               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6969             }
6970           } else if ((p >= cStart) && (p < cEnd)) {
6971             /* Old cells add new cells and interior faces */
6972             for (r = 0; r < 4; ++r) {
6973               newp = cStartNew + (p - cStart)*4 + r;
6974               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6975             }
6976             for (r = 0; r < 3; ++r) {
6977               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6978               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6979             }
6980           }
6981           break;
6982         case 2:
6983           /* Hex 2D */
6984           if ((p >= vStart) && (p < vEnd)) {
6985             /* Old vertices stay the same */
6986             newp = vStartNew + (p - vStart);
6987             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6988           } else if ((p >= fStart) && (p < fEnd)) {
6989             /* Old faces add new faces and vertex */
6990             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6991             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6992             for (r = 0; r < 2; ++r) {
6993               newp = fStartNew + (p - fStart)*2 + r;
6994               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6995             }
6996           } else if ((p >= cStart) && (p < cEnd)) {
6997             /* Old cells add new cells and interior faces and vertex */
6998             for (r = 0; r < 4; ++r) {
6999               newp = cStartNew + (p - cStart)*4 + r;
7000               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7001             }
7002             for (r = 0; r < 4; ++r) {
7003               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7004               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7005             }
7006             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7007             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7008           }
7009           break;
7010         case 3:
7011           /* Hybrid simplicial 2D */
7012           if ((p >= vStart) && (p < vEnd)) {
7013             /* Old vertices stay the same */
7014             newp = vStartNew + (p - vStart);
7015             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7016           } else if ((p >= fStart) && (p < fMax)) {
7017             /* Old interior faces add new faces and vertex */
7018             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7019             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7020             for (r = 0; r < 2; ++r) {
7021               newp = fStartNew + (p - fStart)*2 + r;
7022               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7023             }
7024           } else if ((p >= fMax) && (p < fEnd)) {
7025             /* Old hybrid faces stay the same */
7026             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7027             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7028           } else if ((p >= cStart) && (p < cMax)) {
7029             /* Old interior cells add new cells and interior faces */
7030             for (r = 0; r < 4; ++r) {
7031               newp = cStartNew + (p - cStart)*4 + r;
7032               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7033             }
7034             for (r = 0; r < 3; ++r) {
7035               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7036               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7037             }
7038           } else if ((p >= cMax) && (p < cEnd)) {
7039             /* Old hybrid cells add new cells and hybrid face */
7040             for (r = 0; r < 2; ++r) {
7041               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7042               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7043             }
7044             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7045             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7046           }
7047           break;
7048         default:
7049           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7050         }
7051       }
7052       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7053       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7054     }
7055     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7056     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7057     if (0) {
7058       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7059       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7060       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7061     }
7062   }
7063   PetscFunctionReturn(0);
7064 }
7065 
7066 #undef __FUNCT__
7067 #define __FUNCT__ "DMPlexRefine_Uniform"
7068 /* This will only work for interpolated meshes */
7069 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7070 {
7071   DM              rdm;
7072   PetscInt       *depthSize;
7073   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
7074   PetscErrorCode  ierr;
7075 
7076   PetscFunctionBegin;
7077   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7078   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7079   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7080   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7081   /* Calculate number of new points of each depth */
7082   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7083   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7084   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7085   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7086   /* Step 1: Set chart */
7087   for (d = 0; d <= depth; ++d) {
7088     pEnd += depthSize[d];
7089   }
7090   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7091   /* Step 2: Set cone/support sizes */
7092   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7093   /* Step 3: Setup refined DM */
7094   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7095   /* Step 4: Set cones and supports */
7096   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7097   /* Step 5: Stratify */
7098   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7099   /* Step 6: Set coordinates for vertices */
7100   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7101   /* Step 7: Create pointSF */
7102   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7103   /* Step 8: Create labels */
7104   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7105   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7106 
7107   *dmRefined = rdm;
7108 #if 0
7109   DM_Plex *mesh = (DM_Plex *) dm->data;
7110   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7111   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7112 
7113   PetscFunctionBegin;
7114   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7115   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7116   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7117   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7118   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7119 
7120   /* Count number of new cells which are normal and extra */
7121   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7122   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7123   for (c = cStart; c < cEnd2; ++c) {
7124     PetscInt n;
7125     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7126     newNumCellsNormal += n;
7127   }
7128   for (c = cEnd2; c < cEnd; ++c) {
7129     PetscInt n;
7130     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7131     newNumCellsExtra += n;
7132   }
7133   newNumCells = newNumCellsNormal + newNumCellsExtra;
7134   /* Count number of new vertices which are normal and extra */
7135   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7136   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7137   for (c = cStart; c < cEnd; ++c) {
7138     PetscInt *closure = PETSC_NULL;
7139     PetscInt  closureSize, numCorners = 0, p;
7140 
7141     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7142     for (p = 0; p < closureSize*2; p += 2) {
7143       const PetscInt point = closure[p];
7144       if ((point >= vStart) && (point < vEnd)) {
7145         closure[numCorners++] = point;
7146       }
7147     }
7148     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7149     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7150   }
7151   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7152   for (c = cEnd2; c < cEnd; ++c) {
7153     PetscInt *closure = PETSC_NULL;
7154     PetscInt  closureSize, numCorners = 0, p;
7155 
7156     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7157     for (p = 0; p < closureSize*2; p += 2) {
7158       const PetscInt point = closure[p];
7159       if ((point >= vStart) && (point < vEnd)) {
7160         closure[numCorners++] = point;
7161       }
7162     }
7163     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7164     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7165   } /* for */
7166   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7167   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
7168 
7169 #if 1
7170   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
7171   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
7172   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7173   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7174   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7175   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7176   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7177   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7178   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7179   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7180   ierr = PetscSynchronizedFlush(comm);
7181 #endif
7182 
7183   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7184   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7185   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7186   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7187   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7188   /* Set cone and support sizes for new normal cells */
7189   PetscInt newCell = 0;
7190   for (c = cStart; c < cEnd2; ++c) {
7191     PetscInt coneSize, n, i;
7192 
7193     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7194     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7195     for (i = 0; i < n; ++i, ++newCell) {
7196       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7197     }
7198 
7199     PetscInt *closure = PETSC_NULL;
7200     PetscInt  closureSize, numCorners = 0, p;
7201 
7202     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7203     for (p = 0; p < closureSize*2; p += 2) {
7204       const PetscInt point = closure[p];
7205       if ((point >= vStart) && (point < vEnd)) {
7206         closure[numCorners++] = point;
7207       }
7208     }
7209     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7210     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7211   }
7212 
7213   /* Reset current new cell value and loop over censored cells. */
7214   curNewCell = _orderNewMesh->cellsCensored().min();
7215   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7216   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7217     /* Set new cone and support sizes */
7218     cV.clear();
7219     sieve->cone(*c_iter, cV);
7220     const point_type* cone = cV.getPoints();
7221     const int coneSize = cV.getSize();
7222 
7223     const point_type* newCells;
7224     int numNewCells = 0;
7225     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7226 
7227     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7228       newSieve->setConeSize(curNewCell, coneSize);
7229       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7230         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7231       } /* for */
7232     } /* for */
7233   } /* for */
7234   newSieve->allocate();
7235 
7236   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7237 
7238   /* Create refined cells in new sieve. */
7239   curNewCell = _orderNewMesh->cellsNormal().min();
7240   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7241   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7242     cV.clear();
7243     sieve->cone(*c_iter, cV);
7244     const point_type *cone = cV.getPoints();
7245     const int coneSize = cV.getSize();
7246 
7247     const point_type* newCells;
7248     int numNewCells = 0;
7249     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7250 
7251     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7252       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7253     } /* for */
7254   } /* for */
7255   curNewCell = _orderNewMesh->cellsCensored().min();
7256   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7257   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7258     cV.clear();
7259     sieve->cone(*c_iter, cV);
7260     const point_type *cone = cV.getPoints();
7261     const int coneSize = cV.getSize();
7262 
7263     const point_type* newCells;
7264     int numNewCells = 0;
7265     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7266 
7267     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7268       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7269     } /* for */
7270   } /* for */
7271   newSieve->symmetrize();
7272 
7273   /* Set coordinates in refined mesh. */
7274   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7275   assert(!coordinates.isNull());
7276   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7277   assert(!newCoordinates.isNull());
7278 
7279   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7280   assert(vertices->size() > 0);
7281   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7282   assert(spaceDim > 0);
7283   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7284 
7285   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7286   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7287     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7288   } /* for */
7289   newCoordinates->allocatePoint();
7290 
7291   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7292   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7293     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7294     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7295   } /* for */
7296   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7297   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7298     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7299     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7300   } /* for */
7301 
7302   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7303 
7304   /* Create sensored depth */
7305   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7306   assert(!censoredLabel.isNull());
7307 
7308   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7309 
7310   newSieve->roots(depthVisitor);
7311   while (depthVisitor.isModified()) {
7312     /* FIX: Avoid the copy here somehow by fixing the traversal */
7313     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7314 
7315     depthVisitor.clear();
7316     newSieve->support(modifiedPoints, depthVisitor);
7317   } /* while */
7318   /* Stratify refined mesh */
7319   /* Calculate new point SF */
7320   _calcNewOverlap(newMesh, mesh, refiner);
7321   /* Calculate new labels */
7322   _createLabels(newMesh, mesh, refiner);
7323 #endif
7324   PetscFunctionReturn(0);
7325 }
7326 
7327 #undef __FUNCT__
7328 #define __FUNCT__ "DMPlexSetRefinementUniform"
7329 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7330 {
7331   DM_Plex *mesh = (DM_Plex *) dm->data;
7332 
7333   PetscFunctionBegin;
7334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7335   mesh->refinementUniform = refinementUniform;
7336   PetscFunctionReturn(0);
7337 }
7338 
7339 #undef __FUNCT__
7340 #define __FUNCT__ "DMPlexGetRefinementUniform"
7341 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7342 {
7343   DM_Plex *mesh = (DM_Plex *) dm->data;
7344 
7345   PetscFunctionBegin;
7346   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7347   PetscValidPointer(refinementUniform,  2);
7348   *refinementUniform = mesh->refinementUniform;
7349   PetscFunctionReturn(0);
7350 }
7351 
7352 #undef __FUNCT__
7353 #define __FUNCT__ "DMPlexSetRefinementLimit"
7354 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7355 {
7356   DM_Plex *mesh = (DM_Plex *) dm->data;
7357 
7358   PetscFunctionBegin;
7359   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7360   mesh->refinementLimit = refinementLimit;
7361   PetscFunctionReturn(0);
7362 }
7363 
7364 #undef __FUNCT__
7365 #define __FUNCT__ "DMPlexGetRefinementLimit"
7366 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7367 {
7368   DM_Plex *mesh = (DM_Plex *) dm->data;
7369 
7370   PetscFunctionBegin;
7371   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7372   PetscValidPointer(refinementLimit,  2);
7373   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7374   *refinementLimit = mesh->refinementLimit;
7375   PetscFunctionReturn(0);
7376 }
7377 
7378 #undef __FUNCT__
7379 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7380 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7381 {
7382   PetscInt       dim, cStart, coneSize, cMax;
7383   PetscErrorCode ierr;
7384 
7385   PetscFunctionBegin;
7386   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7387   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7388   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7389   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7390   switch (dim) {
7391   case 2:
7392     switch (coneSize) {
7393     case 3:
7394       if (cMax >= 0) {
7395         *cellRefiner = 3; /* Hybrid */
7396       } else {
7397         *cellRefiner = 1; /* Triangular */
7398       }
7399       break;
7400     case 4:
7401       if (cMax >= 0) {
7402         *cellRefiner = 4; /* Hybrid */
7403       } else {
7404         *cellRefiner = 2; /* Quadrilateral */
7405       }
7406       break;
7407     default:
7408       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7409     }
7410     break;
7411   default:
7412     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7413   }
7414   PetscFunctionReturn(0);
7415 }
7416 
7417 #undef __FUNCT__
7418 #define __FUNCT__ "DMRefine_Plex"
7419 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7420 {
7421   PetscReal      refinementLimit;
7422   PetscInt       dim, cStart, cEnd;
7423   char           genname[1024], *name = PETSC_NULL;
7424   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7425   PetscErrorCode ierr;
7426 
7427   PetscFunctionBegin;
7428   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7429   if (isUniform) {
7430     CellRefiner cellRefiner;
7431 
7432     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7433     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7434     PetscFunctionReturn(0);
7435   }
7436   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7437   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7438   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7439   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7440   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7441   if (flg) {name = genname;}
7442   if (name) {
7443     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7444     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7445     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7446   }
7447   switch (dim) {
7448   case 2:
7449     if (!name || isTriangle) {
7450 #if defined(PETSC_HAVE_TRIANGLE)
7451       double  *maxVolumes;
7452       PetscInt c;
7453 
7454       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7455       for (c = 0; c < cEnd-cStart; ++c) {
7456         maxVolumes[c] = refinementLimit;
7457       }
7458       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7459 #else
7460       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7461 #endif
7462     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7463     break;
7464   case 3:
7465     if (!name || isCTetgen) {
7466 #if defined(PETSC_HAVE_CTETGEN)
7467       PetscReal *maxVolumes;
7468       PetscInt   c;
7469 
7470       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7471       for (c = 0; c < cEnd-cStart; ++c) {
7472         maxVolumes[c] = refinementLimit;
7473       }
7474       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7475 #else
7476       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7477 #endif
7478     } else if (isTetgen) {
7479 #if defined(PETSC_HAVE_TETGEN)
7480       double  *maxVolumes;
7481       PetscInt c;
7482 
7483       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7484       for (c = 0; c < cEnd-cStart; ++c) {
7485         maxVolumes[c] = refinementLimit;
7486       }
7487       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7488 #else
7489       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7490 #endif
7491     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7492     break;
7493   default:
7494     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7495   }
7496   PetscFunctionReturn(0);
7497 }
7498 
7499 #undef __FUNCT__
7500 #define __FUNCT__ "DMPlexGetDepth"
7501 /*@
7502   DMPlexGetDepth - get the number of strata
7503 
7504   Not Collective
7505 
7506   Input Parameters:
7507 . dm           - The DMPlex object
7508 
7509   Output Parameters:
7510 . depth - number of strata
7511 
7512   Level: developer
7513 
7514   Notes:
7515   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7516 
7517 .keywords: mesh, points
7518 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7519 @*/
7520 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7521 {
7522   PetscInt       d;
7523   PetscErrorCode ierr;
7524 
7525   PetscFunctionBegin;
7526   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7527   PetscValidPointer(depth, 2);
7528   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7529   *depth = d-1;
7530   PetscFunctionReturn(0);
7531 }
7532 
7533 #undef __FUNCT__
7534 #define __FUNCT__ "DMPlexGetDepthStratum"
7535 /*@
7536   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7537 
7538   Not Collective
7539 
7540   Input Parameters:
7541 + dm           - The DMPlex object
7542 - stratumValue - The requested depth
7543 
7544   Output Parameters:
7545 + start - The first point at this depth
7546 - end   - One beyond the last point at this depth
7547 
7548   Level: developer
7549 
7550 .keywords: mesh, points
7551 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7552 @*/
7553 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7554 {
7555   DM_Plex    *mesh = (DM_Plex *) dm->data;
7556   DMLabel        next = mesh->labels;
7557   PetscBool      flg  = PETSC_FALSE;
7558   PetscInt       depth;
7559   PetscErrorCode ierr;
7560 
7561   PetscFunctionBegin;
7562   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7563   if (stratumValue < 0) {
7564     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7565     PetscFunctionReturn(0);
7566   } else {
7567     PetscInt pStart, pEnd;
7568 
7569     if (start) {*start = 0;}
7570     if (end)   {*end   = 0;}
7571     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7572     if (pStart == pEnd) {PetscFunctionReturn(0);}
7573   }
7574   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7575   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7576   /* We should have a generic GetLabel() and a Label class */
7577   while (next) {
7578     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7579     if (flg) break;
7580     next = next->next;
7581   }
7582   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7583   depth = stratumValue;
7584   if ((depth < 0) || (depth >= next->numStrata)) {
7585     if (start) {*start = 0;}
7586     if (end)   {*end   = 0;}
7587   } else {
7588     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7589     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7590   }
7591   PetscFunctionReturn(0);
7592 }
7593 
7594 #undef __FUNCT__
7595 #define __FUNCT__ "DMPlexGetHeightStratum"
7596 /*@
7597   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7598 
7599   Not Collective
7600 
7601   Input Parameters:
7602 + dm           - The DMPlex object
7603 - stratumValue - The requested height
7604 
7605   Output Parameters:
7606 + start - The first point at this height
7607 - end   - One beyond the last point at this height
7608 
7609   Level: developer
7610 
7611 .keywords: mesh, points
7612 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7613 @*/
7614 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7615 {
7616   DM_Plex        *mesh = (DM_Plex *) dm->data;
7617   DMLabel        next = mesh->labels;
7618   PetscBool      flg  = PETSC_FALSE;
7619   PetscInt       depth;
7620   PetscErrorCode ierr;
7621 
7622   PetscFunctionBegin;
7623   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7624   if (stratumValue < 0) {
7625     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7626   } else {
7627     PetscInt pStart, pEnd;
7628 
7629     if (start) {*start = 0;}
7630     if (end)   {*end   = 0;}
7631     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7632     if (pStart == pEnd) {PetscFunctionReturn(0);}
7633   }
7634   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7635   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7636   /* We should have a generic GetLabel() and a Label class */
7637   while (next) {
7638     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7639     if (flg) break;
7640     next = next->next;
7641   }
7642   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7643   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7644   if ((depth < 0) || (depth >= next->numStrata)) {
7645     if (start) {*start = 0;}
7646     if (end)   {*end   = 0;}
7647   } else {
7648     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7649     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7650   }
7651   PetscFunctionReturn(0);
7652 }
7653 
7654 #undef __FUNCT__
7655 #define __FUNCT__ "DMPlexCreateSectionInitial"
7656 /* Set the number of dof on each point and separate by fields */
7657 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7658 {
7659   PetscInt      *numDofTot;
7660   PetscInt       pStart = 0, pEnd = 0;
7661   PetscInt       p, d, f;
7662   PetscErrorCode ierr;
7663 
7664   PetscFunctionBegin;
7665   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7666   for (d = 0; d <= dim; ++d) {
7667     numDofTot[d] = 0;
7668     for (f = 0; f < numFields; ++f) {
7669       numDofTot[d] += numDof[f*(dim+1)+d];
7670     }
7671   }
7672   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7673   if (numFields > 0) {
7674     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7675     if (numComp) {
7676       for (f = 0; f < numFields; ++f) {
7677         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7678       }
7679     }
7680   }
7681   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7682   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7683   for (d = 0; d <= dim; ++d) {
7684     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7685     for (p = pStart; p < pEnd; ++p) {
7686       for (f = 0; f < numFields; ++f) {
7687         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7688       }
7689       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7690     }
7691   }
7692   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7693   PetscFunctionReturn(0);
7694 }
7695 
7696 #undef __FUNCT__
7697 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7698 /* Set the number of dof on each point and separate by fields
7699    If constDof is PETSC_DETERMINE, constrain every dof on the point
7700 */
7701 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7702 {
7703   PetscInt       numFields;
7704   PetscInt       bc;
7705   PetscErrorCode ierr;
7706 
7707   PetscFunctionBegin;
7708   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7709   for (bc = 0; bc < numBC; ++bc) {
7710     PetscInt        field = 0;
7711     const PetscInt *idx;
7712     PetscInt        n, i;
7713 
7714     if (numFields) {field = bcField[bc];}
7715     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7716     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7717     for (i = 0; i < n; ++i) {
7718       const PetscInt p = idx[i];
7719       PetscInt       numConst = constDof;
7720 
7721       /* Constrain every dof on the point */
7722       if (numConst < 0) {
7723         if (numFields) {
7724           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7725         } else {
7726           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7727         }
7728       }
7729       if (numFields) {
7730         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7731       }
7732       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7733     }
7734     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7735   }
7736   PetscFunctionReturn(0);
7737 }
7738 
7739 #undef __FUNCT__
7740 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7741 /* Set the constrained indices on each point and separate by fields */
7742 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7743 {
7744   PetscInt      *maxConstraints;
7745   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7746   PetscErrorCode ierr;
7747 
7748   PetscFunctionBegin;
7749   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7750   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7751   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7752   for (f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
7753   for (p = pStart; p < pEnd; ++p) {
7754     PetscInt cdof;
7755 
7756     if (numFields) {
7757       for (f = 0; f < numFields; ++f) {
7758         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7759         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7760       }
7761     } else {
7762       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7763       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7764     }
7765   }
7766   for (f = 0; f < numFields; ++f) {
7767     maxConstraints[numFields] += maxConstraints[f];
7768   }
7769   if (maxConstraints[numFields]) {
7770     PetscInt *indices;
7771 
7772     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7773     for (p = pStart; p < pEnd; ++p) {
7774       PetscInt cdof, d;
7775 
7776       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7777       if (cdof) {
7778         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7779         if (numFields) {
7780           PetscInt numConst = 0, foff = 0;
7781 
7782           for (f = 0; f < numFields; ++f) {
7783             PetscInt cfdof, fdof;
7784 
7785             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7786             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7787             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7788             for (d = 0; d < cfdof; ++d) {
7789               indices[numConst+d] = d;
7790             }
7791             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7792             for (d = 0; d < cfdof; ++d) {
7793               indices[numConst+d] += foff;
7794             }
7795             numConst += cfdof;
7796             foff     += fdof;
7797           }
7798           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7799         } else {
7800           for (d = 0; d < cdof; ++d) {
7801             indices[d] = d;
7802           }
7803         }
7804         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7805       }
7806     }
7807     ierr = PetscFree(indices);CHKERRQ(ierr);
7808   }
7809   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7810   PetscFunctionReturn(0);
7811 }
7812 
7813 #undef __FUNCT__
7814 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7815 /* Set the constrained field indices on each point */
7816 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7817 {
7818   const PetscInt *points, *indices;
7819   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7820   PetscErrorCode  ierr;
7821 
7822   PetscFunctionBegin;
7823   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7824   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7825 
7826   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7827   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7828   if (!constraintIndices) {
7829     PetscInt *idx, i;
7830 
7831     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7832     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7833     for (i = 0; i < maxDof; ++i) {idx[i] = i;}
7834     for (p = 0; p < numPoints; ++p) {
7835       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7836     }
7837     ierr = PetscFree(idx);CHKERRQ(ierr);
7838   } else {
7839     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7840     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7841     for (p = 0; p < numPoints; ++p) {
7842       PetscInt fcdof;
7843 
7844       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7845       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);
7846       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7847     }
7848     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7849   }
7850   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7851   PetscFunctionReturn(0);
7852 }
7853 
7854 #undef __FUNCT__
7855 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7856 /* Set the constrained indices on each point and separate by fields */
7857 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7858 {
7859   PetscInt      *indices;
7860   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7861   PetscErrorCode ierr;
7862 
7863   PetscFunctionBegin;
7864   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7865   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7866   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7867   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7868   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7869   for (p = pStart; p < pEnd; ++p) {
7870     PetscInt cdof, d;
7871 
7872     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7873     if (cdof) {
7874       PetscInt numConst = 0, foff = 0;
7875 
7876       for (f = 0; f < numFields; ++f) {
7877         const PetscInt *fcind;
7878         PetscInt        fdof, fcdof;
7879 
7880         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7881         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7882         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7883         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7884         for (d = 0; d < fcdof; ++d) {
7885           indices[numConst+d] = fcind[d]+foff;
7886         }
7887         foff     += fdof;
7888         numConst += fcdof;
7889       }
7890       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7891       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7892     }
7893   }
7894   ierr = PetscFree(indices);CHKERRQ(ierr);
7895   PetscFunctionReturn(0);
7896 }
7897 
7898 #undef __FUNCT__
7899 #define __FUNCT__ "DMPlexCreateSection"
7900 /*@C
7901   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7902 
7903   Not Collective
7904 
7905   Input Parameters:
7906 + dm        - The DMPlex object
7907 . dim       - The spatial dimension of the problem
7908 . numFields - The number of fields in the problem
7909 . numComp   - An array of size numFields that holds the number of components for each field
7910 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7911 . numBC     - The number of boundary conditions
7912 . bcField   - An array of size numBC giving the field number for each boundry condition
7913 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7914 
7915   Output Parameter:
7916 . section - The PetscSection object
7917 
7918   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
7919   nubmer of dof for field 0 on each edge.
7920 
7921   Level: developer
7922 
7923 .keywords: mesh, elements
7924 .seealso: DMPlexCreate(), PetscSectionCreate()
7925 @*/
7926 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
7927 {
7928   PetscErrorCode ierr;
7929 
7930   PetscFunctionBegin;
7931   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7932   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7933   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7934   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7935   {
7936     PetscBool view = PETSC_FALSE;
7937 
7938     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7939     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7940   }
7941   PetscFunctionReturn(0);
7942 }
7943 
7944 #undef __FUNCT__
7945 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7946 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
7947 {
7948   PetscSection   section;
7949   PetscErrorCode ierr;
7950 
7951   PetscFunctionBegin;
7952   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7953   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
7954   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7955   PetscFunctionReturn(0);
7956 }
7957 
7958 #undef __FUNCT__
7959 #define __FUNCT__ "DMPlexGetCoordinateSection"
7960 /*@
7961   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7962 
7963   Not Collective
7964 
7965   Input Parameter:
7966 . dm - The DMPlex object
7967 
7968   Output Parameter:
7969 . section - The PetscSection object
7970 
7971   Level: intermediate
7972 
7973 .keywords: mesh, coordinates
7974 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7975 @*/
7976 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
7977 {
7978   DM             cdm;
7979   PetscErrorCode ierr;
7980 
7981   PetscFunctionBegin;
7982   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7983   PetscValidPointer(section, 2);
7984   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7985   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7986   PetscFunctionReturn(0);
7987 }
7988 
7989 #undef __FUNCT__
7990 #define __FUNCT__ "DMPlexSetCoordinateSection"
7991 /*@
7992   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7993 
7994   Not Collective
7995 
7996   Input Parameters:
7997 + dm      - The DMPlex object
7998 - section - The PetscSection object
7999 
8000   Level: intermediate
8001 
8002 .keywords: mesh, coordinates
8003 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8004 @*/
8005 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8006 {
8007   DM             cdm;
8008   PetscErrorCode ierr;
8009 
8010   PetscFunctionBegin;
8011   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8012   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8013   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8014   PetscFunctionReturn(0);
8015 }
8016 
8017 #undef __FUNCT__
8018 #define __FUNCT__ "DMPlexGetConeSection"
8019 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8020 {
8021   DM_Plex *mesh = (DM_Plex *) dm->data;
8022 
8023   PetscFunctionBegin;
8024   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8025   if (section) *section = mesh->coneSection;
8026   PetscFunctionReturn(0);
8027 }
8028 
8029 #undef __FUNCT__
8030 #define __FUNCT__ "DMPlexGetCones"
8031 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8032 {
8033   DM_Plex *mesh = (DM_Plex *) dm->data;
8034 
8035   PetscFunctionBegin;
8036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8037   if (cones) *cones = mesh->cones;
8038   PetscFunctionReturn(0);
8039 }
8040 
8041 #undef __FUNCT__
8042 #define __FUNCT__ "DMPlexGetConeOrientations"
8043 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8044 {
8045   DM_Plex *mesh = (DM_Plex *) dm->data;
8046 
8047   PetscFunctionBegin;
8048   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8049   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8050   PetscFunctionReturn(0);
8051 }
8052 
8053 #undef __FUNCT__
8054 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8055 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8056 {
8057   const PetscInt embedDim = 2;
8058   PetscReal      x = PetscRealPart(point[0]);
8059   PetscReal      y = PetscRealPart(point[1]);
8060   PetscReal      v0[2], J[4], invJ[4], detJ;
8061   PetscReal      xi, eta;
8062   PetscErrorCode ierr;
8063 
8064   PetscFunctionBegin;
8065   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8066   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8067   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8068 
8069   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
8070     *cell = c;
8071   } else {
8072     *cell = -1;
8073   }
8074   PetscFunctionReturn(0);
8075 }
8076 
8077 #undef __FUNCT__
8078 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8079 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8080 {
8081   PetscSection       coordSection;
8082   Vec                coordsLocal;
8083   const PetscScalar *coords;
8084   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8085   PetscReal          x         = PetscRealPart(point[0]);
8086   PetscReal          y         = PetscRealPart(point[1]);
8087   PetscInt           crossings = 0, f;
8088   PetscErrorCode     ierr;
8089 
8090   PetscFunctionBegin;
8091   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8092   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8093   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8094   for (f = 0; f < 4; ++f) {
8095     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8096     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8097     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8098     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8099     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8100     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8101     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8102     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8103     if ((cond1 || cond2)  && above) ++crossings;
8104   }
8105   if (crossings % 2) {
8106     *cell = c;
8107   } else {
8108     *cell = -1;
8109   }
8110   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8111   PetscFunctionReturn(0);
8112 }
8113 
8114 #undef __FUNCT__
8115 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8116 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8117 {
8118   const PetscInt embedDim = 3;
8119   PetscReal      v0[3], J[9], invJ[9], detJ;
8120   PetscReal      x = PetscRealPart(point[0]);
8121   PetscReal      y = PetscRealPart(point[1]);
8122   PetscReal      z = PetscRealPart(point[2]);
8123   PetscReal      xi, eta, zeta;
8124   PetscErrorCode ierr;
8125 
8126   PetscFunctionBegin;
8127   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8128   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8129   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8130   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8131 
8132   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
8133     *cell = c;
8134   } else {
8135     *cell = -1;
8136   }
8137   PetscFunctionReturn(0);
8138 }
8139 
8140 #undef __FUNCT__
8141 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8142 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8143 {
8144   PetscSection       coordSection;
8145   Vec                coordsLocal;
8146   const PetscScalar *coords;
8147   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8148                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8149   PetscBool          found     = PETSC_TRUE;
8150   PetscInt           f;
8151   PetscErrorCode     ierr;
8152 
8153   PetscFunctionBegin;
8154   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8155   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8156   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8157   for (f = 0; f < 6; ++f) {
8158     /* Check the point is under plane */
8159     /*   Get face normal */
8160     PetscReal v_i[3]    = {PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]),
8161                            PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]),
8162                            PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2])};
8163     PetscReal v_j[3]    = {PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]),
8164                            PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]),
8165                            PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2])};
8166     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]};
8167     PetscReal pp[3]     = {PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]),
8168                            PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]),
8169                            PetscRealPart(coords[faces[f*4+0]*3+2] - point[2])};
8170     PetscReal dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8171     /* Check that projected point is in face (2D location problem) */
8172     if (dot < 0.0) {
8173       found = PETSC_FALSE;
8174       break;
8175     }
8176   }
8177   if (found) {
8178     *cell = c;
8179   } else {
8180     *cell = -1;
8181   }
8182   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8183   PetscFunctionReturn(0);
8184 }
8185 
8186 #undef __FUNCT__
8187 #define __FUNCT__ "DMLocatePoints_Plex"
8188 /*
8189  Need to implement using the guess
8190 */
8191 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8192 {
8193   PetscInt       cell = -1/*, guess = -1*/;
8194   PetscInt       bs, numPoints, p;
8195   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8196   PetscInt      *cells;
8197   PetscScalar   *a;
8198   PetscErrorCode ierr;
8199 
8200   PetscFunctionBegin;
8201   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8202   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8203   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8204   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8205   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8206   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8207   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8208   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);
8209   numPoints /= bs;
8210   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8211   for (p = 0; p < numPoints; ++p) {
8212     const PetscScalar *point = &a[p*bs];
8213 
8214     switch (dim) {
8215     case 2:
8216       for (c = cStart; c < cEnd; ++c) {
8217         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8218         switch (coneSize) {
8219         case 3:
8220           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8221           break;
8222         case 4:
8223           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8224           break;
8225         default:
8226           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8227         }
8228         if (cell >= 0) break;
8229       }
8230       break;
8231     case 3:
8232       for (c = cStart; c < cEnd; ++c) {
8233         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8234         switch (coneSize) {
8235         case 4:
8236           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8237           break;
8238         case 8:
8239           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8240           break;
8241         default:
8242           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8243         }
8244         if (cell >= 0) break;
8245       }
8246       break;
8247     default:
8248       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8249     }
8250     cells[p] = cell;
8251   }
8252   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8253   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8254   PetscFunctionReturn(0);
8255 }
8256 
8257 /******************************** FEM Support **********************************/
8258 
8259 #undef __FUNCT__
8260 #define __FUNCT__ "DMPlexVecGetClosure"
8261 /*@C
8262   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8263 
8264   Not collective
8265 
8266   Input Parameters:
8267 + dm - The DM
8268 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8269 . v - The local vector
8270 - point - The sieve point in the DM
8271 
8272   Output Parameters:
8273 + csize - The number of values in the closure, or PETSC_NULL
8274 - values - The array of values, which is a borrowed array and should not be freed
8275 
8276   Level: intermediate
8277 
8278 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8279 @*/
8280 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8281 {
8282   PetscScalar    *array, *vArray;
8283   PetscInt       *points = PETSC_NULL;
8284   PetscInt        offsets[32];
8285   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8286   PetscErrorCode  ierr;
8287 
8288   PetscFunctionBegin;
8289   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8290   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8291   if (!section) {
8292     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8293   }
8294   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8295   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8296   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8297   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8298   /* Compress out points not in the section */
8299   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8300   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8301     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8302       points[q*2]   = points[p];
8303       points[q*2+1] = points[p+1];
8304       ++q;
8305     }
8306   }
8307   numPoints = q;
8308   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8309     PetscInt dof, fdof;
8310 
8311     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8312     for (f = 0; f < numFields; ++f) {
8313       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8314       offsets[f+1] += fdof;
8315     }
8316     size += dof;
8317   }
8318   for (f = 1; f < numFields; ++f) {
8319     offsets[f+1] += offsets[f];
8320   }
8321   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8322   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8323   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8324   for (p = 0; p < numPoints*2; p += 2) {
8325     PetscInt     o = points[p+1];
8326     PetscInt     dof, off, d;
8327     PetscScalar *varr;
8328 
8329     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8330     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8331     varr = &vArray[off];
8332     if (numFields) {
8333       PetscInt fdof, foff, fcomp, f, c;
8334 
8335       for (f = 0, foff = 0; f < numFields; ++f) {
8336         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8337         if (o >= 0) {
8338           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8339             array[offsets[f]] = varr[foff+d];
8340           }
8341         } else {
8342           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8343           for (d = fdof/fcomp-1; d >= 0; --d) {
8344             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8345               array[offsets[f]] = varr[foff+d*fcomp+c];
8346             }
8347           }
8348         }
8349         foff += fdof;
8350       }
8351     } else {
8352       if (o >= 0) {
8353         for (d = 0; d < dof; ++d, ++offsets[0]) {
8354           array[offsets[0]] = varr[d];
8355         }
8356       } else {
8357         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8358           array[offsets[0]] = varr[d];
8359         }
8360       }
8361     }
8362   }
8363   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8364   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8365   if (csize) *csize = size;
8366   *values = array;
8367   PetscFunctionReturn(0);
8368 }
8369 
8370 #undef __FUNCT__
8371 #define __FUNCT__ "DMPlexVecRestoreClosure"
8372 /*@C
8373   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8374 
8375   Not collective
8376 
8377   Input Parameters:
8378 + dm - The DM
8379 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8380 . v - The local vector
8381 . point - The sieve point in the DM
8382 . csize - The number of values in the closure, or PETSC_NULL
8383 - values - The array of values, which is a borrowed array and should not be freed
8384 
8385   Level: intermediate
8386 
8387 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8388 @*/
8389 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8390 {
8391   PetscInt        size = 0;
8392   PetscErrorCode  ierr;
8393 
8394   PetscFunctionBegin;
8395   /* Should work without recalculating size */
8396   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8397   PetscFunctionReturn(0);
8398 }
8399 
8400 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8401 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8402 
8403 #undef __FUNCT__
8404 #define __FUNCT__ "updatePoint_private"
8405 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8406 {
8407   PetscInt        cdof;  /* The number of constraints on this point */
8408   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8409   PetscScalar    *a;
8410   PetscInt        off, cind = 0, k;
8411   PetscErrorCode  ierr;
8412 
8413   PetscFunctionBegin;
8414   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8415   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8416   a    = &array[off];
8417   if (!cdof || setBC) {
8418     if (orientation >= 0) {
8419       for (k = 0; k < dof; ++k) {
8420         fuse(&a[k], values[k]);
8421       }
8422     } else {
8423       for (k = 0; k < dof; ++k) {
8424         fuse(&a[k], values[dof-k-1]);
8425       }
8426     }
8427   } else {
8428     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8429     if (orientation >= 0) {
8430       for (k = 0; k < dof; ++k) {
8431         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8432         fuse(&a[k], values[k]);
8433       }
8434     } else {
8435       for (k = 0; k < dof; ++k) {
8436         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8437         fuse(&a[k], values[dof-k-1]);
8438       }
8439     }
8440   }
8441   PetscFunctionReturn(0);
8442 }
8443 
8444 #undef __FUNCT__
8445 #define __FUNCT__ "updatePointFields_private"
8446 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8447 {
8448   PetscScalar   *a;
8449   PetscInt       numFields, off, foff, f;
8450   PetscErrorCode ierr;
8451 
8452   PetscFunctionBegin;
8453   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8454   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8455   a    = &array[off];
8456   for (f = 0, foff = 0; f < numFields; ++f) {
8457     PetscInt        fdof, fcomp, fcdof;
8458     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8459     PetscInt        cind = 0, k, c;
8460 
8461     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8462     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8463     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8464     if (!fcdof || setBC) {
8465       if (orientation >= 0) {
8466         for (k = 0; k < fdof; ++k) {
8467           fuse(&a[foff+k], values[foffs[f]+k]);
8468         }
8469       } else {
8470         for (k = fdof/fcomp-1; k >= 0; --k) {
8471           for (c = 0; c < fcomp; ++c) {
8472             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8473           }
8474         }
8475       }
8476     } else {
8477       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8478       if (orientation >= 0) {
8479         for (k = 0; k < fdof; ++k) {
8480           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8481           fuse(&a[foff+k], values[foffs[f]+k]);
8482         }
8483       } else {
8484         for (k = fdof/fcomp-1; k >= 0; --k) {
8485           for (c = 0; c < fcomp; ++c) {
8486             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8487             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8488           }
8489         }
8490       }
8491     }
8492     foff     += fdof;
8493     foffs[f] += fdof;
8494   }
8495   PetscFunctionReturn(0);
8496 }
8497 
8498 #undef __FUNCT__
8499 #define __FUNCT__ "DMPlexVecSetClosure"
8500 /*@C
8501   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8502 
8503   Not collective
8504 
8505   Input Parameters:
8506 + dm - The DM
8507 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8508 . v - The local vector
8509 . point - The sieve point in the DM
8510 . values - The array of values, which is a borrowed array and should not be freed
8511 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8512 
8513   Level: intermediate
8514 
8515 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8516 @*/
8517 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8518 {
8519   PetscScalar    *array;
8520   PetscInt       *points = PETSC_NULL;
8521   PetscInt        offsets[32];
8522   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8523   PetscErrorCode  ierr;
8524 
8525   PetscFunctionBegin;
8526   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8527   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8528   if (!section) {
8529     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8530   }
8531   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8532   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8533   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8534   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8535   /* Compress out points not in the section */
8536   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8537   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8538     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8539       points[q*2]   = points[p];
8540       points[q*2+1] = points[p+1];
8541       ++q;
8542     }
8543   }
8544   numPoints = q;
8545   for (p = 0; p < numPoints*2; p += 2) {
8546     PetscInt fdof;
8547 
8548     for (f = 0; f < numFields; ++f) {
8549       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8550       offsets[f+1] += fdof;
8551     }
8552   }
8553   for (f = 1; f < numFields; ++f) {
8554     offsets[f+1] += offsets[f];
8555   }
8556   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8557   if (numFields) {
8558     switch (mode) {
8559     case INSERT_VALUES:
8560       for (p = 0; p < numPoints*2; p += 2) {
8561         PetscInt o = points[p+1];
8562         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8563       } break;
8564     case INSERT_ALL_VALUES:
8565       for (p = 0; p < numPoints*2; p += 2) {
8566         PetscInt o = points[p+1];
8567         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8568       } break;
8569     case ADD_VALUES:
8570       for (p = 0; p < numPoints*2; p += 2) {
8571         PetscInt o = points[p+1];
8572         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8573       } break;
8574     case ADD_ALL_VALUES:
8575       for (p = 0; p < numPoints*2; p += 2) {
8576         PetscInt o = points[p+1];
8577         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8578       } break;
8579     default:
8580       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8581     }
8582   } else {
8583     switch (mode) {
8584     case INSERT_VALUES:
8585       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8586         PetscInt o = points[p+1];
8587         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8588         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8589       } break;
8590     case INSERT_ALL_VALUES:
8591       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8592         PetscInt o = points[p+1];
8593         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8594         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8595       } break;
8596     case ADD_VALUES:
8597       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8598         PetscInt o = points[p+1];
8599         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8600         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8601       } break;
8602     case ADD_ALL_VALUES:
8603       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8604         PetscInt o = points[p+1];
8605         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8606         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8607       } break;
8608     default:
8609       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8610     }
8611   }
8612   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8613   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8614   PetscFunctionReturn(0);
8615 }
8616 
8617 #undef __FUNCT__
8618 #define __FUNCT__ "DMPlexPrintMatSetValues"
8619 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8620 {
8621   PetscMPIInt    rank;
8622   PetscInt       i, j;
8623   PetscErrorCode ierr;
8624 
8625   PetscFunctionBegin;
8626   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8627   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8628   for (i = 0; i < numIndices; i++) {
8629     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8630   }
8631   for (i = 0; i < numIndices; i++) {
8632     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8633     for (j = 0; j < numIndices; j++) {
8634 #if defined(PETSC_USE_COMPLEX)
8635       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8636 #else
8637       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8638 #endif
8639     }
8640     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8641   }
8642   PetscFunctionReturn(0);
8643 }
8644 
8645 #undef __FUNCT__
8646 #define __FUNCT__ "indicesPoint_private"
8647 /* . off - The global offset of this point */
8648 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8649 {
8650   PetscInt        cdof;  /* The number of constraints on this point */
8651   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8652   PetscInt        cind = 0, k;
8653   PetscErrorCode  ierr;
8654 
8655   PetscFunctionBegin;
8656   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8657   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8658   if (!cdof || setBC) {
8659     if (orientation >= 0) {
8660       for (k = 0; k < dof; ++k) {
8661         indices[k] = off+k;
8662       }
8663     } else {
8664       for (k = 0; k < dof; ++k) {
8665         indices[dof-k-1] = off+k;
8666       }
8667     }
8668   } else {
8669     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8670     if (orientation >= 0) {
8671       for (k = 0; k < dof; ++k) {
8672         if ((cind < cdof) && (k == cdofs[cind])) {
8673           /* Insert check for returning constrained indices */
8674           indices[k] = -(off+k+1);
8675           ++cind;
8676         } else {
8677           indices[k] = off+k-cind;
8678         }
8679       }
8680     } else {
8681       for (k = 0; k < dof; ++k) {
8682         if ((cind < cdof) && (k == cdofs[cind])) {
8683           /* Insert check for returning constrained indices */
8684           indices[dof-k-1] = -(off+k+1);
8685           ++cind;
8686         } else {
8687           indices[dof-k-1] = off+k-cind;
8688         }
8689       }
8690     }
8691   }
8692   PetscFunctionReturn(0);
8693 }
8694 
8695 #undef __FUNCT__
8696 #define __FUNCT__ "indicesPointFields_private"
8697 /* . off - The global offset of this point */
8698 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8699 {
8700   PetscInt       numFields, foff, f;
8701   PetscErrorCode ierr;
8702 
8703   PetscFunctionBegin;
8704   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8705   for (f = 0, foff = 0; f < numFields; ++f) {
8706     PetscInt        fdof, fcomp, cfdof;
8707     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8708     PetscInt        cind = 0, k, c;
8709 
8710     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8711     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8712     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8713     if (!cfdof || setBC) {
8714       if (orientation >= 0) {
8715         for (k = 0; k < fdof; ++k) {
8716           indices[foffs[f]+k] = off+foff+k;
8717         }
8718       } else {
8719         for (k = fdof/fcomp-1; k >= 0; --k) {
8720           for (c = 0; c < fcomp; ++c) {
8721             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8722           }
8723         }
8724       }
8725     } else {
8726       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8727       if (orientation >= 0) {
8728         for (k = 0; k < fdof; ++k) {
8729           if ((cind < cfdof) && (k == fcdofs[cind])) {
8730             indices[foffs[f]+k] = -(off+foff+k+1);
8731             ++cind;
8732           } else {
8733             indices[foffs[f]+k] = off+foff+k-cind;
8734           }
8735         }
8736       } else {
8737         for (k = fdof/fcomp-1; k >= 0; --k) {
8738           for (c = 0; c < fcomp; ++c) {
8739             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8740               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8741               ++cind;
8742             } else {
8743               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8744             }
8745           }
8746         }
8747       }
8748     }
8749     foff     += fdof - cfdof;
8750     foffs[f] += fdof;
8751   }
8752   PetscFunctionReturn(0);
8753 }
8754 
8755 #undef __FUNCT__
8756 #define __FUNCT__ "DMPlexMatSetClosure"
8757 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8758 {
8759   DM_Plex     *mesh   = (DM_Plex *) dm->data;
8760   PetscInt       *points = PETSC_NULL;
8761   PetscInt       *indices;
8762   PetscInt        offsets[32];
8763   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8764   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8765   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8766   PetscErrorCode  ierr;
8767 
8768   PetscFunctionBegin;
8769   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8770   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8771   if (useDefault) {
8772     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8773   }
8774   if (useGlobalDefault) {
8775     if (useDefault) {
8776       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8777     } else {
8778       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8779     }
8780   }
8781   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8782   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8783   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8784   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8785   /* Compress out points not in the section */
8786   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8787   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8788     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8789       points[q*2]   = points[p];
8790       points[q*2+1] = points[p+1];
8791       ++q;
8792     }
8793   }
8794   numPoints = q;
8795   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8796     PetscInt fdof;
8797 
8798     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8799     for (f = 0; f < numFields; ++f) {
8800       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8801       offsets[f+1] += fdof;
8802     }
8803     numIndices += dof;
8804   }
8805   for (f = 1; f < numFields; ++f) {
8806     offsets[f+1] += offsets[f];
8807   }
8808   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8809   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8810   if (numFields) {
8811     for (p = 0; p < numPoints*2; p += 2) {
8812       PetscInt o = points[p+1];
8813       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8814       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8815     }
8816   } else {
8817     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8818       PetscInt o = points[p+1];
8819       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8820       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8821     }
8822   }
8823   if (useGlobalDefault && !useDefault) {
8824     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8825   }
8826   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8827   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8828   if (ierr) {
8829     PetscMPIInt    rank;
8830     PetscErrorCode ierr2;
8831 
8832     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8833     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8834     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8835     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8836     CHKERRQ(ierr);
8837   }
8838   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8839   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8840   PetscFunctionReturn(0);
8841 }
8842 
8843 #undef __FUNCT__
8844 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8845 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8846 {
8847   PetscSection       coordSection;
8848   Vec                coordinates;
8849   const PetscScalar *coords;
8850   const PetscInt     dim = 2;
8851   PetscInt           d, f;
8852   PetscErrorCode     ierr;
8853 
8854   PetscFunctionBegin;
8855   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8856   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8857   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8858   if (v0) {
8859     for (d = 0; d < dim; d++) {
8860       v0[d] = PetscRealPart(coords[d]);
8861     }
8862   }
8863   if (J) {
8864     for (d = 0; d < dim; d++) {
8865       for (f = 0; f < dim; f++) {
8866         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8867       }
8868     }
8869     *detJ = J[0]*J[3] - J[1]*J[2];
8870 #if 0
8871     if (detJ < 0.0) {
8872       const PetscReal xLength = mesh->periodicity[0];
8873 
8874       if (xLength != 0.0) {
8875         PetscReal v0x = coords[0*dim+0];
8876 
8877         if (v0x == 0.0) {
8878           v0x = v0[0] = xLength;
8879         }
8880         for (f = 0; f < dim; f++) {
8881           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8882 
8883           J[0*dim+f] = 0.5*(px - v0x);
8884         }
8885       }
8886       detJ = J[0]*J[3] - J[1]*J[2];
8887     }
8888 #endif
8889     PetscLogFlops(8.0 + 3.0);
8890   }
8891   if (invJ) {
8892     const PetscReal invDet = 1.0/(*detJ);
8893 
8894     invJ[0] =  invDet*J[3];
8895     invJ[1] = -invDet*J[1];
8896     invJ[2] = -invDet*J[2];
8897     invJ[3] =  invDet*J[0];
8898     PetscLogFlops(5.0);
8899   }
8900   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8901   PetscFunctionReturn(0);
8902 }
8903 
8904 #undef __FUNCT__
8905 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8906 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8907 {
8908   PetscSection       coordSection;
8909   Vec                coordinates;
8910   const PetscScalar *coords;
8911   const PetscInt     dim = 2;
8912   PetscInt           d, f;
8913   PetscErrorCode     ierr;
8914 
8915   PetscFunctionBegin;
8916   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8917   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8918   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8919   if (v0) {
8920     for (d = 0; d < dim; d++) {
8921       v0[d] = PetscRealPart(coords[d]);
8922     }
8923   }
8924   if (J) {
8925     for (d = 0; d < dim; d++) {
8926       for (f = 0; f < dim; f++) {
8927         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8928       }
8929     }
8930     *detJ = J[0]*J[3] - J[1]*J[2];
8931     PetscLogFlops(8.0 + 3.0);
8932   }
8933   if (invJ) {
8934     const PetscReal invDet = 1.0/(*detJ);
8935 
8936     invJ[0] =  invDet*J[3];
8937     invJ[1] = -invDet*J[1];
8938     invJ[2] = -invDet*J[2];
8939     invJ[3] =  invDet*J[0];
8940     PetscLogFlops(5.0);
8941   }
8942   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8943   PetscFunctionReturn(0);
8944 }
8945 
8946 #undef __FUNCT__
8947 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8948 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8949 {
8950   PetscSection       coordSection;
8951   Vec                coordinates;
8952   const PetscScalar *coords;
8953   const PetscInt     dim = 3;
8954   PetscInt           d, f;
8955   PetscErrorCode     ierr;
8956 
8957   PetscFunctionBegin;
8958   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8959   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8960   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8961   if (v0) {
8962     for (d = 0; d < dim; d++) {
8963       v0[d] = PetscRealPart(coords[d]);
8964     }
8965   }
8966   if (J) {
8967     for (d = 0; d < dim; d++) {
8968       for (f = 0; f < dim; f++) {
8969         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8970       }
8971     }
8972     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8973     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8974              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8975              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8976     PetscLogFlops(18.0 + 12.0);
8977   }
8978   if (invJ) {
8979     const PetscReal invDet = 1.0/(*detJ);
8980 
8981     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8982     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8983     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8984     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8985     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8986     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8987     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8988     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8989     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8990     PetscLogFlops(37.0);
8991   }
8992   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8993   PetscFunctionReturn(0);
8994 }
8995 
8996 #undef __FUNCT__
8997 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8998 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8999 {
9000   PetscSection       coordSection;
9001   Vec                coordinates;
9002   const PetscScalar *coords;
9003   const PetscInt     dim = 3;
9004   PetscInt           d;
9005   PetscErrorCode     ierr;
9006 
9007   PetscFunctionBegin;
9008   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9009   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9010   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9011   if (v0) {
9012     for (d = 0; d < dim; d++) {
9013       v0[d] = PetscRealPart(coords[d]);
9014     }
9015   }
9016   if (J) {
9017     for (d = 0; d < dim; d++) {
9018       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9019       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9020       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9021     }
9022     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9023              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9024              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9025     PetscLogFlops(18.0 + 12.0);
9026   }
9027   if (invJ) {
9028     const PetscReal invDet = -1.0/(*detJ);
9029 
9030     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9031     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9032     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9033     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9034     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9035     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9036     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9037     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9038     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9039     PetscLogFlops(37.0);
9040   }
9041   *detJ *= 8.0;
9042   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9043   PetscFunctionReturn(0);
9044 }
9045 
9046 #undef __FUNCT__
9047 #define __FUNCT__ "DMPlexComputeCellGeometry"
9048 /*@C
9049   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9050 
9051   Collective on DM
9052 
9053   Input Arguments:
9054 + dm   - the DM
9055 - cell - the cell
9056 
9057   Output Arguments:
9058 + v0   - the translation part of this affine transform
9059 . J    - the Jacobian of the transform to the reference element
9060 . invJ - the inverse of the Jacobian
9061 - detJ - the Jacobian determinant
9062 
9063   Level: advanced
9064 
9065 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9066 @*/
9067 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9068 {
9069   PetscInt       dim, coneSize;
9070   PetscErrorCode ierr;
9071 
9072   PetscFunctionBegin;
9073   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9074   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9075   switch (dim) {
9076   case 2:
9077     switch (coneSize) {
9078     case 3:
9079       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9080       break;
9081     case 4:
9082       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9083       break;
9084     default:
9085       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9086     }
9087     break;
9088   case 3:
9089     switch (coneSize) {
9090     case 4:
9091       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9092       break;
9093     case 8:
9094       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9095       break;
9096     default:
9097       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9098     }
9099     break;
9100   default:
9101     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9102   }
9103   PetscFunctionReturn(0);
9104 }
9105 
9106 #undef __FUNCT__
9107 #define __FUNCT__ "DMPlexGetFaceOrientation"
9108 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9109 {
9110   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9111   PetscBool      posOrient = PETSC_FALSE;
9112   const PetscInt debug     = 0;
9113   PetscInt       cellDim, faceSize, f;
9114   PetscErrorCode ierr;
9115 
9116   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9117   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9118 
9119   if (cellDim == numCorners-1) {
9120     /* Simplices */
9121     faceSize  = numCorners-1;
9122     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9123   } else if (cellDim == 1 && numCorners == 3) {
9124     /* Quadratic line */
9125     faceSize  = 1;
9126     posOrient = PETSC_TRUE;
9127   } else if (cellDim == 2 && numCorners == 4) {
9128     /* Quads */
9129     faceSize  = 2;
9130     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9131       posOrient = PETSC_TRUE;
9132     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9133       posOrient = PETSC_TRUE;
9134     } else {
9135       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9136         posOrient = PETSC_FALSE;
9137       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9138     }
9139   } else if (cellDim == 2 && numCorners == 6) {
9140     /* Quadratic triangle (I hate this) */
9141     /* Edges are determined by the first 2 vertices (corners of edges) */
9142     const PetscInt faceSizeTri = 3;
9143     PetscInt  sortedIndices[3], i, iFace;
9144     PetscBool found = PETSC_FALSE;
9145     PetscInt  faceVerticesTriSorted[9] = {
9146       0, 3,  4, /* bottom */
9147       1, 4,  5, /* right */
9148       2, 3,  5, /* left */
9149     };
9150     PetscInt  faceVerticesTri[9] = {
9151       0, 3,  4, /* bottom */
9152       1, 4,  5, /* right */
9153       2, 5,  3, /* left */
9154     };
9155 
9156     faceSize = faceSizeTri;
9157     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9158     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9159     for (iFace = 0; iFace < 3; ++iFace) {
9160       const PetscInt ii = iFace*faceSizeTri;
9161       PetscInt       fVertex, cVertex;
9162 
9163       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9164           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9165         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9166           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9167             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9168               faceVertices[fVertex] = origVertices[cVertex];
9169               break;
9170             }
9171           }
9172         }
9173         found = PETSC_TRUE;
9174         break;
9175       }
9176     }
9177     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9178     if (posOriented) {*posOriented = PETSC_TRUE;}
9179     PetscFunctionReturn(0);
9180   } else if (cellDim == 2 && numCorners == 9) {
9181     /* Quadratic quad (I hate this) */
9182     /* Edges are determined by the first 2 vertices (corners of edges) */
9183     const PetscInt faceSizeQuad = 3;
9184     PetscInt  sortedIndices[3], i, iFace;
9185     PetscBool found = PETSC_FALSE;
9186     PetscInt  faceVerticesQuadSorted[12] = {
9187       0, 1,  4, /* bottom */
9188       1, 2,  5, /* right */
9189       2, 3,  6, /* top */
9190       0, 3,  7, /* left */
9191     };
9192     PetscInt  faceVerticesQuad[12] = {
9193       0, 1,  4, /* bottom */
9194       1, 2,  5, /* right */
9195       2, 3,  6, /* top */
9196       3, 0,  7, /* left */
9197     };
9198 
9199     faceSize = faceSizeQuad;
9200     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9201     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9202     for (iFace = 0; iFace < 4; ++iFace) {
9203       const PetscInt ii = iFace*faceSizeQuad;
9204       PetscInt       fVertex, cVertex;
9205 
9206       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9207           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9208         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9209           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9210             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9211               faceVertices[fVertex] = origVertices[cVertex];
9212               break;
9213             }
9214           }
9215         }
9216         found = PETSC_TRUE;
9217         break;
9218       }
9219     }
9220     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9221     if (posOriented) {*posOriented = PETSC_TRUE;}
9222     PetscFunctionReturn(0);
9223   } else if (cellDim == 3 && numCorners == 8) {
9224     /* Hexes
9225        A hex is two oriented quads with the normal of the first
9226        pointing up at the second.
9227 
9228           7---6
9229          /|  /|
9230         4---5 |
9231         | 3-|-2
9232         |/  |/
9233         0---1
9234 
9235         Faces are determined by the first 4 vertices (corners of faces) */
9236     const PetscInt faceSizeHex = 4;
9237     PetscInt  sortedIndices[4], i, iFace;
9238     PetscBool found = PETSC_FALSE;
9239     PetscInt faceVerticesHexSorted[24] = {
9240       0, 1, 2, 3,  /* bottom */
9241       4, 5, 6, 7,  /* top */
9242       0, 1, 4, 5,  /* front */
9243       1, 2, 5, 6,  /* right */
9244       2, 3, 6, 7,  /* back */
9245       0, 3, 4, 7,  /* left */
9246     };
9247     PetscInt faceVerticesHex[24] = {
9248       3, 2, 1, 0,  /* bottom */
9249       4, 5, 6, 7,  /* top */
9250       0, 1, 5, 4,  /* front */
9251       1, 2, 6, 5,  /* right */
9252       2, 3, 7, 6,  /* back */
9253       3, 0, 4, 7,  /* left */
9254     };
9255 
9256     faceSize = faceSizeHex;
9257     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9258     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9259     for (iFace = 0; iFace < 6; ++iFace) {
9260       const PetscInt ii = iFace*faceSizeHex;
9261       PetscInt       fVertex, cVertex;
9262 
9263       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9264           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9265           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9266           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9267         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9268           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9269             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9270               faceVertices[fVertex] = origVertices[cVertex];
9271               break;
9272             }
9273           }
9274         }
9275         found = PETSC_TRUE;
9276         break;
9277       }
9278     }
9279     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9280     if (posOriented) {*posOriented = PETSC_TRUE;}
9281     PetscFunctionReturn(0);
9282   } else if (cellDim == 3 && numCorners == 10) {
9283     /* Quadratic tet */
9284     /* Faces are determined by the first 3 vertices (corners of faces) */
9285     const PetscInt faceSizeTet = 6;
9286     PetscInt  sortedIndices[6], i, iFace;
9287     PetscBool found = PETSC_FALSE;
9288     PetscInt faceVerticesTetSorted[24] = {
9289       0, 1, 2,  6, 7, 8, /* bottom */
9290       0, 3, 4,  6, 7, 9,  /* front */
9291       1, 4, 5,  7, 8, 9,  /* right */
9292       2, 3, 5,  6, 8, 9,  /* left */
9293     };
9294     PetscInt faceVerticesTet[24] = {
9295       0, 1, 2,  6, 7, 8, /* bottom */
9296       0, 4, 3,  6, 7, 9,  /* front */
9297       1, 5, 4,  7, 8, 9,  /* right */
9298       2, 3, 5,  8, 6, 9,  /* left */
9299     };
9300 
9301     faceSize = faceSizeTet;
9302     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9303     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9304     for (iFace=0; iFace < 4; ++iFace) {
9305       const PetscInt ii = iFace*faceSizeTet;
9306       PetscInt       fVertex, cVertex;
9307 
9308       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9309           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9310           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9311           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9312         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9313           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9314             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9315               faceVertices[fVertex] = origVertices[cVertex];
9316               break;
9317             }
9318           }
9319         }
9320         found = PETSC_TRUE;
9321         break;
9322       }
9323     }
9324     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9325     if (posOriented) {*posOriented = PETSC_TRUE;}
9326     PetscFunctionReturn(0);
9327   } else if (cellDim == 3 && numCorners == 27) {
9328     /* Quadratic hexes (I hate this)
9329        A hex is two oriented quads with the normal of the first
9330        pointing up at the second.
9331 
9332          7---6
9333         /|  /|
9334        4---5 |
9335        | 3-|-2
9336        |/  |/
9337        0---1
9338 
9339        Faces are determined by the first 4 vertices (corners of faces) */
9340     const PetscInt faceSizeQuadHex = 9;
9341     PetscInt  sortedIndices[9], i, iFace;
9342     PetscBool found = PETSC_FALSE;
9343     PetscInt faceVerticesQuadHexSorted[54] = {
9344       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9345       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9346       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9347       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9348       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9349       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9350     };
9351     PetscInt faceVerticesQuadHex[54] = {
9352       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9353       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9354       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9355       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9356       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9357       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9358     };
9359 
9360     faceSize = faceSizeQuadHex;
9361     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9362     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9363     for (iFace = 0; iFace < 6; ++iFace) {
9364       const PetscInt ii = iFace*faceSizeQuadHex;
9365       PetscInt       fVertex, cVertex;
9366 
9367       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9368           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9369           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9370           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9371         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9372           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9373             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9374               faceVertices[fVertex] = origVertices[cVertex];
9375               break;
9376             }
9377           }
9378         }
9379         found = PETSC_TRUE;
9380         break;
9381       }
9382     }
9383     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9384     if (posOriented) {*posOriented = PETSC_TRUE;}
9385     PetscFunctionReturn(0);
9386   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9387   if (!posOrient) {
9388     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9389     for (f = 0; f < faceSize; ++f) {
9390       faceVertices[f] = origVertices[faceSize-1 - f];
9391     }
9392   } else {
9393     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9394     for (f = 0; f < faceSize; ++f) {
9395       faceVertices[f] = origVertices[f];
9396     }
9397   }
9398   if (posOriented) {*posOriented = posOrient;}
9399   PetscFunctionReturn(0);
9400 }
9401 
9402 #undef __FUNCT__
9403 #define __FUNCT__ "DMPlexGetOrientedFace"
9404 /*
9405     Given a cell and a face, as a set of vertices,
9406       return the oriented face, as a set of vertices, in faceVertices
9407     The orientation is such that the face normal points out of the cell
9408 */
9409 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9410 {
9411   const PetscInt *cone = PETSC_NULL;
9412   PetscInt        coneSize, v, f, v2;
9413   PetscInt        oppositeVertex = -1;
9414   PetscErrorCode  ierr;
9415 
9416   PetscFunctionBegin;
9417   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9418   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9419   for (v = 0, v2 = 0; v < coneSize; ++v) {
9420     PetscBool found  = PETSC_FALSE;
9421 
9422     for (f = 0; f < faceSize; ++f) {
9423       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9424     }
9425     if (found) {
9426       indices[v2]      = v;
9427       origVertices[v2] = cone[v];
9428       ++v2;
9429     } else {
9430       oppositeVertex = v;
9431     }
9432   }
9433   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9434   PetscFunctionReturn(0);
9435 }
9436 
9437 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9438 {
9439   switch (i) {
9440   case 0:
9441     switch (j) {
9442     case 0: return 0;
9443     case 1:
9444       switch (k) {
9445       case 0: return 0;
9446       case 1: return 0;
9447       case 2: return 1;
9448       }
9449     case 2:
9450       switch (k) {
9451       case 0: return 0;
9452       case 1: return -1;
9453       case 2: return 0;
9454       }
9455     }
9456   case 1:
9457     switch (j) {
9458     case 0:
9459       switch (k) {
9460       case 0: return 0;
9461       case 1: return 0;
9462       case 2: return -1;
9463       }
9464     case 1: return 0;
9465     case 2:
9466       switch (k) {
9467       case 0: return 1;
9468       case 1: return 0;
9469       case 2: return 0;
9470       }
9471     }
9472   case 2:
9473     switch (j) {
9474     case 0:
9475       switch (k) {
9476       case 0: return 0;
9477       case 1: return 1;
9478       case 2: return 0;
9479       }
9480     case 1:
9481       switch (k) {
9482       case 0: return -1;
9483       case 1: return 0;
9484       case 2: return 0;
9485       }
9486     case 2: return 0;
9487     }
9488   }
9489   return 0;
9490 }
9491 
9492 #undef __FUNCT__
9493 #define __FUNCT__ "DMPlexCreateRigidBody"
9494 /*@C
9495   DMPlexCreateRigidBody - create rigid body modes from coordinates
9496 
9497   Collective on DM
9498 
9499   Input Arguments:
9500 + dm - the DM
9501 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9502 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9503 
9504   Output Argument:
9505 . sp - the null space
9506 
9507   Note: This is necessary to take account of Dirichlet conditions on the displacements
9508 
9509   Level: advanced
9510 
9511 .seealso: MatNullSpaceCreate()
9512 @*/
9513 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9514 {
9515   MPI_Comm       comm = ((PetscObject) dm)->comm;
9516   Vec            coordinates, localMode, mode[6];
9517   PetscSection   coordSection;
9518   PetscScalar   *coords;
9519   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9520   PetscErrorCode ierr;
9521 
9522   PetscFunctionBegin;
9523   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9524   if (dim == 1) {
9525     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9526     PetscFunctionReturn(0);
9527   }
9528   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9529   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9530   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9531   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9532   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9533   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9534   m    = (dim*(dim+1))/2;
9535   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9536   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9537   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9538   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9539   /* Assume P1 */
9540   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9541   for (d = 0; d < dim; ++d) {
9542     PetscScalar values[3] = {0.0, 0.0, 0.0};
9543 
9544     values[d] = 1.0;
9545     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9546     for (v = vStart; v < vEnd; ++v) {
9547       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9548     }
9549     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9550     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9551   }
9552   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9553   for (d = dim; d < dim*(dim+1)/2; ++d) {
9554     PetscInt i, j, k = dim > 2 ? d - dim : d;
9555 
9556     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9557     for (v = vStart; v < vEnd; ++v) {
9558       PetscScalar values[3] = {0.0, 0.0, 0.0};
9559       PetscInt    off;
9560 
9561       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9562       for (i = 0; i < dim; ++i) {
9563         for (j = 0; j < dim; ++j) {
9564           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9565         }
9566       }
9567       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9568     }
9569     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9570     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9571   }
9572   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9573   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9574   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9575   /* Orthonormalize system */
9576   for (i = dim; i < m; ++i) {
9577     PetscScalar dots[6];
9578 
9579     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9580     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9581     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9582     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9583   }
9584   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9585   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9586   PetscFunctionReturn(0);
9587 }
9588 
9589 #undef __FUNCT__
9590 #define __FUNCT__ "DMPlexGetHybridBounds"
9591 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9592 {
9593   DM_Plex       *mesh = (DM_Plex *) dm->data;
9594   PetscInt       dim;
9595   PetscErrorCode ierr;
9596 
9597   PetscFunctionBegin;
9598   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9599   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9600   if (cMax) *cMax = mesh->hybridPointMax[dim];
9601   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9602   if (eMax) *eMax = mesh->hybridPointMax[1];
9603   if (vMax) *vMax = mesh->hybridPointMax[0];
9604   PetscFunctionReturn(0);
9605 }
9606 
9607 #undef __FUNCT__
9608 #define __FUNCT__ "DMPlexSetHybridBounds"
9609 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9610 {
9611   DM_Plex       *mesh = (DM_Plex *) dm->data;
9612   PetscInt       dim;
9613   PetscErrorCode ierr;
9614 
9615   PetscFunctionBegin;
9616   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9617   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9618   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9619   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9620   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9621   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9622   PetscFunctionReturn(0);
9623 }
9624 
9625 #undef __FUNCT__
9626 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9627 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9628 {
9629   DM_Plex *mesh = (DM_Plex *) dm->data;
9630 
9631   PetscFunctionBegin;
9632   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9633   PetscValidPointer(cellHeight, 2);
9634   *cellHeight = mesh->vtkCellHeight;
9635   PetscFunctionReturn(0);
9636 }
9637 
9638 #undef __FUNCT__
9639 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9640 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9641 {
9642   DM_Plex *mesh = (DM_Plex *) dm->data;
9643 
9644   PetscFunctionBegin;
9645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9646   mesh->vtkCellHeight = cellHeight;
9647   PetscFunctionReturn(0);
9648 }
9649 
9650 #undef __FUNCT__
9651 #define __FUNCT__ "DMPlexInsertFace_Private"
9652 /*
9653   DMPlexInsertFace_Private - Puts a face into the mesh
9654 
9655   Not collective
9656 
9657   Input Parameters:
9658   + dm              - The DMPlex
9659   . numFaceVertex   - The number of vertices in the face
9660   . faceVertices    - The vertices in the face for dm
9661   . subfaceVertices - The vertices in the face for subdm
9662   . numCorners      - The number of vertices in the cell
9663   . cell            - A cell in dm containing the face
9664   . subcell         - A cell in subdm containing the face
9665   . firstFace       - First face in the mesh
9666   - newFacePoint    - Next face in the mesh
9667 
9668   Output Parameters:
9669   . newFacePoint - Contains next face point number on input, updated on output
9670 
9671   Level: developer
9672 */
9673 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)
9674 {
9675   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9676   DM_Plex     *submesh = (DM_Plex *) subdm->data;
9677   const PetscInt *faces;
9678   PetscInt        numFaces, coneSize;
9679   PetscErrorCode  ierr;
9680 
9681   PetscFunctionBegin;
9682   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9683   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9684 #if 0
9685   /* Cannot use this because support() has not been constructed yet */
9686   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9687 #else
9688   {
9689     PetscInt f;
9690 
9691     numFaces = 0;
9692     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
9693     for (f = firstFace; f < *newFacePoint; ++f) {
9694       PetscInt dof, off, d;
9695 
9696       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9697       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9698       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9699       for (d = 0; d < dof; ++d) {
9700         const PetscInt p = submesh->cones[off+d];
9701         PetscInt       v;
9702 
9703         for (v = 0; v < numFaceVertices; ++v) {
9704           if (subfaceVertices[v] == p) break;
9705         }
9706         if (v == numFaceVertices) break;
9707       }
9708       if (d == dof) {
9709         numFaces = 1;
9710         ((PetscInt *) faces)[0] = f;
9711       }
9712     }
9713   }
9714 #endif
9715   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
9716   else if (numFaces == 1) {
9717     /* Add the other cell neighbor for this face */
9718     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
9719   } else {
9720     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
9721     PetscBool posOriented;
9722 
9723     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9724     origVertices = &orientedVertices[numFaceVertices];
9725     indices      = &orientedVertices[numFaceVertices*2];
9726     orientedSubVertices = &orientedVertices[numFaceVertices*3];
9727     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
9728     /* TODO: I know that routine should return a permutation, not the indices */
9729     for (v = 0; v < numFaceVertices; ++v) {
9730       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
9731       for (ov = 0; ov < numFaceVertices; ++ov) {
9732         if (orientedVertices[ov] == vertex) {
9733           orientedSubVertices[ov] = subvertex;
9734           break;
9735         }
9736       }
9737       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
9738     }
9739     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
9740     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
9741     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9742     ++(*newFacePoint);
9743   }
9744   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9745   PetscFunctionReturn(0);
9746 }
9747 
9748 #undef __FUNCT__
9749 #define __FUNCT__ "DMPlexCreateSubmesh"
9750 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
9751 {
9752   MPI_Comm        comm = ((PetscObject) dm)->comm;
9753   DM_Plex     *submesh;
9754   PetscBool       boundaryFaces = PETSC_FALSE;
9755   PetscSection    coordSection, subCoordSection;
9756   Vec             coordinates, subCoordinates;
9757   PetscScalar    *coords, *subCoords;
9758   IS              labelIS;
9759   const PetscInt *subVertices;
9760   PetscInt       *subVerticesActive, *tmpPoints;
9761   PetscInt       *subCells = PETSC_NULL;
9762   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
9763   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
9764   PetscInt        dim; /* Right now, do not specify dimension */
9765   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
9766   PetscErrorCode  ierr;
9767 
9768   PetscFunctionBegin;
9769   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9770   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9771   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9772   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
9773   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9774   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9775   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9776   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9777   subface = &face[maxConeSize];
9778   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
9779   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
9780   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
9781   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
9782   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
9783   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
9784   maxSubCells = numSubVertices;
9785   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
9786   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
9787   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
9788   for (v = 0; v < numSubVertices; ++v) {
9789     const PetscInt vertex = subVertices[v];
9790     PetscInt *star = PETSC_NULL;
9791     PetscInt  starSize, numCells = 0;
9792 
9793     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9794     for (p = 0; p < starSize*2; p += 2) {
9795       const PetscInt point = star[p];
9796       if ((point >= cStart) && (point < cEnd)) {
9797         star[numCells++] = point;
9798       }
9799     }
9800     numOldSubCells = numSubCells;
9801     for (c = 0; c < numCells; ++c) {
9802       const PetscInt cell    = star[c];
9803       PetscInt      *closure = PETSC_NULL;
9804       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9805       PetscInt       cellLoc;
9806 
9807       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9808       if (cellLoc >= 0) continue;
9809       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9810       for (p = 0; p < closureSize*2; p += 2) {
9811         const PetscInt point = closure[p];
9812         if ((point >= vStart) && (point < vEnd)) {
9813           closure[numCorners++] = point;
9814         }
9815       }
9816       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9817       for (corner = 0; corner < numCorners; ++corner) {
9818         const PetscInt cellVertex = closure[corner];
9819         PetscInt       subVertex;
9820 
9821         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9822         if (subVertex >= 0) { /* contains submesh vertex */
9823           for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9824           if (i == faceSize) {
9825             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9826             face[faceSize]    = cellVertex;
9827             subface[faceSize] = subVertex;
9828             ++faceSize;
9829           }
9830         }
9831       }
9832       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9833       if (faceSize >= nFV) {
9834         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9835         if (numSubCells >= maxSubCells) {
9836           PetscInt *tmpCells;
9837           maxSubCells *= 2;
9838           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9839           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9840           ierr = PetscFree(subCells);CHKERRQ(ierr);
9841           subCells = tmpCells;
9842         }
9843         /* TOOD: Maybe overestimate then squeeze out empty faces */
9844         if (faceSize > nFV) {
9845           /* TODO: This is tricky. Maybe just add all faces */
9846           numSubFaces++;
9847         } else {
9848           numSubFaces++;
9849         }
9850         for (f = 0; f < faceSize; ++f) {
9851           subVerticesActive[subface[f]] = 1;
9852         }
9853         subCells[numSubCells++] = cell;
9854       }
9855     }
9856     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9857     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9858   }
9859   /* Pick out active subvertices */
9860   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9861     if (subVerticesActive[v]) {
9862       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9863     }
9864   }
9865   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9866   /* Set cone sizes */
9867   firstSubVertex = numSubCells;
9868   firstSubFace   = numSubCells+numSubVerticesActive;
9869   newFacePoint   = firstSubFace;
9870   for (c = 0; c < numSubCells; ++c) {
9871     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
9872   }
9873   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9874     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
9875   }
9876   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
9877   /* Create face cones */
9878   for (c = 0; c < numSubCells; ++c) {
9879     const PetscInt cell    = subCells[c];
9880     PetscInt      *closure = PETSC_NULL;
9881     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9882 
9883     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9884     for (p = 0; p < closureSize*2; p += 2) {
9885       const PetscInt point = closure[p];
9886       if ((point >= vStart) && (point < vEnd)) {
9887         closure[numCorners++] = point;
9888       }
9889     }
9890     for (corner = 0; corner < numCorners; ++corner) {
9891       const PetscInt cellVertex = closure[corner];
9892       PetscInt       subVertex;
9893 
9894       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9895       if (subVertex >= 0) { /* contains submesh vertex */
9896         for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9897         if (i == faceSize) {
9898           face[faceSize]    = cellVertex;
9899           subface[faceSize] = numSubCells+subVertex;
9900           ++faceSize;
9901         }
9902       }
9903     }
9904     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9905     if (faceSize >= nFV) {
9906       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9907       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
9908       /*   We have to take all the faces, and discard those in the interior */
9909       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
9910 #if 0
9911       /* This object just calls insert on each face that comes from subsets() */
9912       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
9913       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9914       PointArray                          faceVec(face->begin(), face->end());
9915 
9916       subsets(faceVec, nFV, inserter);
9917 #endif
9918       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
9919     }
9920   }
9921   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
9922   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
9923   /* Build coordinates */
9924   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9925   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9926   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
9927   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
9928   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
9929     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
9930   }
9931   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
9932   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
9933   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
9934   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
9935   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
9936   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
9937   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9938   for (v = 0; v < numSubVerticesActive; ++v) {
9939     const PetscInt vertex    = subVerticesActive[v];
9940     const PetscInt subVertex = firstSubVertex+v;
9941     PetscInt dof, off, sdof, soff;
9942 
9943     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
9944     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
9945     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
9946     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
9947     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
9948     for (d = 0; d < dof; ++d) {
9949       subCoords[soff+d] = coords[off+d];
9950     }
9951   }
9952   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
9953   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9954   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
9955   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
9956 
9957   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
9958   /* Create map from submesh points to original mesh points */
9959   submesh = (DM_Plex *) (*subdm)->data;
9960   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
9961   for (c = 0; c < numSubCells; ++c) {
9962     tmpPoints[c] = subCells[c];
9963   }
9964   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
9965     tmpPoints[v] = subVerticesActive[v-numSubCells];
9966   }
9967   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
9968 
9969   ierr = PetscFree(subCells);CHKERRQ(ierr);
9970   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
9971   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
9972   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
9973   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9974   PetscFunctionReturn(0);
9975 }
9976 
9977 #undef __FUNCT__
9978 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9979 /* We can easily have a form that takes an IS instead */
9980 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9981 {
9982   PetscSection   section, globalSection;
9983   PetscInt      *numbers, p;
9984   PetscErrorCode ierr;
9985 
9986   PetscFunctionBegin;
9987   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
9988   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9989   for (p = pStart; p < pEnd; ++p) {
9990     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9991   }
9992   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9993   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9994   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9995   for (p = pStart; p < pEnd; ++p) {
9996     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9997   }
9998   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9999   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10000   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10001   PetscFunctionReturn(0);
10002 }
10003 
10004 #undef __FUNCT__
10005 #define __FUNCT__ "DMPlexGetCellNumbering"
10006 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10007 {
10008   DM_Plex    *mesh = (DM_Plex *) dm->data;
10009   PetscInt       cellHeight, cStart, cEnd, cMax;
10010   PetscErrorCode ierr;
10011 
10012   PetscFunctionBegin;
10013   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10014   if (!mesh->globalCellNumbers) {
10015     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10016     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10017     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10018     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10019     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10020   }
10021   *globalCellNumbers = mesh->globalCellNumbers;
10022   PetscFunctionReturn(0);
10023 }
10024 
10025 #undef __FUNCT__
10026 #define __FUNCT__ "DMPlexGetVertexNumbering"
10027 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10028 {
10029   DM_Plex    *mesh = (DM_Plex *) dm->data;
10030   PetscInt       vStart, vEnd, vMax;
10031   PetscErrorCode ierr;
10032 
10033   PetscFunctionBegin;
10034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10035   if (!mesh->globalVertexNumbers) {
10036     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10037     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10038     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10039     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10040   }
10041   *globalVertexNumbers = mesh->globalVertexNumbers;
10042   PetscFunctionReturn(0);
10043 }
10044 
10045 #undef __FUNCT__
10046 #define __FUNCT__ "DMPlexGetSubpointMap"
10047 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10048 {
10049   DM_Plex *mesh = (DM_Plex *) dm->data;
10050 
10051   PetscFunctionBegin;
10052   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10053   PetscValidPointer(subpointMap, 2);
10054   *subpointMap = mesh->subpointMap;
10055   PetscFunctionReturn(0);
10056 }
10057 
10058 #undef __FUNCT__
10059 #define __FUNCT__ "DMPlexSetSubpointMap"
10060 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10061 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10062 {
10063   DM_Plex *mesh = (DM_Plex *) dm->data;
10064 
10065   PetscFunctionBegin;
10066   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10067   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10068   mesh->subpointMap = subpointMap;
10069   PetscFunctionReturn(0);
10070 }
10071 
10072 #undef __FUNCT__
10073 #define __FUNCT__ "DMPlexGetScale"
10074 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10075 {
10076   DM_Plex *mesh = (DM_Plex *) dm->data;
10077 
10078   PetscFunctionBegin;
10079   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10080   PetscValidPointer(scale, 3);
10081   *scale = mesh->scale[unit];
10082   PetscFunctionReturn(0);
10083 }
10084 
10085 #undef __FUNCT__
10086 #define __FUNCT__ "DMPlexSetScale"
10087 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10088 {
10089   DM_Plex *mesh = (DM_Plex *) dm->data;
10090 
10091   PetscFunctionBegin;
10092   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10093   mesh->scale[unit] = scale;
10094   PetscFunctionReturn(0);
10095 }
10096 
10097 
10098 /*******************************************************************************
10099 This should be in a separate Discretization object, but I am not sure how to lay
10100 it out yet, so I am stuffing things here while I experiment.
10101 *******************************************************************************/
10102 #undef __FUNCT__
10103 #define __FUNCT__ "DMPlexSetFEMIntegration"
10104 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10105                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10106                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10107                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10108                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10109                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10110                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10111                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10112                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10113                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10114                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10115                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10116                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10117                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10118                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10119                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10120                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10121 {
10122   DM_Plex *mesh = (DM_Plex *) dm->data;
10123 
10124   PetscFunctionBegin;
10125   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10126   mesh->integrateResidualFEM       = integrateResidualFEM;
10127   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10128   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10129   PetscFunctionReturn(0);
10130 }
10131 
10132 #undef __FUNCT__
10133 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10134 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10135 {
10136   Vec            coordinates;
10137   PetscSection   section, cSection;
10138   PetscInt       dim, vStart, vEnd, v, c, d;
10139   PetscScalar   *values, *cArray;
10140   PetscReal     *coords;
10141   PetscErrorCode ierr;
10142 
10143   PetscFunctionBegin;
10144   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10145   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10146   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10147   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10148   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10149   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10150   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10151   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10152   for (v = vStart; v < vEnd; ++v) {
10153     PetscInt dof, off;
10154 
10155     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10156     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10157     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10158     for (d = 0; d < dof; ++d) {
10159       coords[d] = PetscRealPart(cArray[off+d]);
10160     }
10161     for (c = 0; c < numComp; ++c) {
10162       values[c] = (*funcs[c])(coords);
10163     }
10164     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10165   }
10166   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10167   /* Temporary, must be replaced by a projection on the finite element basis */
10168   {
10169     PetscInt eStart = 0, eEnd = 0, e, depth;
10170 
10171     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10172     --depth;
10173     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10174     for (e = eStart; e < eEnd; ++e) {
10175       const PetscInt *cone = PETSC_NULL;
10176       PetscInt        coneSize, d;
10177       PetscScalar    *coordsA, *coordsB;
10178 
10179       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10180       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10181       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10182       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10183       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10184       for (d = 0; d < dim; ++d) {
10185         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10186       }
10187       for (c = 0; c < numComp; ++c) {
10188         values[c] = (*funcs[c])(coords);
10189       }
10190       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10191     }
10192   }
10193 
10194   ierr = PetscFree(coords);CHKERRQ(ierr);
10195   ierr = PetscFree(values);CHKERRQ(ierr);
10196 #if 0
10197   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10198   PetscReal      detJ;
10199 
10200   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10201   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10202   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10203 
10204   for (PetscInt c = cStart; c < cEnd; ++c) {
10205     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10206     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10207     const int                          oSize   = pV.getSize();
10208     int                                v       = 0;
10209 
10210     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10211     for (PetscInt cl = 0; cl < oSize; ++cl) {
10212       const PetscInt fDim;
10213 
10214       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10215       if (pointDim) {
10216         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10217           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10218         }
10219       }
10220     }
10221     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10222     pV.clear();
10223   }
10224   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10225   ierr = PetscFree(values);CHKERRQ(ierr);
10226 #endif
10227   PetscFunctionReturn(0);
10228 }
10229 
10230 #undef __FUNCT__
10231 #define __FUNCT__ "DMPlexProjectFunction"
10232 /*@C
10233   DMPlexProjectFunction - This projects the given function into the function space provided.
10234 
10235   Input Parameters:
10236 + dm      - The DM
10237 . numComp - The number of components (functions)
10238 . funcs   - The coordinate functions to evaluate
10239 - mode    - The insertion mode for values
10240 
10241   Output Parameter:
10242 . X - vector
10243 
10244   Level: developer
10245 
10246   Note:
10247   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10248   We will eventually fix it.
10249 
10250 ,seealso: DMPlexComputeL2Diff()
10251 */
10252 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10253 {
10254   Vec            localX;
10255   PetscErrorCode ierr;
10256 
10257   PetscFunctionBegin;
10258   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10259   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10260   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10261   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10262   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10263   PetscFunctionReturn(0);
10264 }
10265 
10266 #undef __FUNCT__
10267 #define __FUNCT__ "DMPlexComputeL2Diff"
10268 /*@C
10269   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10270 
10271   Input Parameters:
10272 + dm    - The DM
10273 . quad  - The PetscQuadrature object for each field
10274 . funcs - The functions to evaluate for each field component
10275 - X     - The coefficient vector u_h
10276 
10277   Output Parameter:
10278 . diff - The diff ||u - u_h||_2
10279 
10280   Level: developer
10281 
10282 .seealso: DMPlexProjectFunction()
10283 */
10284 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10285 {
10286   const PetscInt   debug = 0;
10287   PetscSection     section;
10288   Vec              localX;
10289   PetscReal       *coords, *v0, *J, *invJ, detJ;
10290   PetscReal        localDiff = 0.0;
10291   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10292   PetscErrorCode   ierr;
10293 
10294   PetscFunctionBegin;
10295   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10296   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10297   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10298   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10299   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10300   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10301   for (field = 0; field < numFields; ++field) {
10302     numComponents += quad[field].numComponents;
10303   }
10304   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10305   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10306   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10307   for (c = cStart; c < cEnd; ++c) {
10308     const PetscScalar *x;
10309     PetscReal          elemDiff = 0.0;
10310 
10311     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10312     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10313     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10314 
10315     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10316       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10317       const PetscReal *quadPoints    = quad[field].quadPoints;
10318       const PetscReal *quadWeights   = quad[field].quadWeights;
10319       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10320       const PetscInt   numBasisComps = quad[field].numComponents;
10321       const PetscReal *basis         = quad[field].basis;
10322       PetscInt         q, d, e, fc, f;
10323 
10324       if (debug) {
10325         char title[1024];
10326         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10327         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10328       }
10329       for (q = 0; q < numQuadPoints; ++q) {
10330         for (d = 0; d < dim; d++) {
10331           coords[d] = v0[d];
10332           for (e = 0; e < dim; e++) {
10333             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10334           }
10335         }
10336         for (fc = 0; fc < numBasisComps; ++fc) {
10337           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10338           PetscReal       interpolant = 0.0;
10339           for (f = 0; f < numBasisFuncs; ++f) {
10340             const PetscInt fidx = f*numBasisComps+fc;
10341             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10342           }
10343           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10344           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10345         }
10346       }
10347       comp        += numBasisComps;
10348       fieldOffset += numBasisFuncs*numBasisComps;
10349     }
10350     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10351     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10352     localDiff += elemDiff;
10353   }
10354   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10355   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10356   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10357   *diff = PetscSqrtReal(*diff);
10358   PetscFunctionReturn(0);
10359 }
10360 
10361 #undef __FUNCT__
10362 #define __FUNCT__ "DMPlexComputeResidualFEM"
10363 /*@
10364   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10365 
10366   Input Parameters:
10367 + dm - The mesh
10368 . X  - Local input vector
10369 - user - The user context
10370 
10371   Output Parameter:
10372 . F  - Local output vector
10373 
10374   Note:
10375   The second member of the user context must be an FEMContext.
10376 
10377   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10378   like a GPU, or vectorize on a multicore machine.
10379 
10380 .seealso: DMPlexComputeJacobianActionFEM()
10381 */
10382 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10383 {
10384   DM_Plex      *mesh = (DM_Plex *) dm->data;
10385   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10386   PetscQuadrature *quad = fem->quad;
10387   PetscSection     section;
10388   PetscReal       *v0, *J, *invJ, *detJ;
10389   PetscScalar     *elemVec, *u;
10390   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10391   PetscInt         cellDof = 0, numComponents = 0;
10392   PetscErrorCode   ierr;
10393 
10394   PetscFunctionBegin;
10395   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10396   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10397   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10398   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10399   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10400   numCells = cEnd - cStart;
10401   for (field = 0; field < numFields; ++field) {
10402     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10403     numComponents += quad[field].numComponents;
10404   }
10405   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10406   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10407   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);
10408   for (c = cStart; c < cEnd; ++c) {
10409     const PetscScalar *x;
10410     PetscInt           i;
10411 
10412     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10413     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10414     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10415 
10416     for (i = 0; i < cellDof; ++i) {
10417       u[c*cellDof+i] = x[i];
10418     }
10419     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10420   }
10421   for (field = 0; field < numFields; ++field) {
10422     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10423     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10424     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10425     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10426     /* Conforming batches */
10427     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10428     PetscInt numBlocks  = 1;
10429     PetscInt batchSize  = numBlocks * blockSize;
10430     PetscInt numBatches = numBatchesTmp;
10431     PetscInt numChunks  = numCells / (numBatches*batchSize);
10432     /* Remainder */
10433     PetscInt numRemainder = numCells % (numBatches * batchSize);
10434     PetscInt offset       = numCells - numRemainder;
10435 
10436     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10437     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10438                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10439   }
10440   for (c = cStart; c < cEnd; ++c) {
10441     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10442     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10443   }
10444   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10445   if (mesh->printFEM) {
10446     PetscMPIInt rank, numProcs;
10447     PetscInt    p;
10448 
10449     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10450     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10451     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10452     for (p = 0; p < numProcs; ++p) {
10453       if (p == rank) {
10454         Vec f;
10455 
10456         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10457         ierr = VecCopy(F, f);CHKERRQ(ierr);
10458         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10459         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10460         ierr = VecDestroy(&f);CHKERRQ(ierr);
10461         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10462       }
10463       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10464     }
10465   }
10466   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10467   PetscFunctionReturn(0);
10468 }
10469 
10470 #undef __FUNCT__
10471 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10472 /*@C
10473   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10474 
10475   Input Parameters:
10476 + dm - The mesh
10477 . J  - The Jacobian shell matrix
10478 . X  - Local input vector
10479 - user - The user context
10480 
10481   Output Parameter:
10482 . F  - Local output vector
10483 
10484   Note:
10485   The second member of the user context must be an FEMContext.
10486 
10487   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10488   like a GPU, or vectorize on a multicore machine.
10489 
10490 .seealso: DMPlexComputeResidualFEM()
10491 */
10492 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10493 {
10494   DM_Plex      *mesh = (DM_Plex *) dm->data;
10495   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10496   PetscQuadrature *quad = fem->quad;
10497   PetscSection     section;
10498   JacActionCtx    *jctx;
10499   PetscReal       *v0, *J, *invJ, *detJ;
10500   PetscScalar     *elemVec, *u, *a;
10501   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10502   PetscInt         cellDof = 0;
10503   PetscErrorCode   ierr;
10504 
10505   PetscFunctionBegin;
10506   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10507   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10508   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10509   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10510   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10511   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10512   numCells = cEnd - cStart;
10513   for (field = 0; field < numFields; ++field) {
10514     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10515   }
10516   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10517   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);
10518   for (c = cStart; c < cEnd; ++c) {
10519     const PetscScalar *x;
10520     PetscInt           i;
10521 
10522     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10523     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10524     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10525     for (i = 0; i < cellDof; ++i) {
10526       u[c*cellDof+i] = x[i];
10527     }
10528     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10529     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10530     for (i = 0; i < cellDof; ++i) {
10531       a[c*cellDof+i] = x[i];
10532     }
10533     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10534   }
10535   for (field = 0; field < numFields; ++field) {
10536     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10537     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10538     /* Conforming batches */
10539     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10540     PetscInt numBlocks  = 1;
10541     PetscInt batchSize  = numBlocks * blockSize;
10542     PetscInt numBatches = numBatchesTmp;
10543     PetscInt numChunks  = numCells / (numBatches*batchSize);
10544     /* Remainder */
10545     PetscInt numRemainder = numCells % (numBatches * batchSize);
10546     PetscInt offset       = numCells - numRemainder;
10547 
10548     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);
10549     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],
10550                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10551   }
10552   for (c = cStart; c < cEnd; ++c) {
10553     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10554     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10555   }
10556   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10557   if (mesh->printFEM) {
10558     PetscMPIInt rank, numProcs;
10559     PetscInt    p;
10560 
10561     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10562     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10563     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10564     for (p = 0; p < numProcs; ++p) {
10565       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10566       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10567     }
10568   }
10569   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10570   PetscFunctionReturn(0);
10571 }
10572 
10573 #undef __FUNCT__
10574 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10575 /*@
10576   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10577 
10578   Input Parameters:
10579 + dm - The mesh
10580 . X  - Local input vector
10581 - user - The user context
10582 
10583   Output Parameter:
10584 . Jac  - Jacobian matrix
10585 
10586   Note:
10587   The second member of the user context must be an FEMContext.
10588 
10589   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10590   like a GPU, or vectorize on a multicore machine.
10591 
10592 .seealso: FormFunctionLocal()
10593 */
10594 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10595 {
10596   DM_Plex      *mesh = (DM_Plex *) dm->data;
10597   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10598   PetscQuadrature *quad = fem->quad;
10599   PetscSection     section;
10600   PetscReal       *v0, *J, *invJ, *detJ;
10601   PetscScalar     *elemMat, *u;
10602   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10603   PetscInt         cellDof = 0, numComponents = 0;
10604   PetscBool        isShell;
10605   PetscErrorCode   ierr;
10606 
10607   PetscFunctionBegin;
10608   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10609   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10610   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10611   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10612   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10613   numCells = cEnd - cStart;
10614   for (field = 0; field < numFields; ++field) {
10615     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10616     numComponents += quad[field].numComponents;
10617   }
10618   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10619   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10620   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);
10621   for (c = cStart; c < cEnd; ++c) {
10622     const PetscScalar *x;
10623     PetscInt           i;
10624 
10625     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10626     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10627     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10628 
10629     for (i = 0; i < cellDof; ++i) {
10630       u[c*cellDof+i] = x[i];
10631     }
10632     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10633   }
10634   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10635   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10636     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10637     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10638     PetscInt       fieldJ;
10639 
10640     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10641       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10642       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10643       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10644       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10645       /* Conforming batches */
10646       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10647       PetscInt numBlocks  = 1;
10648       PetscInt batchSize  = numBlocks * blockSize;
10649       PetscInt numBatches = numBatchesTmp;
10650       PetscInt numChunks  = numCells / (numBatches*batchSize);
10651       /* Remainder */
10652       PetscInt numRemainder = numCells % (numBatches * batchSize);
10653       PetscInt offset       = numCells - numRemainder;
10654 
10655       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10656       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10657                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10658     }
10659   }
10660   for (c = cStart; c < cEnd; ++c) {
10661     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10662     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10663   }
10664   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10665 
10666   /* Assemble matrix, using the 2-step process:
10667        MatAssemblyBegin(), MatAssemblyEnd(). */
10668   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10669   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10670 
10671   if (mesh->printFEM) {
10672     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10673     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10674     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10675   }
10676   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10677   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10678   if (isShell) {
10679     JacActionCtx *jctx;
10680 
10681     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10682     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10683   }
10684   *str = SAME_NONZERO_PATTERN;
10685   PetscFunctionReturn(0);
10686 }
10687 
10688 
10689 #undef __FUNCT__
10690 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10691 /*@C
10692   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10693   the local section and an SF describing the section point overlap.
10694 
10695   Input Parameters:
10696   + s - The PetscSection for the local field layout
10697   . sf - The SF describing parallel layout of the section points
10698   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10699   . label - The label specifying the points
10700   - labelValue - The label stratum specifying the points
10701 
10702   Output Parameter:
10703   . gsection - The PetscSection for the global field layout
10704 
10705   Note: This gives negative sizes and offsets to points not owned by this process
10706 
10707   Level: developer
10708 
10709 .seealso: PetscSectionCreate()
10710 @*/
10711 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10712 {
10713   PetscInt      *neg;
10714   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10715   PetscErrorCode ierr;
10716 
10717   PetscFunctionBegin;
10718   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10719   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10720   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10721   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10722   /* Mark ghost points with negative dof */
10723   for (p = pStart; p < pEnd; ++p) {
10724     PetscInt value;
10725 
10726     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10727     if (value != labelValue) continue;
10728     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10729     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10730     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10731     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10732     neg[p-pStart] = -(dof+1);
10733   }
10734   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10735   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10736   if (nroots >= 0) {
10737     if (nroots > pEnd - pStart) {
10738       PetscInt *tmpDof;
10739       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10740       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10741       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10742       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10743       for (p = pStart; p < pEnd; ++p) {
10744         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
10745       }
10746       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10747     } else {
10748       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10749       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10750     }
10751   }
10752   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10753   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10754     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10755     (*gsection)->atlasOff[p] = off;
10756     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10757   }
10758   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10759   globalOff -= off;
10760   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10761     (*gsection)->atlasOff[p] += globalOff;
10762     neg[p] = -((*gsection)->atlasOff[p]+1);
10763   }
10764   /* Put in negative offsets for ghost points */
10765   if (nroots >= 0) {
10766     if (nroots > pEnd - pStart) {
10767       PetscInt *tmpOff;
10768       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10769       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10770       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10771       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10772       for (p = pStart; p < pEnd; ++p) {
10773         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
10774       }
10775       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10776     } else {
10777       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10778       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10779     }
10780   }
10781   ierr = PetscFree(neg);CHKERRQ(ierr);
10782   PetscFunctionReturn(0);
10783 }
10784