xref: /petsc/src/dm/impls/plex/plex.c (revision 63e7833ae58c359c2a0b3235ce285a042bc82d50)
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, newCoordinates;
3558   PetscScalar   *coords, *newCoords;
3559   PetscInt      *depthEnd, coordSize;
3560   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3561   PetscErrorCode ierr;
3562 
3563   PetscFunctionBegin;
3564   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3565   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3566   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3567   for (d = 0; d <= depth; ++d) {
3568     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3569   }
3570   /* Step 8: Convert coordinates */
3571   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3572   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3573   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3574   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3575   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3576   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3577   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3578   for (v = vStartNew; v < vEndNew; ++v) {
3579     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3580     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3581   }
3582   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3583   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3584   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3585   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3586   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3587   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3588   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3589   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3590   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3591   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3592   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3593   for (v = vStart; v < vEnd; ++v) {
3594     PetscInt dof, off, noff, d;
3595 
3596     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3597     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3598     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3599     for (d = 0; d < dof; ++d) {
3600       newCoords[noff+d] = coords[off+d];
3601     }
3602   }
3603   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3604   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3605   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3606   PetscFunctionReturn(0);
3607 }
3608 
3609 #undef __FUNCT__
3610 #define __FUNCT__ "DMPlexShiftSF_Private"
3611 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3612 {
3613   PetscInt          *depthEnd;
3614   PetscInt           depth = 0, d;
3615   PetscSF            sfPoint, sfPointNew;
3616   const PetscSFNode *remotePoints;
3617   PetscSFNode       *gremotePoints;
3618   const PetscInt    *localPoints;
3619   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3620   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3621   PetscMPIInt        numProcs;
3622   PetscErrorCode     ierr;
3623 
3624   PetscFunctionBegin;
3625   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3626   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3627   for (d = 0; d <= depth; ++d) {
3628     totShift += depthShift[d];
3629     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3630   }
3631   /* Step 9: Convert pointSF */
3632   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3633   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3634   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3635   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3636   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3637   if (numRoots >= 0) {
3638     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3639     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3640     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3641     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3642     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3643     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3644     for (l = 0; l < numLeaves; ++l) {
3645       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3646       gremotePoints[l].rank  = remotePoints[l].rank;
3647       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3648     }
3649     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3650     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3651   }
3652   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3653   PetscFunctionReturn(0);
3654 }
3655 
3656 #undef __FUNCT__
3657 #define __FUNCT__ "DMPlexShiftLabels_Private"
3658 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3659 {
3660   PetscSF        sfPoint;
3661   DMLabel        vtkLabel, ghostLabel;
3662   PetscInt      *depthEnd;
3663   const PetscSFNode *leafRemote;
3664   const PetscInt    *leafLocal;
3665   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3666   PetscMPIInt    rank;
3667   PetscErrorCode ierr;
3668 
3669   PetscFunctionBegin;
3670   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3671   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3672   for (d = 0; d <= depth; ++d) {
3673     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3674   }
3675   /* Step 10: Convert labels */
3676   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3677   for (l = 0; l < numLabels; ++l) {
3678     DMLabel         label, newlabel;
3679     const char     *lname;
3680     PetscBool       isDepth;
3681     IS              valueIS;
3682     const PetscInt *values;
3683     PetscInt        numValues, val;
3684 
3685     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3686     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3687     if (isDepth) continue;
3688     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3689     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3690     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3691     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3692     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3693     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3694     for (val = 0; val < numValues; ++val) {
3695       IS              pointIS;
3696       const PetscInt *points;
3697       PetscInt        numPoints, p;
3698 
3699       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3700       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3701       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3702       for (p = 0; p < numPoints; ++p) {
3703         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3704 
3705         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3706       }
3707       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3708       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3709     }
3710     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3711     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3712   }
3713   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3714   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3715   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3716   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3717   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3718   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3719   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3720   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3721   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3722   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3723   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3724     for (; c < leafLocal[l] && c < cEnd; ++c) {
3725       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3726     }
3727     if (leafLocal[l] >= cEnd) break;
3728     if (leafRemote[l].rank == rank) {
3729       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3730     } else {
3731       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3732     }
3733   }
3734   for (; c < cEnd; ++c) {
3735     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3736   }
3737   if (0) {
3738     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3739     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3740     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3741   }
3742   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3743   for (f = fStart; f < fEnd; ++f) {
3744     PetscInt numCells;
3745 
3746     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3747     if (numCells < 2) {
3748       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3749     } else {
3750       const PetscInt *cells = PETSC_NULL;
3751       PetscInt        vA, vB;
3752 
3753       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3754       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3755       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3756       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3757     }
3758   }
3759   if (0) {
3760     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3761     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3762     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3763   }
3764   PetscFunctionReturn(0);
3765 }
3766 
3767 #undef __FUNCT__
3768 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3769 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3770 {
3771   DMLabel         label;
3772   IS              valueIS;
3773   const PetscInt *values;
3774   PetscInt       *depthShift;
3775   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3776   PetscErrorCode  ierr;
3777 
3778   PetscFunctionBegin;
3779   /* Count ghost cells */
3780   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3781   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3782   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3783   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3784   *numGhostCells = 0;
3785   for (fs = 0; fs < numFS; ++fs) {
3786     PetscInt numBdFaces;
3787 
3788     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3789     *numGhostCells += numBdFaces;
3790   }
3791   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3792   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3793   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3794   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3795   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3796   /* Step 3: Set cone/support sizes for new points */
3797   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3798   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3799     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3800   }
3801   for (fs = 0; fs < numFS; ++fs) {
3802     IS              faceIS;
3803     const PetscInt *faces;
3804     PetscInt        numFaces, f;
3805 
3806     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3807     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3808     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3809     for (f = 0; f < numFaces; ++f) {
3810       PetscInt size;
3811 
3812       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3813       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3814       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3815     }
3816     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3817     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3818   }
3819   /* Step 4: Setup ghosted DM */
3820   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3821   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3822   /* Step 6: Set cones and supports for new points */
3823   ghostCell = cEnd;
3824   for (fs = 0; fs < numFS; ++fs) {
3825     IS              faceIS;
3826     const PetscInt *faces;
3827     PetscInt        numFaces, f;
3828 
3829     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3830     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3831     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3832     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3833       PetscInt newFace = faces[f] + *numGhostCells;
3834 
3835       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3836       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3837     }
3838     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3839     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3840   }
3841   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3842   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3843   /* Step 7: Stratify */
3844   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3845   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3846   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3847   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3848   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3849   PetscFunctionReturn(0);
3850 }
3851 
3852 #undef __FUNCT__
3853 #define __FUNCT__ "DMPlexConstructGhostCells"
3854 /*@C
3855   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3856 
3857   Collective on dm
3858 
3859   Input Parameters:
3860 + dm - The original DM
3861 - labelName - The label specifying the boundary faces (this could be auto-generated)
3862 
3863   Output Parameters:
3864 + numGhostCells - The number of ghost cells added to the DM
3865 - dmGhosted - The new DM
3866 
3867   Level: developer
3868 
3869 .seealso: DMCreate()
3870 */
3871 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3872 {
3873   DM             gdm;
3874   PetscInt       dim;
3875   PetscErrorCode ierr;
3876 
3877   PetscFunctionBegin;
3878   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3879   PetscValidPointer(numGhostCells, 3);
3880   PetscValidPointer(dmGhosted, 4);
3881   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3882   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3883   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3884   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3885   switch (dim) {
3886   case 2:
3887     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3888     break;
3889   default:
3890     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3891   }
3892   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3893   *dmGhosted = gdm;
3894   PetscFunctionReturn(0);
3895 }
3896 
3897 #undef __FUNCT__
3898 #define __FUNCT__ "DMPlexConstructCohesiveCells_2D"
3899 PetscErrorCode DMPlexConstructCohesiveCells_2D(DM dm, const char labelName[], DM sdm)
3900 {
3901   MPI_Comm        comm = ((PetscObject) dm)->comm;
3902   DMLabel         label;
3903   IS              valueIS, svIS = PETSC_NULL, seIS = PETSC_NULL;
3904   const PetscInt *values, *splitVertices = PETSC_NULL, *splitEdges = PETSC_NULL;
3905   PetscSection    coordSection;
3906   Vec             coordinates;
3907   PetscScalar    *coords;
3908   PetscInt       *depthShift, *depthOffset, *pMaxNew, *coneNew, *supportNew;
3909   PetscInt        shift = 100, depth = 0, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numSplitVertices = 0, v, numSplitEdges = 0, numLabels, l;
3910   PetscErrorCode  ierr;
3911 
3912   PetscFunctionBegin;
3913   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3914   /* Count split points and add cohesive cells */
3915   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3916   if (label) {
3917     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3918     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3919     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3920     ierr = DMLabelGetStratumIS(label, 0, &svIS);CHKERRQ(ierr);
3921     if (svIS) {
3922       ierr = ISGetLocalSize(svIS, &numSplitVertices);CHKERRQ(ierr);
3923       ierr = ISGetIndices(svIS, &splitVertices);CHKERRQ(ierr);
3924     }
3925     ierr = DMLabelGetStratumIS(label, 1, &seIS);CHKERRQ(ierr);
3926     if (seIS) {
3927       ierr = ISGetLocalSize(seIS, &numSplitEdges);CHKERRQ(ierr);
3928       ierr = ISGetIndices(seIS, &splitEdges);CHKERRQ(ierr);
3929     }
3930   }
3931   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3932   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3933   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3934   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3935   for(d = 0; d <= depth; ++d) {
3936     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3937   }
3938   for(sp = 0; sp < numSP; ++sp) {
3939     if ((values[sp] < 0) || (values[sp] > depth)) continue;
3940     ierr = DMLabelGetStratumSize(label, values[sp], &depthShift[values[sp]]);CHKERRQ(ierr);
3941   }
3942   if (depth >= 0) {
3943     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3944     depthShift[1]    += depthShift[0];     /* There is a cohesive edge for every split vertex */
3945     pMaxNew[0]       += depthShift[depth];
3946     if (depth > 1) {pMaxNew[1]   += depthShift[depth] + depthShift[0];}
3947     if (depth > 2) {pMaxNew[2]   += depthShift[depth] + depthShift[0] + depthShift[1];}
3948     depthOffset[depth] = 0;
3949     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3950     if (depth > 1) {depthOffset[1]   = depthOffset[0] + depthShift[0];}
3951     if (depth > 2) {depthOffset[2]   = depthOffset[1] + depthShift[1];}
3952   }
3953   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3954   /* Step 3: Set cone/support sizes for new points */
3955   for(sp = 0; sp < numSP; ++sp) {
3956     const PetscInt  dep = values[sp];
3957     const PetscInt *points;
3958     IS              dimIS;
3959     PetscInt        numPoints, p;
3960 
3961     if ((values[sp] < 0) || (values[sp] > depth)) continue;
3962     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
3963     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
3964     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
3965     for(p = 0; p < numPoints; ++p) {
3966       const PetscInt *support;
3967       PetscInt        coneSize, supportSize, q, e;
3968 
3969       ierr = DMPlexGetConeSize(dm, points[p], &coneSize);CHKERRQ(ierr);
3970       ierr = DMPlexSetConeSize(sdm, pMaxNew[dep] + p, coneSize);CHKERRQ(ierr);
3971       ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
3972       ierr = DMPlexSetSupportSize(sdm, pMaxNew[dep] + p, supportSize);CHKERRQ(ierr);
3973       if (dep == depth-1) {
3974         /* Add cohesive cells, they are prisms */
3975         ierr = DMPlexSetConeSize(sdm, pMaxNew[depth] + p, 2 + coneSize);CHKERRQ(ierr);
3976       } else if (dep == 0) {
3977         ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
3978         /* Split old vertex: Edges in old split faces and new cohesive edge */
3979         for(e = 0, q = 0; e < supportSize; ++e) {
3980           PetscInt val;
3981 
3982           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3983           if ((val == 1) || (val == (shift + 1))) ++q;
3984         }
3985         ierr = DMPlexSetSupportSize(sdm, depthShift[depth] + points[p], q+1);CHKERRQ(ierr);
3986         /* Split new vertex: Edges in new split faces and new cohesive edge */
3987         for(e = 0, q = 0; e < supportSize; ++e) {
3988           PetscInt val;
3989 
3990           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3991           if ((val == 1) || (val == -(shift + 1))) ++q;
3992         }
3993         ierr = DMPlexSetSupportSize(sdm, pMaxNew[dep] + p, q+1);CHKERRQ(ierr);
3994         /* Add cohesive edges */
3995         ierr = DMPlexSetConeSize(sdm, pMaxNew[1] + (depthShift[1] - depthShift[0]) + p, 2);CHKERRQ(ierr);
3996         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3997       }
3998     }
3999     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4000     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4001   }
4002   /* Step 4: Setup ghosted DM */
4003   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4004   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4005   /* Step 6: Set cones and supports for new points */
4006   for(sp = 0; sp < numSP; ++sp) {
4007     const PetscInt  dep = values[sp];
4008     const PetscInt *points;
4009     IS              dimIS;
4010     PetscInt        numPoints, p;
4011 
4012     if ((values[sp] < 0) || (values[sp] > depth)) continue;
4013     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
4014     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4015     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4016     for(p = 0; p < numPoints; ++p) {
4017       const PetscInt *cone, *support;
4018       PetscInt        coneSize, supportSize, q, v, e, s;
4019 
4020       ierr = DMPlexGetConeSize(dm, points[p], &coneSize);CHKERRQ(ierr);
4021       ierr = DMPlexGetCone(dm, points[p], &cone);CHKERRQ(ierr);
4022       ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4023       ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4024       if (dep == depth-1) {
4025         const PetscInt  newp   = depthOffset[dep] + points[p];
4026         const PetscInt  splitp = pMaxNew[dep] + p;
4027         const PetscInt  ccell  = pMaxNew[depth] + p;
4028         const PetscInt *supportF;
4029 
4030         /* Split face:       copy in old face to new face to start */
4031         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4032         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4033         /* Split old face:   old vertices in cone so no change */
4034         /* Split new face:   new vertices in cone */
4035         for(q = 0; q < coneSize; ++q) {
4036           ierr = PetscFindInt(cone[q], numSplitVertices, splitVertices, &v);CHKERRQ(ierr);
4037           coneNew[2+q] = pMaxNew[0] + v;
4038         }
4039         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4040         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4041         coneNew[0] = newp;
4042         coneNew[1] = splitp;
4043         for(q = 0; q < coneSize; ++q) {
4044           coneNew[2+q] = (pMaxNew[1] - pMaxNew[0]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4045         }
4046         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4047         for(s = 0; s < supportSize; ++s) {
4048           PetscInt val;
4049 
4050           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4051           if (val < 0) {
4052             const PetscInt *scone;
4053             PetscInt        sconeSize, sc;
4054 
4055             /* Split old face:   Replace negative side cell with cohesive cell */
4056             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4057             /* Negative cell: replace split face */
4058             ierr = DMPlexGetConeSize(sdm, support[s], &sconeSize);CHKERRQ(ierr);
4059             ierr = DMPlexGetCone(sdm, support[s], &scone);CHKERRQ(ierr);
4060             for(sc = 0; sc < sconeSize; ++sc) {
4061               if (scone[sc] == newp) {
4062                 ierr = DMPlexInsertCone(sdm, support[s], sc, splitp);CHKERRQ(ierr);
4063                 break;
4064               }
4065             }
4066           } else {
4067             /* Split new face:   Replace positive side cell with cohesive cell */
4068             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4069           }
4070         }
4071       } else if (dep == 0) {
4072         const PetscInt newp   = depthOffset[dep] + points[p];
4073         const PetscInt splitp = pMaxNew[dep] + p;
4074         const PetscInt cedge  = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4075 
4076         /* Split old vertex: Edges in old split faces and new cohesive edge */
4077         for(e = 0, q = 0; e < supportSize; ++e) {
4078           PetscInt val;
4079 
4080           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4081           if ((val == 1) || (val == (shift + 1))) {
4082             supportNew[q++] = depthOffset[1] + support[e];
4083           }
4084         }
4085         supportNew[q] = cedge;
4086         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4087         /* Split new vertex: Edges in new split faces and new cohesive edge */
4088         for(e = 0, q = 0; e < supportSize; ++e) {
4089           PetscInt val, edge;
4090 
4091           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4092           if (val == 1) {
4093             ierr = PetscFindInt(support[e], numSplitEdges, splitEdges, &edge);CHKERRQ(ierr);
4094             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4095             supportNew[q++] = pMaxNew[1] + edge;
4096           } else if (val == -(shift + 1)) {
4097             const PetscInt *scone;
4098             PetscInt        sconeSize, sc;
4099 
4100             supportNew[q++] = depthOffset[1] + support[e];
4101             /* Negative edge: replace split vertex */
4102             ierr = DMPlexGetConeSize(sdm, depthOffset[1] + support[e], &sconeSize);CHKERRQ(ierr);
4103             ierr = DMPlexGetCone(sdm, depthOffset[1] + support[e], &scone);CHKERRQ(ierr);
4104             for(sc = 0; sc < sconeSize; ++sc) {
4105               if (scone[sc] == newp) {
4106                 ierr = DMPlexInsertCone(sdm, depthOffset[1] + support[e], sc, splitp);CHKERRQ(ierr);
4107                 break;
4108               }
4109             }
4110             if (sc == sconeSize) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Edge %d does not contain split vertex %d", support[e], newp);
4111           }
4112         }
4113         supportNew[q] = cedge;
4114         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4115         /* Cohesive edge:    Old and new split vertex, punting on support */
4116         coneNew[0] = newp;
4117         coneNew[1] = splitp;
4118         ierr = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4119       }
4120     }
4121     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4122     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4123   }
4124   if (label) {
4125     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4126     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4127   }
4128   /* Step 7: Stratify */
4129   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4130   /* Step 8: Coordinates */
4131   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4132   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4133   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4134   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4135   for(v = 0; v < numSplitVertices; ++v) {
4136     const PetscInt newp   = depthOffset[0] + splitVertices[v];
4137     const PetscInt splitp = pMaxNew[0] + v;
4138     PetscInt       dof, off, soff, d;
4139 
4140     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4141     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4142     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4143     for(d = 0; d < dof; ++d) {
4144       coords[soff+d] = coords[off+d];
4145     }
4146   }
4147   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4148   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4149   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4150   /* Step 10: Labels */
4151   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4152   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4153   for(sp = 0; sp < numSP; ++sp) {
4154     const PetscInt  dep = values[sp];
4155     const PetscInt *points;
4156     IS              dimIS;
4157     PetscInt        numPoints, p;
4158 
4159     if ((values[sp] < 0) || (values[sp] > depth)) continue;
4160     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
4161     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4162     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4163     for(p = 0; p < numPoints; ++p) {
4164       const PetscInt newp   = depthOffset[dep] + points[p];
4165       const PetscInt splitp = pMaxNew[dep] + p;
4166 
4167       for (l = 0; l < numLabels; ++l) {
4168         DMLabel     label;
4169         const char *lname;
4170         PetscInt    val;
4171 
4172         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4173         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4174         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4175         if (val >= 0) {
4176           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4177           if (dep == 0) {
4178             const PetscInt cedge  = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4179             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4180           }
4181         }
4182       }
4183     }
4184     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4185     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4186   }
4187   if (svIS) {ierr = ISRestoreIndices(svIS, &splitVertices);CHKERRQ(ierr);}
4188   if (seIS) {ierr = ISRestoreIndices(seIS, &splitEdges);CHKERRQ(ierr);}
4189   ierr = ISDestroy(&svIS);CHKERRQ(ierr);
4190   ierr = ISDestroy(&seIS);CHKERRQ(ierr);
4191   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4192   PetscFunctionReturn(0);
4193 }
4194 
4195 #undef __FUNCT__
4196 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4197 /*@C
4198   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4199 
4200   Collective on dm
4201 
4202   Input Parameters:
4203 + dm - The original DM
4204 - labelName - The label specifying the boundary faces (this could be auto-generated)
4205 
4206   Output Parameters:
4207 - dmSplit - The new DM
4208 
4209   Level: developer
4210 
4211 .seealso: DMCreate()
4212 */
4213 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4214 {
4215   DM             sdm;
4216   PetscInt       dim;
4217   PetscErrorCode ierr;
4218 
4219   PetscFunctionBegin;
4220   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4221   PetscValidPointer(dmSplit, 4);
4222   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4223   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4224   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4225   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4226   switch(dim) {
4227   case 2:
4228     ierr = DMPlexConstructCohesiveCells_2D(dm, labelName, sdm);CHKERRQ(ierr);
4229     break;
4230   default:
4231     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4232   }
4233   *dmSplit = sdm;
4234   PetscFunctionReturn(0);
4235 }
4236 
4237 #undef __FUNCT__
4238 #define __FUNCT__ "DMLabelCohesiveComplete"
4239 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4240 {
4241   IS              dimIS;
4242   const PetscInt *points;
4243   PetscInt        shift = 100, dim, numPoints, p;
4244   PetscErrorCode  ierr;
4245 
4246   PetscFunctionBegin;
4247   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4248   /* Cell orientation for face gives the side of the fault */
4249   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4250   if (!dimIS) PetscFunctionReturn(0);
4251   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4252   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4253   for(p = 0; p < numPoints; ++p) {
4254     const PetscInt *support;
4255     PetscInt        supportSize, s;
4256 
4257     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4258     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4259     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4260     for(s = 0; s < supportSize; ++s) {
4261       const PetscInt *cone, *ornt;
4262       PetscInt        coneSize, c;
4263       PetscBool       pos = PETSC_TRUE;
4264 
4265       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4266       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4267       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4268       for(c = 0; c < coneSize; ++c) {
4269         if (cone[c] == points[p]) {
4270           if (ornt[c] >= 0) {
4271             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4272           } else {
4273             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4274             pos  = PETSC_FALSE;
4275           }
4276           break;
4277         }
4278       }
4279       if (c == coneSize) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4280       for(c = 0; c < coneSize; ++c) {
4281         if (cone[c] != points[p]) {
4282           if (pos) {
4283             ierr = DMLabelSetValue(label, cone[c],   shift+dim-1);CHKERRQ(ierr);
4284           } else {
4285             ierr = DMLabelSetValue(label, cone[c], -(shift+dim-1));CHKERRQ(ierr);
4286             pos  = PETSC_FALSE;
4287           }
4288         }
4289       }
4290     }
4291   }
4292   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4293   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4294   /* Search for other cells/faces/edges connected to the fault */
4295   PetscFunctionReturn(0);
4296 }
4297 
4298 #undef __FUNCT__
4299 #define __FUNCT__ "DMPlexInterpolate_2D"
4300 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4301 {
4302   DM             idm;
4303   DM_Plex       *mesh;
4304   PetscHashIJ    edgeTable;
4305   PetscInt      *off;
4306   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4307   PetscInt       numEdges, firstEdge, edge, e;
4308   PetscErrorCode ierr;
4309 
4310   PetscFunctionBegin;
4311   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4312   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4313   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4314   numCells    = cEnd - cStart;
4315   numVertices = vEnd - vStart;
4316   firstEdge   = numCells + numVertices;
4317   numEdges    = 0 ;
4318   /* Count edges using algorithm from CreateNeighborCSR */
4319   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4320   if (off) {
4321     PetscInt numCorners = 0;
4322 
4323     numEdges = off[numCells]/2;
4324 #if 0
4325     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4326     numEdges += 3*numCells - off[numCells];
4327 #else
4328     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4329     for (c = cStart; c < cEnd; ++c) {
4330       PetscInt coneSize;
4331 
4332       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4333       numCorners += coneSize;
4334     }
4335     numEdges += numCorners - off[numCells];
4336 #endif
4337   }
4338 #if 0
4339   /* Check Euler characteristic V - E + F = 1 */
4340   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4341 #endif
4342   /* Create interpolated mesh */
4343   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4344   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4345   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4346   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4347   for (c = 0; c < numCells; ++c) {
4348     PetscInt numCorners;
4349 
4350     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4351     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4352   }
4353   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4354     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4355   }
4356   ierr = DMSetUp(idm);CHKERRQ(ierr);
4357   /* Get edge cones from subsets of cell vertices */
4358   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4359   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4360 
4361   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4362     const PetscInt *cellFaces;
4363     PetscInt        numCellFaces, faceSize, cf;
4364 
4365     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4366     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4367     for (cf = 0; cf < numCellFaces; ++cf) {
4368 #if 1
4369       PetscHashIJKey key = {PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]),
4370                             PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1])};
4371 
4372       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4373       if (e < 0) {
4374         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4375         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4376         e    = edge++;
4377       }
4378 #else
4379       PetscBool found = PETSC_FALSE;
4380 
4381       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4382       for (e = firstEdge; e < edge; ++e) {
4383         const PetscInt *cone;
4384 
4385         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4386         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4387             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4388           found = PETSC_TRUE;
4389           break;
4390         }
4391       }
4392       if (!found) {
4393         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4394         ++edge;
4395       }
4396 #endif
4397       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4398     }
4399   }
4400   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4401   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4402   ierr = PetscFree(off);CHKERRQ(ierr);
4403   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4404   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4405   mesh = (DM_Plex *) (idm)->data;
4406   /* Orient edges */
4407   for (c = 0; c < numCells; ++c) {
4408     const PetscInt *cone = PETSC_NULL, *cellFaces;
4409     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4410 
4411     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4412     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4413     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4414     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4415     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4416     for (cf = 0; cf < numCellFaces; ++cf) {
4417       const PetscInt *econe = PETSC_NULL;
4418       PetscInt        esize;
4419 
4420       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4421       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4422       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]);
4423       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4424         /* Correctly oriented */
4425         mesh->coneOrientations[coff+cf] = 0;
4426       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4427         /* Start at index 1, and reverse orientation */
4428         mesh->coneOrientations[coff+cf] = -(1+1);
4429       }
4430     }
4431   }
4432   *dmInt  = idm;
4433   PetscFunctionReturn(0);
4434 }
4435 
4436 #undef __FUNCT__
4437 #define __FUNCT__ "DMPlexInterpolate_3D"
4438 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4439 {
4440   DM             idm, fdm;
4441   DM_Plex    *mesh;
4442   PetscInt      *off;
4443   const PetscInt numCorners = 4;
4444   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4445   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4446   PetscErrorCode ierr;
4447 
4448   PetscFunctionBegin;
4449   {
4450     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4451     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4452     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4453   }
4454   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4455   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4456   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4457   numCells    = cEnd - cStart;
4458   numVertices = vEnd - vStart;
4459   firstFace   = numCells + numVertices;
4460   numFaces    = 0 ;
4461   /* Count faces using algorithm from CreateNeighborCSR */
4462   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4463   if (off) {
4464     numFaces = off[numCells]/2;
4465     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4466     numFaces += 4*numCells - off[numCells];
4467   }
4468   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4469   firstEdge = firstFace + numFaces;
4470   numEdges  = numVertices + numFaces - numCells - 1;
4471   /* Create interpolated mesh */
4472   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4473   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4474   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4475   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4476   for (c = 0; c < numCells; ++c) {
4477     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4478   }
4479   for (f = firstFace; f < firstFace+numFaces; ++f) {
4480     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4481   }
4482   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4483     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4484   }
4485   ierr = DMSetUp(idm);CHKERRQ(ierr);
4486   /* Get face cones from subsets of cell vertices */
4487   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4488   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4489   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4490   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4491   for (f = firstFace; f < firstFace+numFaces; ++f) {
4492     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4493   }
4494   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4495   for (c = 0, face = firstFace; c < numCells; ++c) {
4496     const PetscInt *cellFaces;
4497     PetscInt        numCellFaces, faceSize, cf;
4498 
4499     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4500     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4501     for (cf = 0; cf < numCellFaces; ++cf) {
4502       PetscBool found = PETSC_FALSE;
4503 
4504       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4505       for (f = firstFace; f < face; ++f) {
4506         const PetscInt *cone = PETSC_NULL;
4507 
4508         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4509         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4510             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4511             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4512             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4513             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4514             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4515           found = PETSC_TRUE;
4516           break;
4517         }
4518       }
4519       if (!found) {
4520         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4521         /* Save the vertices for orientation calculation */
4522         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4523         ++face;
4524       }
4525       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4526     }
4527   }
4528   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4529   /* Get edge cones from subsets of face vertices */
4530   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4531     const PetscInt *cellFaces;
4532     PetscInt        numCellFaces, faceSize, cf;
4533 
4534     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4535     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4536     for (cf = 0; cf < numCellFaces; ++cf) {
4537       PetscBool found = PETSC_FALSE;
4538 
4539       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4540       for (e = firstEdge; e < edge; ++e) {
4541         const PetscInt *cone = PETSC_NULL;
4542 
4543         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4544         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4545             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4546           found = PETSC_TRUE;
4547           break;
4548         }
4549       }
4550       if (!found) {
4551         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4552         ++edge;
4553       }
4554       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4555     }
4556   }
4557   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4558   ierr = PetscFree(off);CHKERRQ(ierr);
4559   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4560   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4561   mesh = (DM_Plex *) (idm)->data;
4562   /* Orient edges */
4563   for (f = firstFace; f < firstFace+numFaces; ++f) {
4564     const PetscInt *cone, *cellFaces;
4565     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4566 
4567     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4568     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4569     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4570     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4571     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4572     for (cf = 0; cf < numCellFaces; ++cf) {
4573       const PetscInt *econe;
4574       PetscInt        esize;
4575 
4576       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4577       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4578       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]);
4579       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4580         /* Correctly oriented */
4581         mesh->coneOrientations[coff+cf] = 0;
4582       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4583         /* Start at index 1, and reverse orientation */
4584         mesh->coneOrientations[coff+cf] = -(1+1);
4585       }
4586     }
4587   }
4588   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4589   /* Orient faces */
4590   for (c = 0; c < numCells; ++c) {
4591     const PetscInt *cone, *cellFaces;
4592     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4593 
4594     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4595     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4596     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4597     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4598     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4599     for (cf = 0; cf < numCellFaces; ++cf) {
4600       PetscInt *origClosure = PETSC_NULL, *closure;
4601       PetscInt  closureSize, i;
4602 
4603       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4604       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4605       for (i = 4; i < 7; ++i) {
4606         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);
4607       }
4608       closure = &origClosure[4*2];
4609       /* Remember that this is the orientation for edges, not vertices */
4610       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4611         /* Correctly oriented */
4612         mesh->coneOrientations[coff+cf] = 0;
4613       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4614         /* Shifted by 1 */
4615         mesh->coneOrientations[coff+cf] = 1;
4616       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4617         /* Shifted by 2 */
4618         mesh->coneOrientations[coff+cf] = 2;
4619       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4620         /* Start at edge 1, and reverse orientation */
4621         mesh->coneOrientations[coff+cf] = -(1+1);
4622       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4623         /* Start at index 0, and reverse orientation */
4624         mesh->coneOrientations[coff+cf] = -(0+1);
4625       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4626         /* Start at index 2, and reverse orientation */
4627         mesh->coneOrientations[coff+cf] = -(2+1);
4628       } 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);
4629       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4630     }
4631   }
4632   {
4633     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4634     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4635     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4636   }
4637   *dmInt  = idm;
4638   PetscFunctionReturn(0);
4639 }
4640 
4641 #undef __FUNCT__
4642 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4643 /*
4644   This takes as input the common mesh generator output, a list of the vertices for each cell
4645 */
4646 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4647 {
4648   PetscInt      *cone, c, p;
4649   PetscErrorCode ierr;
4650 
4651   PetscFunctionBegin;
4652   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4653   for (c = 0; c < numCells; ++c) {
4654     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4655   }
4656   ierr = DMSetUp(dm);CHKERRQ(ierr);
4657   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4658   for (c = 0; c < numCells; ++c) {
4659     for (p = 0; p < numCorners; ++p) {
4660       cone[p] = cells[c*numCorners+p]+numCells;
4661     }
4662     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4663   }
4664   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4665   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4666   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4667   PetscFunctionReturn(0);
4668 }
4669 
4670 #undef __FUNCT__
4671 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4672 /*
4673   This takes as input the coordinates for each vertex
4674 */
4675 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4676 {
4677   PetscSection   coordSection;
4678   Vec            coordinates;
4679   PetscScalar   *coords;
4680   PetscInt       coordSize, v, d;
4681   PetscErrorCode ierr;
4682 
4683   PetscFunctionBegin;
4684   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4685   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4686   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4687   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4688   for (v = numCells; v < numCells+numVertices; ++v) {
4689     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4690     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4691   }
4692   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4693   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4694   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4695   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4696   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4697   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4698   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4699   for (v = 0; v < numVertices; ++v) {
4700     for (d = 0; d < spaceDim; ++d) {
4701       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4702     }
4703   }
4704   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4705   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4706   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4707   PetscFunctionReturn(0);
4708 }
4709 
4710 #undef __FUNCT__
4711 #define __FUNCT__ "DMPlexCreateFromCellList"
4712 /*
4713   This takes as input the common mesh generator output, a list of the vertices for each cell
4714 */
4715 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4716 {
4717   PetscErrorCode ierr;
4718 
4719   PetscFunctionBegin;
4720   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4721   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4722   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4723   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4724   if (interpolate) {
4725     DM idm;
4726 
4727     switch (dim) {
4728     case 2:
4729       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4730     case 3:
4731       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4732     default:
4733       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4734     }
4735     ierr = DMDestroy(dm);CHKERRQ(ierr);
4736     *dm  = idm;
4737   }
4738   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4739   PetscFunctionReturn(0);
4740 }
4741 
4742 #if defined(PETSC_HAVE_TRIANGLE)
4743 #include <triangle.h>
4744 
4745 #undef __FUNCT__
4746 #define __FUNCT__ "InitInput_Triangle"
4747 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4748 {
4749   PetscFunctionBegin;
4750   inputCtx->numberofpoints = 0;
4751   inputCtx->numberofpointattributes = 0;
4752   inputCtx->pointlist = PETSC_NULL;
4753   inputCtx->pointattributelist = PETSC_NULL;
4754   inputCtx->pointmarkerlist = PETSC_NULL;
4755   inputCtx->numberofsegments = 0;
4756   inputCtx->segmentlist = PETSC_NULL;
4757   inputCtx->segmentmarkerlist = PETSC_NULL;
4758   inputCtx->numberoftriangleattributes = 0;
4759   inputCtx->trianglelist = PETSC_NULL;
4760   inputCtx->numberofholes = 0;
4761   inputCtx->holelist = PETSC_NULL;
4762   inputCtx->numberofregions = 0;
4763   inputCtx->regionlist = PETSC_NULL;
4764   PetscFunctionReturn(0);
4765 }
4766 
4767 #undef __FUNCT__
4768 #define __FUNCT__ "InitOutput_Triangle"
4769 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4770 {
4771   PetscFunctionBegin;
4772   outputCtx->numberofpoints = 0;
4773   outputCtx->pointlist = PETSC_NULL;
4774   outputCtx->pointattributelist = PETSC_NULL;
4775   outputCtx->pointmarkerlist = PETSC_NULL;
4776   outputCtx->numberoftriangles = 0;
4777   outputCtx->trianglelist = PETSC_NULL;
4778   outputCtx->triangleattributelist = PETSC_NULL;
4779   outputCtx->neighborlist = PETSC_NULL;
4780   outputCtx->segmentlist = PETSC_NULL;
4781   outputCtx->segmentmarkerlist = PETSC_NULL;
4782   outputCtx->numberofedges = 0;
4783   outputCtx->edgelist = PETSC_NULL;
4784   outputCtx->edgemarkerlist = PETSC_NULL;
4785   PetscFunctionReturn(0);
4786 }
4787 
4788 #undef __FUNCT__
4789 #define __FUNCT__ "FiniOutput_Triangle"
4790 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4791 {
4792   PetscFunctionBegin;
4793   free(outputCtx->pointmarkerlist);
4794   free(outputCtx->edgelist);
4795   free(outputCtx->edgemarkerlist);
4796   free(outputCtx->trianglelist);
4797   free(outputCtx->neighborlist);
4798   PetscFunctionReturn(0);
4799 }
4800 
4801 #undef __FUNCT__
4802 #define __FUNCT__ "DMPlexGenerate_Triangle"
4803 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4804 {
4805   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4806   PetscInt             dim              = 2;
4807   const PetscBool      createConvexHull = PETSC_FALSE;
4808   const PetscBool      constrained      = PETSC_FALSE;
4809   struct triangulateio in;
4810   struct triangulateio out;
4811   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4812   PetscMPIInt          rank;
4813   PetscErrorCode       ierr;
4814 
4815   PetscFunctionBegin;
4816   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4817   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4818   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4819   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4820   in.numberofpoints = vEnd - vStart;
4821   if (in.numberofpoints > 0) {
4822     PetscSection coordSection;
4823     Vec          coordinates;
4824     PetscScalar *array;
4825 
4826     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4827     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4828     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4829     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4830     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4831     for (v = vStart; v < vEnd; ++v) {
4832       const PetscInt idx = v - vStart;
4833       PetscInt       off, d;
4834 
4835       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4836       for (d = 0; d < dim; ++d) {
4837         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4838       }
4839       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4840     }
4841     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4842   }
4843   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4844   in.numberofsegments = eEnd - eStart;
4845   if (in.numberofsegments > 0) {
4846     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4847     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4848     for (e = eStart; e < eEnd; ++e) {
4849       const PetscInt  idx = e - eStart;
4850       const PetscInt *cone;
4851 
4852       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4853       in.segmentlist[idx*2+0] = cone[0] - vStart;
4854       in.segmentlist[idx*2+1] = cone[1] - vStart;
4855       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4856     }
4857   }
4858 #if 0 /* Do not currently support holes */
4859   PetscReal *holeCoords;
4860   PetscInt   h, d;
4861 
4862   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4863   if (in.numberofholes > 0) {
4864     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4865     for (h = 0; h < in.numberofholes; ++h) {
4866       for (d = 0; d < dim; ++d) {
4867         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4868       }
4869     }
4870   }
4871 #endif
4872   if (!rank) {
4873     char args[32];
4874 
4875     /* Take away 'Q' for verbose output */
4876     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4877     if (createConvexHull) {
4878       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4879     }
4880     if (constrained) {
4881       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4882     }
4883     triangulate(args, &in, &out, PETSC_NULL);
4884   }
4885   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4886   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4887   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4888   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4889   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4890 
4891   {
4892     const PetscInt numCorners  = 3;
4893     const PetscInt numCells    = out.numberoftriangles;
4894     const PetscInt numVertices = out.numberofpoints;
4895     const int     *cells       = out.trianglelist;
4896     const double  *meshCoords  = out.pointlist;
4897 
4898     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4899     /* Set labels */
4900     for (v = 0; v < numVertices; ++v) {
4901       if (out.pointmarkerlist[v]) {
4902         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4903       }
4904     }
4905     if (interpolate) {
4906       for (e = 0; e < out.numberofedges; e++) {
4907         if (out.edgemarkerlist[e]) {
4908           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4909           const PetscInt *edges;
4910           PetscInt        numEdges;
4911 
4912           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4913           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4914           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4915           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4916         }
4917       }
4918     }
4919     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4920   }
4921 #if 0 /* Do not currently support holes */
4922   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4923 #endif
4924   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4925   PetscFunctionReturn(0);
4926 }
4927 
4928 #undef __FUNCT__
4929 #define __FUNCT__ "DMPlexRefine_Triangle"
4930 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4931 {
4932   MPI_Comm             comm = ((PetscObject) dm)->comm;
4933   PetscInt             dim  = 2;
4934   struct triangulateio in;
4935   struct triangulateio out;
4936   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4937   PetscMPIInt          rank;
4938   PetscErrorCode       ierr;
4939 
4940   PetscFunctionBegin;
4941   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4942   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4943   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4944   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4945   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4946   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4947   in.numberofpoints = vEnd - vStart;
4948   if (in.numberofpoints > 0) {
4949     PetscSection coordSection;
4950     Vec          coordinates;
4951     PetscScalar *array;
4952 
4953     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4954     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4955     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4956     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4957     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4958     for (v = vStart; v < vEnd; ++v) {
4959       const PetscInt idx = v - vStart;
4960       PetscInt       off, d;
4961 
4962       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4963       for (d = 0; d < dim; ++d) {
4964         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4965       }
4966       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4967     }
4968     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4969   }
4970   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4971   in.numberofcorners   = 3;
4972   in.numberoftriangles = cEnd - cStart;
4973   in.trianglearealist  = (double *) maxVolumes;
4974   if (in.numberoftriangles > 0) {
4975     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4976     for (c = cStart; c < cEnd; ++c) {
4977       const PetscInt idx     = c - cStart;
4978       PetscInt      *closure = PETSC_NULL;
4979       PetscInt       closureSize;
4980 
4981       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4982       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4983       for (v = 0; v < 3; ++v) {
4984         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4985       }
4986       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4987     }
4988   }
4989   /* TODO: Segment markers are missing on input */
4990 #if 0 /* Do not currently support holes */
4991   PetscReal *holeCoords;
4992   PetscInt   h, d;
4993 
4994   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4995   if (in.numberofholes > 0) {
4996     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4997     for (h = 0; h < in.numberofholes; ++h) {
4998       for (d = 0; d < dim; ++d) {
4999         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5000       }
5001     }
5002   }
5003 #endif
5004   if (!rank) {
5005     char args[32];
5006 
5007     /* Take away 'Q' for verbose output */
5008     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5009     triangulate(args, &in, &out, PETSC_NULL);
5010   }
5011   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5012   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5013   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5014   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5015   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5016 
5017   {
5018     const PetscInt numCorners  = 3;
5019     const PetscInt numCells    = out.numberoftriangles;
5020     const PetscInt numVertices = out.numberofpoints;
5021     const int     *cells       = out.trianglelist;
5022     const double  *meshCoords  = out.pointlist;
5023     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5024 
5025     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5026     /* Set labels */
5027     for (v = 0; v < numVertices; ++v) {
5028       if (out.pointmarkerlist[v]) {
5029         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5030       }
5031     }
5032     if (interpolate) {
5033       PetscInt e;
5034 
5035       for (e = 0; e < out.numberofedges; e++) {
5036         if (out.edgemarkerlist[e]) {
5037           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5038           const PetscInt *edges;
5039           PetscInt        numEdges;
5040 
5041           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5042           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5043           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5044           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5045         }
5046       }
5047     }
5048     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5049   }
5050 #if 0 /* Do not currently support holes */
5051   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5052 #endif
5053   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5054   PetscFunctionReturn(0);
5055 }
5056 #endif
5057 
5058 #if defined(PETSC_HAVE_TETGEN)
5059 #include <tetgen.h>
5060 #undef __FUNCT__
5061 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5062 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5063 {
5064   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5065   const PetscInt dim  = 3;
5066   ::tetgenio     in;
5067   ::tetgenio     out;
5068   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5069   PetscMPIInt    rank;
5070   PetscErrorCode ierr;
5071 
5072   PetscFunctionBegin;
5073   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5074   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5075   in.numberofpoints = vEnd - vStart;
5076   if (in.numberofpoints > 0) {
5077     PetscSection coordSection;
5078     Vec          coordinates;
5079     PetscScalar *array;
5080 
5081     in.pointlist       = new double[in.numberofpoints*dim];
5082     in.pointmarkerlist = new int[in.numberofpoints];
5083     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5084     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5085     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5086     for (v = vStart; v < vEnd; ++v) {
5087       const PetscInt idx = v - vStart;
5088       PetscInt       off, d;
5089 
5090       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5091       for (d = 0; d < dim; ++d) {
5092         in.pointlist[idx*dim + d] = array[off+d];
5093       }
5094       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5095     }
5096     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5097   }
5098   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5099   in.numberoffacets = fEnd - fStart;
5100   if (in.numberoffacets > 0) {
5101     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5102     in.facetmarkerlist = new int[in.numberoffacets];
5103     for (f = fStart; f < fEnd; ++f) {
5104       const PetscInt idx    = f - fStart;
5105       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5106 
5107       in.facetlist[idx].numberofpolygons = 1;
5108       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5109       in.facetlist[idx].numberofholes    = 0;
5110       in.facetlist[idx].holelist         = NULL;
5111 
5112       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5113       for (p = 0; p < numPoints*2; p += 2) {
5114         const PetscInt point = points[p];
5115         if ((point >= vStart) && (point < vEnd)) {
5116           points[numVertices++] = point;
5117         }
5118       }
5119 
5120       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5121       poly->numberofvertices = numVertices;
5122       poly->vertexlist       = new int[poly->numberofvertices];
5123       for (v = 0; v < numVertices; ++v) {
5124         const PetscInt vIdx = points[v] - vStart;
5125         poly->vertexlist[v] = vIdx;
5126       }
5127       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5128       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5129     }
5130   }
5131   if (!rank) {
5132     char args[32];
5133 
5134     /* Take away 'Q' for verbose output */
5135     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5136     ::tetrahedralize(args, &in, &out);
5137   }
5138   {
5139     const PetscInt numCorners  = 4;
5140     const PetscInt numCells    = out.numberoftetrahedra;
5141     const PetscInt numVertices = out.numberofpoints;
5142     const int     *cells       = out.tetrahedronlist;
5143     const double  *meshCoords  = out.pointlist;
5144 
5145     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5146     /* Set labels */
5147     for (v = 0; v < numVertices; ++v) {
5148       if (out.pointmarkerlist[v]) {
5149         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5150       }
5151     }
5152     if (interpolate) {
5153       PetscInt e;
5154 
5155       for (e = 0; e < out.numberofedges; e++) {
5156         if (out.edgemarkerlist[e]) {
5157           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5158           const PetscInt *edges;
5159           PetscInt        numEdges;
5160 
5161           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5162           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5163           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5164           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5165         }
5166       }
5167       for (f = 0; f < out.numberoftrifaces; f++) {
5168         if (out.trifacemarkerlist[f]) {
5169           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5170           const PetscInt *faces;
5171           PetscInt        numFaces;
5172 
5173           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5174           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5175           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5176           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5177         }
5178       }
5179     }
5180     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5181   }
5182   PetscFunctionReturn(0);
5183 }
5184 
5185 #undef __FUNCT__
5186 #define __FUNCT__ "DMPlexRefine_Tetgen"
5187 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5188 {
5189   MPI_Comm       comm = ((PetscObject) dm)->comm;
5190   const PetscInt dim  = 3;
5191   ::tetgenio     in;
5192   ::tetgenio     out;
5193   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5194   PetscMPIInt    rank;
5195   PetscErrorCode ierr;
5196 
5197   PetscFunctionBegin;
5198   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5199   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5200   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5201   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5202   in.numberofpoints = vEnd - vStart;
5203   if (in.numberofpoints > 0) {
5204     PetscSection coordSection;
5205     Vec          coordinates;
5206     PetscScalar *array;
5207 
5208     in.pointlist       = new double[in.numberofpoints*dim];
5209     in.pointmarkerlist = new int[in.numberofpoints];
5210     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5211     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5212     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5213     for (v = vStart; v < vEnd; ++v) {
5214       const PetscInt idx = v - vStart;
5215       PetscInt       off, d;
5216 
5217       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5218       for (d = 0; d < dim; ++d) {
5219         in.pointlist[idx*dim + d] = array[off+d];
5220       }
5221       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5222     }
5223     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5224   }
5225   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5226   in.numberofcorners       = 4;
5227   in.numberoftetrahedra    = cEnd - cStart;
5228   in.tetrahedronvolumelist = (double *) maxVolumes;
5229   if (in.numberoftetrahedra > 0) {
5230     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5231     for (c = cStart; c < cEnd; ++c) {
5232       const PetscInt idx     = c - cStart;
5233       PetscInt      *closure = PETSC_NULL;
5234       PetscInt       closureSize;
5235 
5236       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5237       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5238       for (v = 0; v < 4; ++v) {
5239         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5240       }
5241       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5242     }
5243   }
5244   /* TODO: Put in boundary faces with markers */
5245   if (!rank) {
5246     char args[32];
5247 
5248     /* Take away 'Q' for verbose output */
5249     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5250     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5251     ::tetrahedralize(args, &in, &out);
5252   }
5253   in.tetrahedronvolumelist = NULL;
5254 
5255   {
5256     const PetscInt numCorners  = 4;
5257     const PetscInt numCells    = out.numberoftetrahedra;
5258     const PetscInt numVertices = out.numberofpoints;
5259     const int     *cells       = out.tetrahedronlist;
5260     const double  *meshCoords  = out.pointlist;
5261     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5262 
5263     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5264     /* Set labels */
5265     for (v = 0; v < numVertices; ++v) {
5266       if (out.pointmarkerlist[v]) {
5267         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5268       }
5269     }
5270     if (interpolate) {
5271       PetscInt e, f;
5272 
5273       for (e = 0; e < out.numberofedges; e++) {
5274         if (out.edgemarkerlist[e]) {
5275           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5276           const PetscInt *edges;
5277           PetscInt        numEdges;
5278 
5279           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5280           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5281           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5282           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5283         }
5284       }
5285       for (f = 0; f < out.numberoftrifaces; f++) {
5286         if (out.trifacemarkerlist[f]) {
5287           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5288           const PetscInt *faces;
5289           PetscInt        numFaces;
5290 
5291           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5292           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5293           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5294           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5295         }
5296       }
5297     }
5298     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5299   }
5300   PetscFunctionReturn(0);
5301 }
5302 #endif
5303 
5304 #if defined(PETSC_HAVE_CTETGEN)
5305 #include "ctetgen.h"
5306 
5307 #undef __FUNCT__
5308 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5309 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5310 {
5311   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5312   const PetscInt dim  = 3;
5313   PLC           *in, *out;
5314   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5315   PetscMPIInt    rank;
5316   PetscErrorCode ierr;
5317 
5318   PetscFunctionBegin;
5319   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5320   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5321   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5322   ierr = PLCCreate(&in);CHKERRQ(ierr);
5323   ierr = PLCCreate(&out);CHKERRQ(ierr);
5324   in->numberofpoints = vEnd - vStart;
5325   if (in->numberofpoints > 0) {
5326     PetscSection coordSection;
5327     Vec          coordinates;
5328     PetscScalar *array;
5329 
5330     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5331     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5332     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5333     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5334     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5335     for (v = vStart; v < vEnd; ++v) {
5336       const PetscInt idx = v - vStart;
5337       PetscInt       off, d, m;
5338 
5339       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5340       for (d = 0; d < dim; ++d) {
5341         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5342       }
5343       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5344       in->pointmarkerlist[idx] = (int) m;
5345     }
5346     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5347   }
5348   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5349   in->numberoffacets = fEnd - fStart;
5350   if (in->numberoffacets > 0) {
5351     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5352     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5353     for (f = fStart; f < fEnd; ++f) {
5354       const PetscInt idx    = f - fStart;
5355       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5356       polygon       *poly;
5357 
5358       in->facetlist[idx].numberofpolygons = 1;
5359       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5360       in->facetlist[idx].numberofholes    = 0;
5361       in->facetlist[idx].holelist         = PETSC_NULL;
5362 
5363       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5364       for (p = 0; p < numPoints*2; p += 2) {
5365         const PetscInt point = points[p];
5366         if ((point >= vStart) && (point < vEnd)) {
5367           points[numVertices++] = point;
5368         }
5369       }
5370 
5371       poly = in->facetlist[idx].polygonlist;
5372       poly->numberofvertices = numVertices;
5373       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5374       for (v = 0; v < numVertices; ++v) {
5375         const PetscInt vIdx = points[v] - vStart;
5376         poly->vertexlist[v] = vIdx;
5377       }
5378       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5379       in->facetmarkerlist[idx] = (int) m;
5380       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5381     }
5382   }
5383   if (!rank) {
5384     TetGenOpts t;
5385 
5386     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5387     t.in        = boundary; /* Should go away */
5388     t.plc       = 1;
5389     t.quality   = 1;
5390     t.edgesout  = 1;
5391     t.zeroindex = 1;
5392     t.quiet     = 1;
5393     t.verbose   = verbose;
5394     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5395     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5396   }
5397   {
5398     const PetscInt numCorners  = 4;
5399     const PetscInt numCells    = out->numberoftetrahedra;
5400     const PetscInt numVertices = out->numberofpoints;
5401     const int     *cells       = out->tetrahedronlist;
5402     const double  *meshCoords  = out->pointlist;
5403 
5404     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5405     /* Set labels */
5406     for (v = 0; v < numVertices; ++v) {
5407       if (out->pointmarkerlist[v]) {
5408         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5409       }
5410     }
5411     if (interpolate) {
5412       PetscInt e;
5413 
5414       for (e = 0; e < out->numberofedges; e++) {
5415         if (out->edgemarkerlist[e]) {
5416           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5417           const PetscInt *edges;
5418           PetscInt        numEdges;
5419 
5420           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5421           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5422           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5423           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5424         }
5425       }
5426       for (f = 0; f < out->numberoftrifaces; f++) {
5427         if (out->trifacemarkerlist[f]) {
5428           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5429           const PetscInt *faces;
5430           PetscInt        numFaces;
5431 
5432           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5433           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5434           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5435           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5436         }
5437       }
5438     }
5439     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5440   }
5441 
5442   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5443   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5444   PetscFunctionReturn(0);
5445 }
5446 
5447 #undef __FUNCT__
5448 #define __FUNCT__ "DMPlexRefine_CTetgen"
5449 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5450 {
5451   MPI_Comm       comm = ((PetscObject) dm)->comm;
5452   const PetscInt dim  = 3;
5453   PLC           *in, *out;
5454   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5455   PetscMPIInt    rank;
5456   PetscErrorCode ierr;
5457 
5458   PetscFunctionBegin;
5459   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5460   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5461   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5462   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5463   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5464   ierr = PLCCreate(&in);CHKERRQ(ierr);
5465   ierr = PLCCreate(&out);CHKERRQ(ierr);
5466   in->numberofpoints = vEnd - vStart;
5467   if (in->numberofpoints > 0) {
5468     PetscSection coordSection;
5469     Vec          coordinates;
5470     PetscScalar *array;
5471 
5472     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5473     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5474     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5475     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5476     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5477     for (v = vStart; v < vEnd; ++v) {
5478       const PetscInt idx = v - vStart;
5479       PetscInt       off, d, m;
5480 
5481       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5482       for (d = 0; d < dim; ++d) {
5483         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5484       }
5485       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5486       in->pointmarkerlist[idx] = (int) m;
5487     }
5488     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5489   }
5490   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5491   in->numberofcorners       = 4;
5492   in->numberoftetrahedra    = cEnd - cStart;
5493   in->tetrahedronvolumelist = maxVolumes;
5494   if (in->numberoftetrahedra > 0) {
5495     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5496     for (c = cStart; c < cEnd; ++c) {
5497       const PetscInt idx     = c - cStart;
5498       PetscInt      *closure = PETSC_NULL;
5499       PetscInt       closureSize;
5500 
5501       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5502       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5503       for (v = 0; v < 4; ++v) {
5504         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5505       }
5506       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5507     }
5508   }
5509   if (!rank) {
5510     TetGenOpts t;
5511 
5512     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5513     t.in        = dm; /* Should go away */
5514     t.refine    = 1;
5515     t.varvolume = 1;
5516     t.quality   = 1;
5517     t.edgesout  = 1;
5518     t.zeroindex = 1;
5519     t.quiet     = 1;
5520     t.verbose   = verbose; /* Change this */
5521     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5522     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5523   }
5524   {
5525     const PetscInt numCorners  = 4;
5526     const PetscInt numCells    = out->numberoftetrahedra;
5527     const PetscInt numVertices = out->numberofpoints;
5528     const int     *cells       = out->tetrahedronlist;
5529     const double  *meshCoords  = out->pointlist;
5530     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5531 
5532     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5533     /* Set labels */
5534     for (v = 0; v < numVertices; ++v) {
5535       if (out->pointmarkerlist[v]) {
5536         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5537       }
5538     }
5539     if (interpolate) {
5540       PetscInt e, f;
5541 
5542       for (e = 0; e < out->numberofedges; e++) {
5543         if (out->edgemarkerlist[e]) {
5544           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5545           const PetscInt *edges;
5546           PetscInt        numEdges;
5547 
5548           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5549           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5550           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5551           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5552         }
5553       }
5554       for (f = 0; f < out->numberoftrifaces; f++) {
5555         if (out->trifacemarkerlist[f]) {
5556           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5557           const PetscInt *faces;
5558           PetscInt        numFaces;
5559 
5560           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5561           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5562           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5563           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5564         }
5565       }
5566     }
5567     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5568   }
5569   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5570   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5571   PetscFunctionReturn(0);
5572 }
5573 #endif
5574 
5575 #undef __FUNCT__
5576 #define __FUNCT__ "DMPlexGenerate"
5577 /*@C
5578   DMPlexGenerate - Generates a mesh.
5579 
5580   Not Collective
5581 
5582   Input Parameters:
5583 + boundary - The DMPlex boundary object
5584 . name - The mesh generation package name
5585 - interpolate - Flag to create intermediate mesh elements
5586 
5587   Output Parameter:
5588 . mesh - The DMPlex object
5589 
5590   Level: intermediate
5591 
5592 .keywords: mesh, elements
5593 .seealso: DMPlexCreate(), DMRefine()
5594 @*/
5595 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5596 {
5597   PetscInt       dim;
5598   char           genname[1024];
5599   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5600   PetscErrorCode ierr;
5601 
5602   PetscFunctionBegin;
5603   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5604   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5605   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5606   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5607   if (flg) {name = genname;}
5608   if (name) {
5609     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5610     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5611     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5612   }
5613   switch (dim) {
5614   case 1:
5615     if (!name || isTriangle) {
5616 #if defined(PETSC_HAVE_TRIANGLE)
5617       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5618 #else
5619       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5620 #endif
5621     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5622     break;
5623   case 2:
5624     if (!name || isCTetgen) {
5625 #if defined(PETSC_HAVE_CTETGEN)
5626       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5627 #else
5628       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5629 #endif
5630     } else if (isTetgen) {
5631 #if defined(PETSC_HAVE_TETGEN)
5632       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5633 #else
5634       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5635 #endif
5636     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5637     break;
5638   default:
5639     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5640   }
5641   PetscFunctionReturn(0);
5642 }
5643 
5644 typedef PetscInt CellRefiner;
5645 
5646 #undef __FUNCT__
5647 #define __FUNCT__ "GetDepthStart_Private"
5648 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5649 {
5650   PetscFunctionBegin;
5651   if (cStart) *cStart = 0;
5652   if (vStart) *vStart = depthSize[depth];
5653   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5654   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5655   PetscFunctionReturn(0);
5656 }
5657 
5658 #undef __FUNCT__
5659 #define __FUNCT__ "GetDepthEnd_Private"
5660 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5661 {
5662   PetscFunctionBegin;
5663   if (cEnd) *cEnd = depthSize[depth];
5664   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5665   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5666   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5667   PetscFunctionReturn(0);
5668 }
5669 
5670 #undef __FUNCT__
5671 #define __FUNCT__ "CellRefinerGetSizes"
5672 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5673 {
5674   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5675   PetscErrorCode ierr;
5676 
5677   PetscFunctionBegin;
5678   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5679   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5680   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5681   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5682   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5683   switch (refiner) {
5684   case 1:
5685     /* Simplicial 2D */
5686     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5687     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5688     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5689     break;
5690   case 3:
5691     /* Hybrid 2D */
5692     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5693     cMax = PetscMin(cEnd, cMax);
5694     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5695     fMax = PetscMin(fEnd, fMax);
5696     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5697     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 */
5698     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5699     break;
5700   case 2:
5701     /* Hex 2D */
5702     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5703     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5704     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5705     break;
5706   default:
5707     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5708   }
5709   PetscFunctionReturn(0);
5710 }
5711 
5712 #undef __FUNCT__
5713 #define __FUNCT__ "CellRefinerSetConeSizes"
5714 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5715 {
5716   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5717   PetscErrorCode ierr;
5718 
5719   PetscFunctionBegin;
5720   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5721   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5722   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5723   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5724   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5725   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5726   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5727   switch (refiner) {
5728   case 1:
5729     /* Simplicial 2D */
5730     /* All cells have 3 faces */
5731     for (c = cStart; c < cEnd; ++c) {
5732       for (r = 0; r < 4; ++r) {
5733         const PetscInt newp = (c - cStart)*4 + r;
5734 
5735         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5736       }
5737     }
5738     /* Split faces have 2 vertices and the same cells as the parent */
5739     for (f = fStart; f < fEnd; ++f) {
5740       for (r = 0; r < 2; ++r) {
5741         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5742         PetscInt       size;
5743 
5744         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5745         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5746         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5747       }
5748     }
5749     /* Interior faces have 2 vertices and 2 cells */
5750     for (c = cStart; c < cEnd; ++c) {
5751       for (r = 0; r < 3; ++r) {
5752         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5753 
5754         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5755         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5756       }
5757     }
5758     /* Old vertices have identical supports */
5759     for (v = vStart; v < vEnd; ++v) {
5760       const PetscInt newp = vStartNew + (v - vStart);
5761       PetscInt       size;
5762 
5763       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5764       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5765     }
5766     /* Face vertices have 2 + cells*2 supports */
5767     for (f = fStart; f < fEnd; ++f) {
5768       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5769       PetscInt       size;
5770 
5771       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5772       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5773     }
5774     break;
5775   case 2:
5776     /* Hex 2D */
5777     /* All cells have 4 faces */
5778     for (c = cStart; c < cEnd; ++c) {
5779       for (r = 0; r < 4; ++r) {
5780         const PetscInt newp = (c - cStart)*4 + r;
5781 
5782         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5783       }
5784     }
5785     /* Split faces have 2 vertices and the same cells as the parent */
5786     for (f = fStart; f < fEnd; ++f) {
5787       for (r = 0; r < 2; ++r) {
5788         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5789         PetscInt       size;
5790 
5791         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5792         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5793         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5794       }
5795     }
5796     /* Interior faces have 2 vertices and 2 cells */
5797     for (c = cStart; c < cEnd; ++c) {
5798       for (r = 0; r < 4; ++r) {
5799         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5800 
5801         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5802         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5803       }
5804     }
5805     /* Old vertices have identical supports */
5806     for (v = vStart; v < vEnd; ++v) {
5807       const PetscInt newp = vStartNew + (v - vStart);
5808       PetscInt       size;
5809 
5810       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5811       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5812     }
5813     /* Face vertices have 2 + cells supports */
5814     for (f = fStart; f < fEnd; ++f) {
5815       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5816       PetscInt       size;
5817 
5818       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5819       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5820     }
5821     /* Cell vertices have 4 supports */
5822     for (c = cStart; c < cEnd; ++c) {
5823       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5824 
5825       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5826     }
5827     break;
5828   case 3:
5829     /* Hybrid 2D */
5830     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5831     cMax = PetscMin(cEnd, cMax);
5832     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5833     fMax = PetscMin(fEnd, fMax);
5834     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5835     /* Interior cells have 3 faces */
5836     for (c = cStart; c < cMax; ++c) {
5837       for (r = 0; r < 4; ++r) {
5838         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5839 
5840         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5841       }
5842     }
5843     /* Hybrid cells have 4 faces */
5844     for (c = cMax; c < cEnd; ++c) {
5845       for (r = 0; r < 2; ++r) {
5846         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5847 
5848         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5849       }
5850     }
5851     /* Interior split faces have 2 vertices and the same cells as the parent */
5852     for (f = fStart; f < fMax; ++f) {
5853       for (r = 0; r < 2; ++r) {
5854         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5855         PetscInt       size;
5856 
5857         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5858         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5859         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5860       }
5861     }
5862     /* Interior cell faces have 2 vertices and 2 cells */
5863     for (c = cStart; c < cMax; ++c) {
5864       for (r = 0; r < 3; ++r) {
5865         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5866 
5867         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5868         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5869       }
5870     }
5871     /* Hybrid faces have 2 vertices and the same cells */
5872     for (f = fMax; f < fEnd; ++f) {
5873       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5874       PetscInt       size;
5875 
5876       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5877       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5878       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5879     }
5880     /* Hybrid cell faces have 2 vertices and 2 cells */
5881     for (c = cMax; c < cEnd; ++c) {
5882       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5883 
5884       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5885       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5886     }
5887     /* Old vertices have identical supports */
5888     for (v = vStart; v < vEnd; ++v) {
5889       const PetscInt newp = vStartNew + (v - vStart);
5890       PetscInt       size;
5891 
5892       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5893       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5894     }
5895     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5896     for (f = fStart; f < fMax; ++f) {
5897       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5898       const PetscInt *support;
5899       PetscInt        size, newSize = 2, s;
5900 
5901       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5902       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5903       for (s = 0; s < size; ++s) {
5904         if (support[s] >= cMax) {
5905           newSize += 1;
5906         } else {
5907           newSize += 2;
5908         }
5909       }
5910       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5911     }
5912     break;
5913   default:
5914     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5915   }
5916   PetscFunctionReturn(0);
5917 }
5918 
5919 #undef __FUNCT__
5920 #define __FUNCT__ "CellRefinerSetCones"
5921 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5922 {
5923   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;
5924   PetscInt       maxSupportSize, *supportRef;
5925   PetscErrorCode ierr;
5926 
5927   PetscFunctionBegin;
5928   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5929   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5930   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5931   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5932   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5933   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5934   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5935   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5936   switch (refiner) {
5937   case 1:
5938     /* Simplicial 2D */
5939     /*
5940      2
5941      |\
5942      | \
5943      |  \
5944      |   \
5945      | C  \
5946      |     \
5947      |      \
5948      2---1---1
5949      |\  D  / \
5950      | 2   0   \
5951      |A \ /  B  \
5952      0---0-------1
5953      */
5954     /* All cells have 3 faces */
5955     for (c = cStart; c < cEnd; ++c) {
5956       const PetscInt  newp = cStartNew + (c - cStart)*4;
5957       const PetscInt *cone, *ornt;
5958       PetscInt        coneNew[3], orntNew[3];
5959 
5960       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5961       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5962       /* A triangle */
5963       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5964       orntNew[0] = ornt[0];
5965       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5966       orntNew[1] = -2;
5967       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5968       orntNew[2] = ornt[2];
5969       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5970       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5971 #if 1
5972       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);
5973       for (p = 0; p < 3; ++p) {
5974         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);
5975       }
5976 #endif
5977       /* B triangle */
5978       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5979       orntNew[0] = ornt[0];
5980       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5981       orntNew[1] = ornt[1];
5982       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5983       orntNew[2] = -2;
5984       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5985       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5986 #if 1
5987       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);
5988       for (p = 0; p < 3; ++p) {
5989         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);
5990       }
5991 #endif
5992       /* C triangle */
5993       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5994       orntNew[0] = -2;
5995       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5996       orntNew[1] = ornt[1];
5997       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5998       orntNew[2] = ornt[2];
5999       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6000       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6001 #if 1
6002       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);
6003       for (p = 0; p < 3; ++p) {
6004         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);
6005       }
6006 #endif
6007       /* D triangle */
6008       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6009       orntNew[0] = 0;
6010       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6011       orntNew[1] = 0;
6012       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6013       orntNew[2] = 0;
6014       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6015       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6016 #if 1
6017       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);
6018       for (p = 0; p < 3; ++p) {
6019         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);
6020       }
6021 #endif
6022     }
6023     /* Split faces have 2 vertices and the same cells as the parent */
6024     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6025     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6026     for (f = fStart; f < fEnd; ++f) {
6027       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6028 
6029       for (r = 0; r < 2; ++r) {
6030         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6031         const PetscInt *cone, *support;
6032         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6033 
6034         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6035         coneNew[0] = vStartNew + (cone[0] - vStart);
6036         coneNew[1] = vStartNew + (cone[1] - vStart);
6037         coneNew[(r+1)%2] = newv;
6038         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6039 #if 1
6040         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6041         for (p = 0; p < 2; ++p) {
6042           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);
6043         }
6044 #endif
6045         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6046         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6047         for (s = 0; s < supportSize; ++s) {
6048           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6049           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6050           for (c = 0; c < coneSize; ++c) {
6051             if (cone[c] == f) {
6052               break;
6053             }
6054           }
6055           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6056         }
6057         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6058 #if 1
6059         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6060         for (p = 0; p < supportSize; ++p) {
6061           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);
6062         }
6063 #endif
6064       }
6065     }
6066     /* Interior faces have 2 vertices and 2 cells */
6067     for (c = cStart; c < cEnd; ++c) {
6068       const PetscInt *cone;
6069 
6070       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6071       for (r = 0; r < 3; ++r) {
6072         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6073         PetscInt       coneNew[2];
6074         PetscInt       supportNew[2];
6075 
6076         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6077         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6078         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6079 #if 1
6080         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6081         for (p = 0; p < 2; ++p) {
6082           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);
6083         }
6084 #endif
6085         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6086         supportNew[1] = (c - cStart)*4 + 3;
6087         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6088 #if 1
6089         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6090         for (p = 0; p < 2; ++p) {
6091           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);
6092         }
6093 #endif
6094       }
6095     }
6096     /* Old vertices have identical supports */
6097     for (v = vStart; v < vEnd; ++v) {
6098       const PetscInt  newp = vStartNew + (v - vStart);
6099       const PetscInt *support, *cone;
6100       PetscInt        size, s;
6101 
6102       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6103       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6104       for (s = 0; s < size; ++s) {
6105         PetscInt r = 0;
6106 
6107         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6108         if (cone[1] == v) r = 1;
6109         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6110       }
6111       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6112 #if 1
6113       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6114       for (p = 0; p < size; ++p) {
6115         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);
6116       }
6117 #endif
6118     }
6119     /* Face vertices have 2 + cells*2 supports */
6120     for (f = fStart; f < fEnd; ++f) {
6121       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6122       const PetscInt *cone, *support;
6123       PetscInt        size, s;
6124 
6125       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6126       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6127       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6128       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
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] == f) r = 1;
6134         else if (cone[2] == f) r = 2;
6135         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6136         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6137       }
6138       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6139 #if 1
6140       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6141       for (p = 0; p < 2+size*2; ++p) {
6142         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);
6143       }
6144 #endif
6145     }
6146     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6147     break;
6148   case 2:
6149     /* Hex 2D */
6150     /*
6151      3---------2---------2
6152      |         |         |
6153      |    D    2    C    |
6154      |         |         |
6155      3----3----0----1----1
6156      |         |         |
6157      |    A    0    B    |
6158      |         |         |
6159      0---------0---------1
6160      */
6161     /* All cells have 4 faces */
6162     for (c = cStart; c < cEnd; ++c) {
6163       const PetscInt  newp = (c - cStart)*4;
6164       const PetscInt *cone, *ornt;
6165       PetscInt        coneNew[4], orntNew[4];
6166 
6167       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6168       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6169       /* A quad */
6170       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6171       orntNew[0] = ornt[0];
6172       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6173       orntNew[1] = 0;
6174       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6175       orntNew[2] = -2;
6176       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6177       orntNew[3] = ornt[3];
6178       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6179       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6180 #if 1
6181       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);
6182       for (p = 0; p < 4; ++p) {
6183         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);
6184       }
6185 #endif
6186       /* B quad */
6187       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6188       orntNew[0] = ornt[0];
6189       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6190       orntNew[1] = ornt[1];
6191       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6192       orntNew[2] = 0;
6193       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6194       orntNew[3] = -2;
6195       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6196       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6197 #if 1
6198       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);
6199       for (p = 0; p < 4; ++p) {
6200         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);
6201       }
6202 #endif
6203       /* C quad */
6204       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6205       orntNew[0] = -2;
6206       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6207       orntNew[1] = ornt[1];
6208       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6209       orntNew[2] = ornt[2];
6210       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6211       orntNew[3] = 0;
6212       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6213       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6214 #if 1
6215       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);
6216       for (p = 0; p < 4; ++p) {
6217         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);
6218       }
6219 #endif
6220       /* D quad */
6221       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6222       orntNew[0] = 0;
6223       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6224       orntNew[1] = -2;
6225       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6226       orntNew[2] = ornt[2];
6227       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6228       orntNew[3] = ornt[3];
6229       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6230       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6231 #if 1
6232       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);
6233       for (p = 0; p < 4; ++p) {
6234         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);
6235       }
6236 #endif
6237     }
6238     /* Split faces have 2 vertices and the same cells as the parent */
6239     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6240     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6241     for (f = fStart; f < fEnd; ++f) {
6242       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6243 
6244       for (r = 0; r < 2; ++r) {
6245         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6246         const PetscInt *cone, *support;
6247         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6248 
6249         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6250         coneNew[0] = vStartNew + (cone[0] - vStart);
6251         coneNew[1] = vStartNew + (cone[1] - vStart);
6252         coneNew[(r+1)%2] = newv;
6253         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6254 #if 1
6255         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6256         for (p = 0; p < 2; ++p) {
6257           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);
6258         }
6259 #endif
6260         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6261         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6262         for (s = 0; s < supportSize; ++s) {
6263           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6264           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6265           for (c = 0; c < coneSize; ++c) {
6266             if (cone[c] == f) {
6267               break;
6268             }
6269           }
6270           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6271         }
6272         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6273 #if 1
6274         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6275         for (p = 0; p < supportSize; ++p) {
6276           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);
6277         }
6278 #endif
6279       }
6280     }
6281     /* Interior faces have 2 vertices and 2 cells */
6282     for (c = cStart; c < cEnd; ++c) {
6283       const PetscInt *cone;
6284       PetscInt        coneNew[2], supportNew[2];
6285 
6286       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6287       for (r = 0; r < 4; ++r) {
6288         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6289 
6290         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6291         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6292         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6293 #if 1
6294         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6295         for (p = 0; p < 2; ++p) {
6296           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);
6297         }
6298 #endif
6299         supportNew[0] = (c - cStart)*4 + r;
6300         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6301         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6302 #if 1
6303         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6304         for (p = 0; p < 2; ++p) {
6305           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);
6306         }
6307 #endif
6308       }
6309     }
6310     /* Old vertices have identical supports */
6311     for (v = vStart; v < vEnd; ++v) {
6312       const PetscInt  newp = vStartNew + (v - vStart);
6313       const PetscInt *support, *cone;
6314       PetscInt        size, s;
6315 
6316       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6317       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6318       for (s = 0; s < size; ++s) {
6319         PetscInt r = 0;
6320 
6321         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6322         if (cone[1] == v) r = 1;
6323         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6324       }
6325       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6326 #if 1
6327       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6328       for (p = 0; p < size; ++p) {
6329         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);
6330       }
6331 #endif
6332     }
6333     /* Face vertices have 2 + cells supports */
6334     for (f = fStart; f < fEnd; ++f) {
6335       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6336       const PetscInt *cone, *support;
6337       PetscInt        size, s;
6338 
6339       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6340       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6341       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6342       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6343       for (s = 0; s < size; ++s) {
6344         PetscInt r = 0;
6345 
6346         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6347         if      (cone[1] == f) r = 1;
6348         else if (cone[2] == f) r = 2;
6349         else if (cone[3] == f) r = 3;
6350         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6351       }
6352       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6353 #if 1
6354       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6355       for (p = 0; p < 2+size; ++p) {
6356         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);
6357       }
6358 #endif
6359     }
6360     /* Cell vertices have 4 supports */
6361     for (c = cStart; c < cEnd; ++c) {
6362       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6363       PetscInt       supportNew[4];
6364 
6365       for (r = 0; r < 4; ++r) {
6366         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6367       }
6368       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6369     }
6370     break;
6371   case 3:
6372     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6373     cMax = PetscMin(cEnd, cMax);
6374     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6375     fMax = PetscMin(fEnd, fMax);
6376     /* Interior cells have 3 faces */
6377     for (c = cStart; c < cMax; ++c) {
6378       const PetscInt  newp = cStartNew + (c - cStart)*4;
6379       const PetscInt *cone, *ornt;
6380       PetscInt        coneNew[3], orntNew[3];
6381 
6382       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6383       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6384       /* A triangle */
6385       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6386       orntNew[0] = ornt[0];
6387       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6388       orntNew[1] = -2;
6389       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6390       orntNew[2] = ornt[2];
6391       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6392       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6393 #if 1
6394       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);
6395       for (p = 0; p < 3; ++p) {
6396         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);
6397       }
6398 #endif
6399       /* B triangle */
6400       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6401       orntNew[0] = ornt[0];
6402       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6403       orntNew[1] = ornt[1];
6404       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6405       orntNew[2] = -2;
6406       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6407       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6408 #if 1
6409       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);
6410       for (p = 0; p < 3; ++p) {
6411         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);
6412       }
6413 #endif
6414       /* C triangle */
6415       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6416       orntNew[0] = -2;
6417       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6418       orntNew[1] = ornt[1];
6419       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6420       orntNew[2] = ornt[2];
6421       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6422       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6423 #if 1
6424       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);
6425       for (p = 0; p < 3; ++p) {
6426         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);
6427       }
6428 #endif
6429       /* D triangle */
6430       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6431       orntNew[0] = 0;
6432       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6433       orntNew[1] = 0;
6434       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6435       orntNew[2] = 0;
6436       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6437       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6438 #if 1
6439       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);
6440       for (p = 0; p < 3; ++p) {
6441         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);
6442       }
6443 #endif
6444     }
6445     /*
6446      2----3----3
6447      |         |
6448      |    B    |
6449      |         |
6450      0----4--- 1
6451      |         |
6452      |    A    |
6453      |         |
6454      0----2----1
6455      */
6456     /* Hybrid cells have 4 faces */
6457     for (c = cMax; c < cEnd; ++c) {
6458       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6459       const PetscInt *cone, *ornt;
6460       PetscInt        coneNew[4], orntNew[4];
6461 
6462       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6463       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6464       /* A quad */
6465       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6466       orntNew[0] = ornt[0];
6467       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6468       orntNew[1] = ornt[1];
6469       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6470       orntNew[2] = 0;
6471       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6472       orntNew[3] = 0;
6473       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6474       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6475 #if 1
6476       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);
6477       for (p = 0; p < 4; ++p) {
6478         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);
6479       }
6480 #endif
6481       /* B quad */
6482       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6483       orntNew[0] = ornt[0];
6484       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6485       orntNew[1] = ornt[1];
6486       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6487       orntNew[2] = 0;
6488       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6489       orntNew[3] = 0;
6490       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6491       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6492 #if 1
6493       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);
6494       for (p = 0; p < 4; ++p) {
6495         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);
6496       }
6497 #endif
6498     }
6499     /* Interior split faces have 2 vertices and the same cells as the parent */
6500     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6501     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6502     for (f = fStart; f < fMax; ++f) {
6503       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6504 
6505       for (r = 0; r < 2; ++r) {
6506         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6507         const PetscInt *cone, *support;
6508         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6509 
6510         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6511         coneNew[0] = vStartNew + (cone[0] - vStart);
6512         coneNew[1] = vStartNew + (cone[1] - vStart);
6513         coneNew[(r+1)%2] = newv;
6514         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6515 #if 1
6516         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6517         for (p = 0; p < 2; ++p) {
6518           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);
6519         }
6520 #endif
6521         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6522         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6523         for (s = 0; s < supportSize; ++s) {
6524           if (support[s] >= cMax) {
6525             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6526           } else {
6527             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6528             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6529             for (c = 0; c < coneSize; ++c) {
6530               if (cone[c] == f) {
6531                 break;
6532               }
6533             }
6534             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6535           }
6536         }
6537         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6538 #if 1
6539         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6540         for (p = 0; p < supportSize; ++p) {
6541           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);
6542         }
6543 #endif
6544       }
6545     }
6546     /* Interior cell faces have 2 vertices and 2 cells */
6547     for (c = cStart; c < cMax; ++c) {
6548       const PetscInt *cone;
6549 
6550       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6551       for (r = 0; r < 3; ++r) {
6552         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6553         PetscInt       coneNew[2];
6554         PetscInt       supportNew[2];
6555 
6556         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6557         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6558         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6559 #if 1
6560         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6561         for (p = 0; p < 2; ++p) {
6562           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);
6563         }
6564 #endif
6565         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6566         supportNew[1] = (c - cStart)*4 + 3;
6567         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6568 #if 1
6569         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6570         for (p = 0; p < 2; ++p) {
6571           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);
6572         }
6573 #endif
6574       }
6575     }
6576     /* Interior hybrid faces have 2 vertices and the same cells */
6577     for (f = fMax; f < fEnd; ++f) {
6578       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6579       const PetscInt *cone;
6580       const PetscInt *support;
6581       PetscInt        coneNew[2];
6582       PetscInt        supportNew[2];
6583       PetscInt        size, s, r;
6584 
6585       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6586       coneNew[0] = vStartNew + (cone[0] - vStart);
6587       coneNew[1] = vStartNew + (cone[1] - vStart);
6588       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6589 #if 1
6590       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6591       for (p = 0; p < 2; ++p) {
6592         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);
6593       }
6594 #endif
6595       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6596       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6597       for (s = 0; s < size; ++s) {
6598         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6599         for (r = 0; r < 2; ++r) {
6600           if (cone[r+2] == f) break;
6601         }
6602         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6603       }
6604       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6605 #if 1
6606       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6607       for (p = 0; p < size; ++p) {
6608         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);
6609       }
6610 #endif
6611     }
6612     /* Cell hybrid faces have 2 vertices and 2 cells */
6613     for (c = cMax; c < cEnd; ++c) {
6614       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6615       const PetscInt *cone;
6616       PetscInt        coneNew[2];
6617       PetscInt        supportNew[2];
6618 
6619       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6620       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6621       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6622       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6623 #if 1
6624       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6625       for (p = 0; p < 2; ++p) {
6626         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);
6627       }
6628 #endif
6629       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6630       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6631       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6632 #if 1
6633       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6634       for (p = 0; p < 2; ++p) {
6635         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);
6636       }
6637 #endif
6638     }
6639     /* Old vertices have identical supports */
6640     for (v = vStart; v < vEnd; ++v) {
6641       const PetscInt  newp = vStartNew + (v - vStart);
6642       const PetscInt *support, *cone;
6643       PetscInt        size, s;
6644 
6645       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6646       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6647       for (s = 0; s < size; ++s) {
6648         if (support[s] >= fMax) {
6649           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6650         } else {
6651           PetscInt r = 0;
6652 
6653           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6654           if (cone[1] == v) r = 1;
6655           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6656         }
6657       }
6658       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6659 #if 1
6660       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6661       for (p = 0; p < size; ++p) {
6662         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);
6663       }
6664 #endif
6665     }
6666     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6667     for (f = fStart; f < fMax; ++f) {
6668       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6669       const PetscInt *cone, *support;
6670       PetscInt        size, newSize = 2, s;
6671 
6672       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6673       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6674       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6675       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6676       for (s = 0; s < size; ++s) {
6677         PetscInt r = 0;
6678 
6679         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6680         if (support[s] >= cMax) {
6681           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6682           newSize += 1;
6683         } else {
6684           if      (cone[1] == f) r = 1;
6685           else if (cone[2] == f) r = 2;
6686           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6687           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6688           newSize += 2;
6689         }
6690       }
6691       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6692 #if 1
6693       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6694       for (p = 0; p < newSize; ++p) {
6695         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);
6696       }
6697 #endif
6698     }
6699     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6700     break;
6701   default:
6702     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6703   }
6704   PetscFunctionReturn(0);
6705 }
6706 
6707 #undef __FUNCT__
6708 #define __FUNCT__ "CellRefinerSetCoordinates"
6709 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6710 {
6711   PetscSection   coordSection, coordSectionNew;
6712   Vec            coordinates, coordinatesNew;
6713   PetscScalar   *coords, *coordsNew;
6714   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6715   PetscErrorCode ierr;
6716 
6717   PetscFunctionBegin;
6718   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6719   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6720   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6721   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6722   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6723   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6724   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6725   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6726   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6727   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6728   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6729   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6730   if (fMax < 0) fMax = fEnd;
6731   switch (refiner) {
6732   case 1:
6733   case 2:
6734   case 3:
6735     /* Simplicial and Hex 2D */
6736     /* All vertices have the dim coordinates */
6737     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6738       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6739       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6740     }
6741     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6742     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6743     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6744     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6745     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6746     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6747     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6748     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6749     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6750     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6751     /* Old vertices have the same coordinates */
6752     for (v = vStart; v < vEnd; ++v) {
6753       const PetscInt newv = vStartNew + (v - vStart);
6754       PetscInt       off, offnew, d;
6755 
6756       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6757       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6758       for (d = 0; d < dim; ++d) {
6759         coordsNew[offnew+d] = coords[off+d];
6760       }
6761     }
6762     /* Face vertices have the average of endpoint coordinates */
6763     for (f = fStart; f < fMax; ++f) {
6764       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6765       const PetscInt *cone;
6766       PetscInt        coneSize, offA, offB, offnew, d;
6767 
6768       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6769       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6770       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6771       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6772       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6773       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6774       for (d = 0; d < dim; ++d) {
6775         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6776       }
6777     }
6778     /* Just Hex 2D */
6779     if (refiner == 2) {
6780       /* Cell vertices have the average of corner coordinates */
6781       for (c = cStart; c < cEnd; ++c) {
6782         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6783         PetscInt      *cone = PETSC_NULL;
6784         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6785 
6786         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6787         for (p = 0; p < closureSize*2; p += 2) {
6788           const PetscInt point = cone[p];
6789           if ((point >= vStart) && (point < vEnd)) {
6790             cone[coneSize++] = point;
6791           }
6792         }
6793         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6794         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6795         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6796         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6797         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6798         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6799         for (d = 0; d < dim; ++d) {
6800           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6801         }
6802         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6803       }
6804     }
6805     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6806     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6807     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6808     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6809     break;
6810   default:
6811     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6812   }
6813   PetscFunctionReturn(0);
6814 }
6815 
6816 #undef __FUNCT__
6817 #define __FUNCT__ "DMPlexCreateProcessSF"
6818 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6819 {
6820   PetscInt           numRoots, numLeaves, l;
6821   const PetscInt    *localPoints;
6822   const PetscSFNode *remotePoints;
6823   PetscInt          *localPointsNew;
6824   PetscSFNode       *remotePointsNew;
6825   PetscInt          *ranks, *ranksNew;
6826   PetscErrorCode     ierr;
6827 
6828   PetscFunctionBegin;
6829   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6830   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6831   for (l = 0; l < numLeaves; ++l) {
6832     ranks[l] = remotePoints[l].rank;
6833   }
6834   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6835   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6836   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6837   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6838   for (l = 0; l < numLeaves; ++l) {
6839     ranksNew[l]              = ranks[l];
6840     localPointsNew[l]        = l;
6841     remotePointsNew[l].index = 0;
6842     remotePointsNew[l].rank  = ranksNew[l];
6843   }
6844   ierr = PetscFree(ranks);CHKERRQ(ierr);
6845   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6846   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6847   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6848   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6849   PetscFunctionReturn(0);
6850 }
6851 
6852 #undef __FUNCT__
6853 #define __FUNCT__ "CellRefinerCreateSF"
6854 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6855 {
6856   PetscSF            sf, sfNew, sfProcess;
6857   IS                 processRanks;
6858   MPI_Datatype       depthType;
6859   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6860   const PetscInt    *localPoints, *neighbors;
6861   const PetscSFNode *remotePoints;
6862   PetscInt          *localPointsNew;
6863   PetscSFNode       *remotePointsNew;
6864   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6865   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6866   PetscErrorCode     ierr;
6867 
6868   PetscFunctionBegin;
6869   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6870   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6871   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6872   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6873   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6874   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6875   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6876   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6877   switch (refiner) {
6878   case 3:
6879     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6880     cMax = PetscMin(cEnd, cMax);
6881     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6882     fMax = PetscMin(fEnd, fMax);
6883   }
6884   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6885   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6886   /* Caculate size of new SF */
6887   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6888   if (numRoots < 0) PetscFunctionReturn(0);
6889   for (l = 0; l < numLeaves; ++l) {
6890     const PetscInt p = localPoints[l];
6891 
6892     switch (refiner) {
6893     case 1:
6894       /* Simplicial 2D */
6895       if ((p >= vStart) && (p < vEnd)) {
6896         /* Old vertices stay the same */
6897         ++numLeavesNew;
6898       } else if ((p >= fStart) && (p < fEnd)) {
6899         /* Old faces add new faces and vertex */
6900         numLeavesNew += 1 + 2;
6901       } else if ((p >= cStart) && (p < cEnd)) {
6902         /* Old cells add new cells and interior faces */
6903         numLeavesNew += 4 + 3;
6904       }
6905       break;
6906     case 2:
6907       /* Hex 2D */
6908       if ((p >= vStart) && (p < vEnd)) {
6909         /* Old vertices stay the same */
6910         ++numLeavesNew;
6911       } else if ((p >= fStart) && (p < fEnd)) {
6912         /* Old faces add new faces and vertex */
6913         numLeavesNew += 1 + 2;
6914       } else if ((p >= cStart) && (p < cEnd)) {
6915         /* Old cells add new cells and interior faces */
6916         numLeavesNew += 4 + 4;
6917       }
6918       break;
6919     default:
6920       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6921     }
6922   }
6923   /* Communicate depthSizes for each remote rank */
6924   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6925   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6926   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6927   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);
6928   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6929   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6930   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6931   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6932   for (n = 0; n < numNeighbors; ++n) {
6933     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6934   }
6935   depthSizeOld[depth]   = cMax;
6936   depthSizeOld[0]       = vMax;
6937   depthSizeOld[depth-1] = fMax;
6938   depthSizeOld[1]       = eMax;
6939   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6940   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6941   depthSizeOld[depth]   = cEnd - cStart;
6942   depthSizeOld[0]       = vEnd - vStart;
6943   depthSizeOld[depth-1] = fEnd - fStart;
6944   depthSizeOld[1]       = eEnd - eStart;
6945   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6946   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6947   for (n = 0; n < numNeighbors; ++n) {
6948     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6949   }
6950   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6951   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6952   /* Calculate new point SF */
6953   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6954   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6955   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6956   for (l = 0, m = 0; l < numLeaves; ++l) {
6957     PetscInt    p     = localPoints[l];
6958     PetscInt    rp    = remotePoints[l].index, n;
6959     PetscMPIInt rrank = remotePoints[l].rank;
6960 
6961     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6962     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6963     switch (refiner) {
6964     case 1:
6965       /* Simplicial 2D */
6966       if ((p >= vStart) && (p < vEnd)) {
6967         /* Old vertices stay the same */
6968         localPointsNew[m]        = vStartNew     + (p  - vStart);
6969         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6970         remotePointsNew[m].rank  = rrank;
6971         ++m;
6972       } else if ((p >= fStart) && (p < fEnd)) {
6973         /* Old faces add new faces and vertex */
6974         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6975         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6976         remotePointsNew[m].rank  = rrank;
6977         ++m;
6978         for (r = 0; r < 2; ++r, ++m) {
6979           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6980           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6981           remotePointsNew[m].rank  = rrank;
6982         }
6983       } else if ((p >= cStart) && (p < cEnd)) {
6984         /* Old cells add new cells and interior faces */
6985         for (r = 0; r < 4; ++r, ++m) {
6986           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6987           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6988           remotePointsNew[m].rank  = rrank;
6989         }
6990         for (r = 0; r < 3; ++r, ++m) {
6991           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6992           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6993           remotePointsNew[m].rank  = rrank;
6994         }
6995       }
6996       break;
6997     case 2:
6998       /* Hex 2D */
6999       if ((p >= vStart) && (p < vEnd)) {
7000         /* Old vertices stay the same */
7001         localPointsNew[m]        = vStartNew     + (p  - vStart);
7002         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7003         remotePointsNew[m].rank  = rrank;
7004         ++m;
7005       } else if ((p >= fStart) && (p < fEnd)) {
7006         /* Old faces add new faces and vertex */
7007         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7008         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7009         remotePointsNew[m].rank  = rrank;
7010         ++m;
7011         for (r = 0; r < 2; ++r, ++m) {
7012           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7013           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7014           remotePointsNew[m].rank  = rrank;
7015         }
7016       } else if ((p >= cStart) && (p < cEnd)) {
7017         /* Old cells add new cells and interior faces */
7018         for (r = 0; r < 4; ++r, ++m) {
7019           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7020           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7021           remotePointsNew[m].rank  = rrank;
7022         }
7023         for (r = 0; r < 4; ++r, ++m) {
7024           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7025           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7026           remotePointsNew[m].rank  = rrank;
7027         }
7028       }
7029       break;
7030     case 3:
7031       /* Hybrid simplicial 2D */
7032       if ((p >= vStart) && (p < vEnd)) {
7033         /* Old vertices stay the same */
7034         localPointsNew[m]        = vStartNew     + (p  - vStart);
7035         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7036         remotePointsNew[m].rank  = rrank;
7037         ++m;
7038       } else if ((p >= fStart) && (p < fMax)) {
7039         /* Old interior faces add new faces and vertex */
7040         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7041         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7042         remotePointsNew[m].rank  = rrank;
7043         ++m;
7044         for (r = 0; r < 2; ++r, ++m) {
7045           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7046           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7047           remotePointsNew[m].rank  = rrank;
7048         }
7049       } else if ((p >= fMax) && (p < fEnd)) {
7050         /* Old hybrid faces stay the same */
7051         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7052         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7053         remotePointsNew[m].rank  = rrank;
7054         ++m;
7055       } else if ((p >= cStart) && (p < cMax)) {
7056         /* Old interior cells add new cells and interior faces */
7057         for (r = 0; r < 4; ++r, ++m) {
7058           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7059           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7060           remotePointsNew[m].rank  = rrank;
7061         }
7062         for (r = 0; r < 3; ++r, ++m) {
7063           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7064           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7065           remotePointsNew[m].rank  = rrank;
7066         }
7067       } else if ((p >= cStart) && (p < cMax)) {
7068         /* Old hybrid cells add new cells and hybrid face */
7069         for (r = 0; r < 2; ++r, ++m) {
7070           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7071           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7072           remotePointsNew[m].rank  = rrank;
7073         }
7074         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7075         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]);
7076         remotePointsNew[m].rank  = rrank;
7077         ++m;
7078       }
7079       break;
7080     default:
7081       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7082     }
7083   }
7084   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7085   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7086   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7087   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7088   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7089   PetscFunctionReturn(0);
7090 }
7091 
7092 #undef __FUNCT__
7093 #define __FUNCT__ "CellRefinerCreateLabels"
7094 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7095 {
7096   PetscInt       numLabels, l;
7097   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7098   PetscErrorCode ierr;
7099 
7100   PetscFunctionBegin;
7101   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7102   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7103   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7104   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7105   cStartNew = 0;
7106   vStartNew = depthSize[2];
7107   fStartNew = depthSize[2] + depthSize[0];
7108   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7109   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7110   switch (refiner) {
7111   case 3:
7112     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7113     cMax = PetscMin(cEnd, cMax);
7114     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7115     fMax = PetscMin(fEnd, fMax);
7116   }
7117   for (l = 0; l < numLabels; ++l) {
7118     DMLabel         label, labelNew;
7119     const char     *lname;
7120     PetscBool       isDepth;
7121     IS              valueIS;
7122     const PetscInt *values;
7123     PetscInt        numValues, val;
7124 
7125     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7126     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7127     if (isDepth) continue;
7128     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7129     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7130     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7131     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7132     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7133     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7134     for (val = 0; val < numValues; ++val) {
7135       IS              pointIS;
7136       const PetscInt *points;
7137       PetscInt        numPoints, n;
7138 
7139       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7140       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7141       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7142       for (n = 0; n < numPoints; ++n) {
7143         const PetscInt p = points[n];
7144         switch (refiner) {
7145         case 1:
7146           /* Simplicial 2D */
7147           if ((p >= vStart) && (p < vEnd)) {
7148             /* Old vertices stay the same */
7149             newp = vStartNew + (p - vStart);
7150             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7151           } else if ((p >= fStart) && (p < fEnd)) {
7152             /* Old faces add new faces and vertex */
7153             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7154             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7155             for (r = 0; r < 2; ++r) {
7156               newp = fStartNew + (p - fStart)*2 + r;
7157               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7158             }
7159           } else if ((p >= cStart) && (p < cEnd)) {
7160             /* Old cells add new cells and interior faces */
7161             for (r = 0; r < 4; ++r) {
7162               newp = cStartNew + (p - cStart)*4 + r;
7163               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7164             }
7165             for (r = 0; r < 3; ++r) {
7166               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7167               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7168             }
7169           }
7170           break;
7171         case 2:
7172           /* Hex 2D */
7173           if ((p >= vStart) && (p < vEnd)) {
7174             /* Old vertices stay the same */
7175             newp = vStartNew + (p - vStart);
7176             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7177           } else if ((p >= fStart) && (p < fEnd)) {
7178             /* Old faces add new faces and vertex */
7179             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7180             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7181             for (r = 0; r < 2; ++r) {
7182               newp = fStartNew + (p - fStart)*2 + r;
7183               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7184             }
7185           } else if ((p >= cStart) && (p < cEnd)) {
7186             /* Old cells add new cells and interior faces and vertex */
7187             for (r = 0; r < 4; ++r) {
7188               newp = cStartNew + (p - cStart)*4 + r;
7189               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7190             }
7191             for (r = 0; r < 4; ++r) {
7192               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7193               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7194             }
7195             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7196             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7197           }
7198           break;
7199         case 3:
7200           /* Hybrid simplicial 2D */
7201           if ((p >= vStart) && (p < vEnd)) {
7202             /* Old vertices stay the same */
7203             newp = vStartNew + (p - vStart);
7204             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7205           } else if ((p >= fStart) && (p < fMax)) {
7206             /* Old interior faces add new faces and vertex */
7207             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7208             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7209             for (r = 0; r < 2; ++r) {
7210               newp = fStartNew + (p - fStart)*2 + r;
7211               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7212             }
7213           } else if ((p >= fMax) && (p < fEnd)) {
7214             /* Old hybrid faces stay the same */
7215             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7216             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7217           } else if ((p >= cStart) && (p < cMax)) {
7218             /* Old interior cells add new cells and interior faces */
7219             for (r = 0; r < 4; ++r) {
7220               newp = cStartNew + (p - cStart)*4 + r;
7221               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7222             }
7223             for (r = 0; r < 3; ++r) {
7224               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7225               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7226             }
7227           } else if ((p >= cMax) && (p < cEnd)) {
7228             /* Old hybrid cells add new cells and hybrid face */
7229             for (r = 0; r < 2; ++r) {
7230               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7231               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7232             }
7233             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7234             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7235           }
7236           break;
7237         default:
7238           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7239         }
7240       }
7241       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7242       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7243     }
7244     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7245     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7246     if (0) {
7247       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7248       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7249       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7250     }
7251   }
7252   PetscFunctionReturn(0);
7253 }
7254 
7255 #undef __FUNCT__
7256 #define __FUNCT__ "DMPlexRefine_Uniform"
7257 /* This will only work for interpolated meshes */
7258 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7259 {
7260   DM              rdm;
7261   PetscInt       *depthSize;
7262   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
7263   PetscErrorCode  ierr;
7264 
7265   PetscFunctionBegin;
7266   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7267   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7268   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7269   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7270   /* Calculate number of new points of each depth */
7271   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7272   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7273   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7274   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7275   /* Step 1: Set chart */
7276   for (d = 0; d <= depth; ++d) {
7277     pEnd += depthSize[d];
7278   }
7279   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7280   /* Step 2: Set cone/support sizes */
7281   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7282   /* Step 3: Setup refined DM */
7283   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7284   /* Step 4: Set cones and supports */
7285   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7286   /* Step 5: Stratify */
7287   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7288   /* Step 6: Set coordinates for vertices */
7289   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7290   /* Step 7: Create pointSF */
7291   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7292   /* Step 8: Create labels */
7293   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7294   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7295 
7296   *dmRefined = rdm;
7297 #if 0
7298   DM_Plex *mesh = (DM_Plex *) dm->data;
7299   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7300   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7301 
7302   PetscFunctionBegin;
7303   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7304   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7305   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7306   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7307   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7308 
7309   /* Count number of new cells which are normal and extra */
7310   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7311   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7312   for (c = cStart; c < cEnd2; ++c) {
7313     PetscInt n;
7314     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7315     newNumCellsNormal += n;
7316   }
7317   for (c = cEnd2; c < cEnd; ++c) {
7318     PetscInt n;
7319     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7320     newNumCellsExtra += n;
7321   }
7322   newNumCells = newNumCellsNormal + newNumCellsExtra;
7323   /* Count number of new vertices which are normal and extra */
7324   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7325   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7326   for (c = cStart; c < cEnd; ++c) {
7327     PetscInt *closure = PETSC_NULL;
7328     PetscInt  closureSize, numCorners = 0, p;
7329 
7330     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7331     for (p = 0; p < closureSize*2; p += 2) {
7332       const PetscInt point = closure[p];
7333       if ((point >= vStart) && (point < vEnd)) {
7334         closure[numCorners++] = point;
7335       }
7336     }
7337     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7338     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7339   }
7340   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7341   for (c = cEnd2; c < cEnd; ++c) {
7342     PetscInt *closure = PETSC_NULL;
7343     PetscInt  closureSize, numCorners = 0, p;
7344 
7345     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7346     for (p = 0; p < closureSize*2; p += 2) {
7347       const PetscInt point = closure[p];
7348       if ((point >= vStart) && (point < vEnd)) {
7349         closure[numCorners++] = point;
7350       }
7351     }
7352     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7353     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7354   } /* for */
7355   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7356   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
7357 
7358 #if 1
7359   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
7360   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
7361   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7362   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7363   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7364   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7365   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7366   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7367   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7368   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7369   ierr = PetscSynchronizedFlush(comm);
7370 #endif
7371 
7372   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7373   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7374   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7375   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7376   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7377   /* Set cone and support sizes for new normal cells */
7378   PetscInt newCell = 0;
7379   for (c = cStart; c < cEnd2; ++c) {
7380     PetscInt coneSize, n, i;
7381 
7382     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7383     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7384     for (i = 0; i < n; ++i, ++newCell) {
7385       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7386     }
7387 
7388     PetscInt *closure = PETSC_NULL;
7389     PetscInt  closureSize, numCorners = 0, p;
7390 
7391     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7392     for (p = 0; p < closureSize*2; p += 2) {
7393       const PetscInt point = closure[p];
7394       if ((point >= vStart) && (point < vEnd)) {
7395         closure[numCorners++] = point;
7396       }
7397     }
7398     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7399     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7400   }
7401 
7402   /* Reset current new cell value and loop over censored cells. */
7403   curNewCell = _orderNewMesh->cellsCensored().min();
7404   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7405   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7406     /* Set new cone and support sizes */
7407     cV.clear();
7408     sieve->cone(*c_iter, cV);
7409     const point_type* cone = cV.getPoints();
7410     const int coneSize = cV.getSize();
7411 
7412     const point_type* newCells;
7413     int numNewCells = 0;
7414     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7415 
7416     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7417       newSieve->setConeSize(curNewCell, coneSize);
7418       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7419         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7420       } /* for */
7421     } /* for */
7422   } /* for */
7423   newSieve->allocate();
7424 
7425   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7426 
7427   /* Create refined cells in new sieve. */
7428   curNewCell = _orderNewMesh->cellsNormal().min();
7429   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7430   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7431     cV.clear();
7432     sieve->cone(*c_iter, cV);
7433     const point_type *cone = cV.getPoints();
7434     const int coneSize = cV.getSize();
7435 
7436     const point_type* newCells;
7437     int numNewCells = 0;
7438     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7439 
7440     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7441       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7442     } /* for */
7443   } /* for */
7444   curNewCell = _orderNewMesh->cellsCensored().min();
7445   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7446   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7447     cV.clear();
7448     sieve->cone(*c_iter, cV);
7449     const point_type *cone = cV.getPoints();
7450     const int coneSize = cV.getSize();
7451 
7452     const point_type* newCells;
7453     int numNewCells = 0;
7454     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7455 
7456     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7457       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7458     } /* for */
7459   } /* for */
7460   newSieve->symmetrize();
7461 
7462   /* Set coordinates in refined mesh. */
7463   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7464   assert(!coordinates.isNull());
7465   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7466   assert(!newCoordinates.isNull());
7467 
7468   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7469   assert(vertices->size() > 0);
7470   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7471   assert(spaceDim > 0);
7472   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7473 
7474   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7475   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7476     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7477   } /* for */
7478   newCoordinates->allocatePoint();
7479 
7480   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7481   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7482     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7483     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7484   } /* for */
7485   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7486   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7487     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7488     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7489   } /* for */
7490 
7491   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7492 
7493   /* Create sensored depth */
7494   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7495   assert(!censoredLabel.isNull());
7496 
7497   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7498 
7499   newSieve->roots(depthVisitor);
7500   while (depthVisitor.isModified()) {
7501     /* FIX: Avoid the copy here somehow by fixing the traversal */
7502     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7503 
7504     depthVisitor.clear();
7505     newSieve->support(modifiedPoints, depthVisitor);
7506   } /* while */
7507   /* Stratify refined mesh */
7508   /* Calculate new point SF */
7509   _calcNewOverlap(newMesh, mesh, refiner);
7510   /* Calculate new labels */
7511   _createLabels(newMesh, mesh, refiner);
7512 #endif
7513   PetscFunctionReturn(0);
7514 }
7515 
7516 #undef __FUNCT__
7517 #define __FUNCT__ "DMPlexSetRefinementUniform"
7518 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7519 {
7520   DM_Plex *mesh = (DM_Plex *) dm->data;
7521 
7522   PetscFunctionBegin;
7523   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7524   mesh->refinementUniform = refinementUniform;
7525   PetscFunctionReturn(0);
7526 }
7527 
7528 #undef __FUNCT__
7529 #define __FUNCT__ "DMPlexGetRefinementUniform"
7530 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7531 {
7532   DM_Plex *mesh = (DM_Plex *) dm->data;
7533 
7534   PetscFunctionBegin;
7535   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7536   PetscValidPointer(refinementUniform,  2);
7537   *refinementUniform = mesh->refinementUniform;
7538   PetscFunctionReturn(0);
7539 }
7540 
7541 #undef __FUNCT__
7542 #define __FUNCT__ "DMPlexSetRefinementLimit"
7543 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7544 {
7545   DM_Plex *mesh = (DM_Plex *) dm->data;
7546 
7547   PetscFunctionBegin;
7548   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7549   mesh->refinementLimit = refinementLimit;
7550   PetscFunctionReturn(0);
7551 }
7552 
7553 #undef __FUNCT__
7554 #define __FUNCT__ "DMPlexGetRefinementLimit"
7555 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7556 {
7557   DM_Plex *mesh = (DM_Plex *) dm->data;
7558 
7559   PetscFunctionBegin;
7560   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7561   PetscValidPointer(refinementLimit,  2);
7562   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7563   *refinementLimit = mesh->refinementLimit;
7564   PetscFunctionReturn(0);
7565 }
7566 
7567 #undef __FUNCT__
7568 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7569 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7570 {
7571   PetscInt       dim, cStart, coneSize, cMax;
7572   PetscErrorCode ierr;
7573 
7574   PetscFunctionBegin;
7575   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7576   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7577   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7578   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7579   switch (dim) {
7580   case 2:
7581     switch (coneSize) {
7582     case 3:
7583       if (cMax >= 0) {
7584         *cellRefiner = 3; /* Hybrid */
7585       } else {
7586         *cellRefiner = 1; /* Triangular */
7587       }
7588       break;
7589     case 4:
7590       if (cMax >= 0) {
7591         *cellRefiner = 4; /* Hybrid */
7592       } else {
7593         *cellRefiner = 2; /* Quadrilateral */
7594       }
7595       break;
7596     default:
7597       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7598     }
7599     break;
7600   default:
7601     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7602   }
7603   PetscFunctionReturn(0);
7604 }
7605 
7606 #undef __FUNCT__
7607 #define __FUNCT__ "DMRefine_Plex"
7608 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7609 {
7610   PetscReal      refinementLimit;
7611   PetscInt       dim, cStart, cEnd;
7612   char           genname[1024], *name = PETSC_NULL;
7613   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7614   PetscErrorCode ierr;
7615 
7616   PetscFunctionBegin;
7617   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7618   if (isUniform) {
7619     CellRefiner cellRefiner;
7620 
7621     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7622     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7623     PetscFunctionReturn(0);
7624   }
7625   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7626   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7627   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7628   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7629   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7630   if (flg) {name = genname;}
7631   if (name) {
7632     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7633     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7634     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7635   }
7636   switch (dim) {
7637   case 2:
7638     if (!name || isTriangle) {
7639 #if defined(PETSC_HAVE_TRIANGLE)
7640       double  *maxVolumes;
7641       PetscInt c;
7642 
7643       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7644       for (c = 0; c < cEnd-cStart; ++c) {
7645         maxVolumes[c] = refinementLimit;
7646       }
7647       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7648 #else
7649       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7650 #endif
7651     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7652     break;
7653   case 3:
7654     if (!name || isCTetgen) {
7655 #if defined(PETSC_HAVE_CTETGEN)
7656       PetscReal *maxVolumes;
7657       PetscInt   c;
7658 
7659       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7660       for (c = 0; c < cEnd-cStart; ++c) {
7661         maxVolumes[c] = refinementLimit;
7662       }
7663       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7664 #else
7665       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7666 #endif
7667     } else if (isTetgen) {
7668 #if defined(PETSC_HAVE_TETGEN)
7669       double  *maxVolumes;
7670       PetscInt c;
7671 
7672       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7673       for (c = 0; c < cEnd-cStart; ++c) {
7674         maxVolumes[c] = refinementLimit;
7675       }
7676       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7677 #else
7678       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7679 #endif
7680     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7681     break;
7682   default:
7683     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7684   }
7685   PetscFunctionReturn(0);
7686 }
7687 
7688 #undef __FUNCT__
7689 #define __FUNCT__ "DMPlexGetDepth"
7690 /*@
7691   DMPlexGetDepth - get the number of strata
7692 
7693   Not Collective
7694 
7695   Input Parameters:
7696 . dm           - The DMPlex object
7697 
7698   Output Parameters:
7699 . depth - number of strata
7700 
7701   Level: developer
7702 
7703   Notes:
7704   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7705 
7706 .keywords: mesh, points
7707 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7708 @*/
7709 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7710 {
7711   PetscInt       d;
7712   PetscErrorCode ierr;
7713 
7714   PetscFunctionBegin;
7715   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7716   PetscValidPointer(depth, 2);
7717   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7718   *depth = d-1;
7719   PetscFunctionReturn(0);
7720 }
7721 
7722 #undef __FUNCT__
7723 #define __FUNCT__ "DMPlexGetDepthStratum"
7724 /*@
7725   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7726 
7727   Not Collective
7728 
7729   Input Parameters:
7730 + dm           - The DMPlex object
7731 - stratumValue - The requested depth
7732 
7733   Output Parameters:
7734 + start - The first point at this depth
7735 - end   - One beyond the last point at this depth
7736 
7737   Level: developer
7738 
7739 .keywords: mesh, points
7740 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7741 @*/
7742 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7743 {
7744   DM_Plex    *mesh = (DM_Plex *) dm->data;
7745   DMLabel        next = mesh->labels;
7746   PetscBool      flg  = PETSC_FALSE;
7747   PetscInt       depth;
7748   PetscErrorCode ierr;
7749 
7750   PetscFunctionBegin;
7751   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7752   if (stratumValue < 0) {
7753     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7754     PetscFunctionReturn(0);
7755   } else {
7756     PetscInt pStart, pEnd;
7757 
7758     if (start) {*start = 0;}
7759     if (end)   {*end   = 0;}
7760     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7761     if (pStart == pEnd) {PetscFunctionReturn(0);}
7762   }
7763   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7764   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7765   /* We should have a generic GetLabel() and a Label class */
7766   while (next) {
7767     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7768     if (flg) break;
7769     next = next->next;
7770   }
7771   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7772   depth = stratumValue;
7773   if ((depth < 0) || (depth >= next->numStrata)) {
7774     if (start) {*start = 0;}
7775     if (end)   {*end   = 0;}
7776   } else {
7777     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7778     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7779   }
7780   PetscFunctionReturn(0);
7781 }
7782 
7783 #undef __FUNCT__
7784 #define __FUNCT__ "DMPlexGetHeightStratum"
7785 /*@
7786   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7787 
7788   Not Collective
7789 
7790   Input Parameters:
7791 + dm           - The DMPlex object
7792 - stratumValue - The requested height
7793 
7794   Output Parameters:
7795 + start - The first point at this height
7796 - end   - One beyond the last point at this height
7797 
7798   Level: developer
7799 
7800 .keywords: mesh, points
7801 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7802 @*/
7803 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7804 {
7805   DM_Plex        *mesh = (DM_Plex *) dm->data;
7806   DMLabel        next = mesh->labels;
7807   PetscBool      flg  = PETSC_FALSE;
7808   PetscInt       depth;
7809   PetscErrorCode ierr;
7810 
7811   PetscFunctionBegin;
7812   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7813   if (stratumValue < 0) {
7814     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7815   } else {
7816     PetscInt pStart, pEnd;
7817 
7818     if (start) {*start = 0;}
7819     if (end)   {*end   = 0;}
7820     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7821     if (pStart == pEnd) {PetscFunctionReturn(0);}
7822   }
7823   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7824   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7825   /* We should have a generic GetLabel() and a Label class */
7826   while (next) {
7827     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7828     if (flg) break;
7829     next = next->next;
7830   }
7831   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7832   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7833   if ((depth < 0) || (depth >= next->numStrata)) {
7834     if (start) {*start = 0;}
7835     if (end)   {*end   = 0;}
7836   } else {
7837     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7838     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7839   }
7840   PetscFunctionReturn(0);
7841 }
7842 
7843 #undef __FUNCT__
7844 #define __FUNCT__ "DMPlexCreateSectionInitial"
7845 /* Set the number of dof on each point and separate by fields */
7846 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7847 {
7848   PetscInt      *numDofTot;
7849   PetscInt       pStart = 0, pEnd = 0;
7850   PetscInt       p, d, f;
7851   PetscErrorCode ierr;
7852 
7853   PetscFunctionBegin;
7854   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7855   for (d = 0; d <= dim; ++d) {
7856     numDofTot[d] = 0;
7857     for (f = 0; f < numFields; ++f) {
7858       numDofTot[d] += numDof[f*(dim+1)+d];
7859     }
7860   }
7861   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7862   if (numFields > 0) {
7863     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7864     if (numComp) {
7865       for (f = 0; f < numFields; ++f) {
7866         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7867       }
7868     }
7869   }
7870   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7871   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7872   for (d = 0; d <= dim; ++d) {
7873     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7874     for (p = pStart; p < pEnd; ++p) {
7875       for (f = 0; f < numFields; ++f) {
7876         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7877       }
7878       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7879     }
7880   }
7881   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7882   PetscFunctionReturn(0);
7883 }
7884 
7885 #undef __FUNCT__
7886 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7887 /* Set the number of dof on each point and separate by fields
7888    If constDof is PETSC_DETERMINE, constrain every dof on the point
7889 */
7890 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7891 {
7892   PetscInt       numFields;
7893   PetscInt       bc;
7894   PetscErrorCode ierr;
7895 
7896   PetscFunctionBegin;
7897   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7898   for (bc = 0; bc < numBC; ++bc) {
7899     PetscInt        field = 0;
7900     const PetscInt *idx;
7901     PetscInt        n, i;
7902 
7903     if (numFields) {field = bcField[bc];}
7904     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7905     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7906     for (i = 0; i < n; ++i) {
7907       const PetscInt p = idx[i];
7908       PetscInt       numConst = constDof;
7909 
7910       /* Constrain every dof on the point */
7911       if (numConst < 0) {
7912         if (numFields) {
7913           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7914         } else {
7915           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7916         }
7917       }
7918       if (numFields) {
7919         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7920       }
7921       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7922     }
7923     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7924   }
7925   PetscFunctionReturn(0);
7926 }
7927 
7928 #undef __FUNCT__
7929 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7930 /* Set the constrained indices on each point and separate by fields */
7931 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7932 {
7933   PetscInt      *maxConstraints;
7934   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7935   PetscErrorCode ierr;
7936 
7937   PetscFunctionBegin;
7938   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7939   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7940   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7941   for (f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
7942   for (p = pStart; p < pEnd; ++p) {
7943     PetscInt cdof;
7944 
7945     if (numFields) {
7946       for (f = 0; f < numFields; ++f) {
7947         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7948         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7949       }
7950     } else {
7951       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7952       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7953     }
7954   }
7955   for (f = 0; f < numFields; ++f) {
7956     maxConstraints[numFields] += maxConstraints[f];
7957   }
7958   if (maxConstraints[numFields]) {
7959     PetscInt *indices;
7960 
7961     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7962     for (p = pStart; p < pEnd; ++p) {
7963       PetscInt cdof, d;
7964 
7965       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7966       if (cdof) {
7967         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7968         if (numFields) {
7969           PetscInt numConst = 0, foff = 0;
7970 
7971           for (f = 0; f < numFields; ++f) {
7972             PetscInt cfdof, fdof;
7973 
7974             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7975             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7976             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7977             for (d = 0; d < cfdof; ++d) {
7978               indices[numConst+d] = d;
7979             }
7980             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7981             for (d = 0; d < cfdof; ++d) {
7982               indices[numConst+d] += foff;
7983             }
7984             numConst += cfdof;
7985             foff     += fdof;
7986           }
7987           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7988         } else {
7989           for (d = 0; d < cdof; ++d) {
7990             indices[d] = d;
7991           }
7992         }
7993         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7994       }
7995     }
7996     ierr = PetscFree(indices);CHKERRQ(ierr);
7997   }
7998   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7999   PetscFunctionReturn(0);
8000 }
8001 
8002 #undef __FUNCT__
8003 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
8004 /* Set the constrained field indices on each point */
8005 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
8006 {
8007   const PetscInt *points, *indices;
8008   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
8009   PetscErrorCode  ierr;
8010 
8011   PetscFunctionBegin;
8012   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8013   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8014 
8015   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8016   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8017   if (!constraintIndices) {
8018     PetscInt *idx, i;
8019 
8020     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8021     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8022     for (i = 0; i < maxDof; ++i) {idx[i] = i;}
8023     for (p = 0; p < numPoints; ++p) {
8024       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8025     }
8026     ierr = PetscFree(idx);CHKERRQ(ierr);
8027   } else {
8028     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8029     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8030     for (p = 0; p < numPoints; ++p) {
8031       PetscInt fcdof;
8032 
8033       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8034       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);
8035       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8036     }
8037     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8038   }
8039   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8040   PetscFunctionReturn(0);
8041 }
8042 
8043 #undef __FUNCT__
8044 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8045 /* Set the constrained indices on each point and separate by fields */
8046 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8047 {
8048   PetscInt      *indices;
8049   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8050   PetscErrorCode ierr;
8051 
8052   PetscFunctionBegin;
8053   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8054   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8055   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8056   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8057   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8058   for (p = pStart; p < pEnd; ++p) {
8059     PetscInt cdof, d;
8060 
8061     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8062     if (cdof) {
8063       PetscInt numConst = 0, foff = 0;
8064 
8065       for (f = 0; f < numFields; ++f) {
8066         const PetscInt *fcind;
8067         PetscInt        fdof, fcdof;
8068 
8069         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8070         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8071         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8072         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8073         for (d = 0; d < fcdof; ++d) {
8074           indices[numConst+d] = fcind[d]+foff;
8075         }
8076         foff     += fdof;
8077         numConst += fcdof;
8078       }
8079       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8080       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8081     }
8082   }
8083   ierr = PetscFree(indices);CHKERRQ(ierr);
8084   PetscFunctionReturn(0);
8085 }
8086 
8087 #undef __FUNCT__
8088 #define __FUNCT__ "DMPlexCreateSection"
8089 /*@C
8090   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8091 
8092   Not Collective
8093 
8094   Input Parameters:
8095 + dm        - The DMPlex object
8096 . dim       - The spatial dimension of the problem
8097 . numFields - The number of fields in the problem
8098 . numComp   - An array of size numFields that holds the number of components for each field
8099 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8100 . numBC     - The number of boundary conditions
8101 . bcField   - An array of size numBC giving the field number for each boundry condition
8102 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8103 
8104   Output Parameter:
8105 . section - The PetscSection object
8106 
8107   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
8108   nubmer of dof for field 0 on each edge.
8109 
8110   Level: developer
8111 
8112 .keywords: mesh, elements
8113 .seealso: DMPlexCreate(), PetscSectionCreate()
8114 @*/
8115 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8116 {
8117   PetscErrorCode ierr;
8118 
8119   PetscFunctionBegin;
8120   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8121   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8122   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8123   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8124   {
8125     PetscBool view = PETSC_FALSE;
8126 
8127     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8128     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8129   }
8130   PetscFunctionReturn(0);
8131 }
8132 
8133 #undef __FUNCT__
8134 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8135 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8136 {
8137   PetscSection   section;
8138   PetscErrorCode ierr;
8139 
8140   PetscFunctionBegin;
8141   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8142   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8143   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8144   PetscFunctionReturn(0);
8145 }
8146 
8147 #undef __FUNCT__
8148 #define __FUNCT__ "DMPlexGetCoordinateSection"
8149 /*@
8150   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8151 
8152   Not Collective
8153 
8154   Input Parameter:
8155 . dm - The DMPlex object
8156 
8157   Output Parameter:
8158 . section - The PetscSection object
8159 
8160   Level: intermediate
8161 
8162 .keywords: mesh, coordinates
8163 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8164 @*/
8165 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8166 {
8167   DM             cdm;
8168   PetscErrorCode ierr;
8169 
8170   PetscFunctionBegin;
8171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8172   PetscValidPointer(section, 2);
8173   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8174   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8175   PetscFunctionReturn(0);
8176 }
8177 
8178 #undef __FUNCT__
8179 #define __FUNCT__ "DMPlexSetCoordinateSection"
8180 /*@
8181   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8182 
8183   Not Collective
8184 
8185   Input Parameters:
8186 + dm      - The DMPlex object
8187 - section - The PetscSection object
8188 
8189   Level: intermediate
8190 
8191 .keywords: mesh, coordinates
8192 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8193 @*/
8194 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8195 {
8196   DM             cdm;
8197   PetscErrorCode ierr;
8198 
8199   PetscFunctionBegin;
8200   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8201   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8202   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8203   PetscFunctionReturn(0);
8204 }
8205 
8206 #undef __FUNCT__
8207 #define __FUNCT__ "DMPlexGetConeSection"
8208 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8209 {
8210   DM_Plex *mesh = (DM_Plex *) dm->data;
8211 
8212   PetscFunctionBegin;
8213   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8214   if (section) *section = mesh->coneSection;
8215   PetscFunctionReturn(0);
8216 }
8217 
8218 #undef __FUNCT__
8219 #define __FUNCT__ "DMPlexGetCones"
8220 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8221 {
8222   DM_Plex *mesh = (DM_Plex *) dm->data;
8223 
8224   PetscFunctionBegin;
8225   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8226   if (cones) *cones = mesh->cones;
8227   PetscFunctionReturn(0);
8228 }
8229 
8230 #undef __FUNCT__
8231 #define __FUNCT__ "DMPlexGetConeOrientations"
8232 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8233 {
8234   DM_Plex *mesh = (DM_Plex *) dm->data;
8235 
8236   PetscFunctionBegin;
8237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8238   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8239   PetscFunctionReturn(0);
8240 }
8241 
8242 #undef __FUNCT__
8243 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8244 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8245 {
8246   const PetscInt embedDim = 2;
8247   PetscReal      x = PetscRealPart(point[0]);
8248   PetscReal      y = PetscRealPart(point[1]);
8249   PetscReal      v0[2], J[4], invJ[4], detJ;
8250   PetscReal      xi, eta;
8251   PetscErrorCode ierr;
8252 
8253   PetscFunctionBegin;
8254   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8255   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8256   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8257 
8258   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
8259     *cell = c;
8260   } else {
8261     *cell = -1;
8262   }
8263   PetscFunctionReturn(0);
8264 }
8265 
8266 #undef __FUNCT__
8267 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8268 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8269 {
8270   PetscSection       coordSection;
8271   Vec                coordsLocal;
8272   const PetscScalar *coords;
8273   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8274   PetscReal          x         = PetscRealPart(point[0]);
8275   PetscReal          y         = PetscRealPart(point[1]);
8276   PetscInt           crossings = 0, f;
8277   PetscErrorCode     ierr;
8278 
8279   PetscFunctionBegin;
8280   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8281   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8282   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8283   for (f = 0; f < 4; ++f) {
8284     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8285     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8286     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8287     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8288     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8289     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8290     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8291     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8292     if ((cond1 || cond2)  && above) ++crossings;
8293   }
8294   if (crossings % 2) {
8295     *cell = c;
8296   } else {
8297     *cell = -1;
8298   }
8299   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8300   PetscFunctionReturn(0);
8301 }
8302 
8303 #undef __FUNCT__
8304 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8305 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8306 {
8307   const PetscInt embedDim = 3;
8308   PetscReal      v0[3], J[9], invJ[9], detJ;
8309   PetscReal      x = PetscRealPart(point[0]);
8310   PetscReal      y = PetscRealPart(point[1]);
8311   PetscReal      z = PetscRealPart(point[2]);
8312   PetscReal      xi, eta, zeta;
8313   PetscErrorCode ierr;
8314 
8315   PetscFunctionBegin;
8316   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8317   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8318   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8319   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8320 
8321   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
8322     *cell = c;
8323   } else {
8324     *cell = -1;
8325   }
8326   PetscFunctionReturn(0);
8327 }
8328 
8329 #undef __FUNCT__
8330 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8331 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8332 {
8333   PetscSection       coordSection;
8334   Vec                coordsLocal;
8335   const PetscScalar *coords;
8336   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8337                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8338   PetscBool          found     = PETSC_TRUE;
8339   PetscInt           f;
8340   PetscErrorCode     ierr;
8341 
8342   PetscFunctionBegin;
8343   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8344   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8345   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8346   for (f = 0; f < 6; ++f) {
8347     /* Check the point is under plane */
8348     /*   Get face normal */
8349     PetscReal v_i[3]    = {PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]),
8350                            PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]),
8351                            PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2])};
8352     PetscReal v_j[3]    = {PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]),
8353                            PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]),
8354                            PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2])};
8355     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]};
8356     PetscReal pp[3]     = {PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]),
8357                            PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]),
8358                            PetscRealPart(coords[faces[f*4+0]*3+2] - point[2])};
8359     PetscReal dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8360     /* Check that projected point is in face (2D location problem) */
8361     if (dot < 0.0) {
8362       found = PETSC_FALSE;
8363       break;
8364     }
8365   }
8366   if (found) {
8367     *cell = c;
8368   } else {
8369     *cell = -1;
8370   }
8371   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8372   PetscFunctionReturn(0);
8373 }
8374 
8375 #undef __FUNCT__
8376 #define __FUNCT__ "DMLocatePoints_Plex"
8377 /*
8378  Need to implement using the guess
8379 */
8380 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8381 {
8382   PetscInt       cell = -1/*, guess = -1*/;
8383   PetscInt       bs, numPoints, p;
8384   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8385   PetscInt      *cells;
8386   PetscScalar   *a;
8387   PetscErrorCode ierr;
8388 
8389   PetscFunctionBegin;
8390   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8391   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8392   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8393   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8394   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8395   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8396   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8397   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);
8398   numPoints /= bs;
8399   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8400   for (p = 0; p < numPoints; ++p) {
8401     const PetscScalar *point = &a[p*bs];
8402 
8403     switch (dim) {
8404     case 2:
8405       for (c = cStart; c < cEnd; ++c) {
8406         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8407         switch (coneSize) {
8408         case 3:
8409           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8410           break;
8411         case 4:
8412           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8413           break;
8414         default:
8415           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8416         }
8417         if (cell >= 0) break;
8418       }
8419       break;
8420     case 3:
8421       for (c = cStart; c < cEnd; ++c) {
8422         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8423         switch (coneSize) {
8424         case 4:
8425           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8426           break;
8427         case 8:
8428           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8429           break;
8430         default:
8431           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8432         }
8433         if (cell >= 0) break;
8434       }
8435       break;
8436     default:
8437       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8438     }
8439     cells[p] = cell;
8440   }
8441   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8442   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8443   PetscFunctionReturn(0);
8444 }
8445 
8446 /******************************** FEM Support **********************************/
8447 
8448 #undef __FUNCT__
8449 #define __FUNCT__ "DMPlexVecGetClosure"
8450 /*@C
8451   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8452 
8453   Not collective
8454 
8455   Input Parameters:
8456 + dm - The DM
8457 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8458 . v - The local vector
8459 - point - The sieve point in the DM
8460 
8461   Output Parameters:
8462 + csize - The number of values in the closure, or PETSC_NULL
8463 - values - The array of values, which is a borrowed array and should not be freed
8464 
8465   Level: intermediate
8466 
8467 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8468 @*/
8469 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8470 {
8471   PetscScalar    *array, *vArray;
8472   PetscInt       *points = PETSC_NULL;
8473   PetscInt        offsets[32];
8474   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8475   PetscErrorCode  ierr;
8476 
8477   PetscFunctionBegin;
8478   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8479   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8480   if (!section) {
8481     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8482   }
8483   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8484   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8485   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8486   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8487   /* Compress out points not in the section */
8488   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8489   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8490     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8491       points[q*2]   = points[p];
8492       points[q*2+1] = points[p+1];
8493       ++q;
8494     }
8495   }
8496   numPoints = q;
8497   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8498     PetscInt dof, fdof;
8499 
8500     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8501     for (f = 0; f < numFields; ++f) {
8502       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8503       offsets[f+1] += fdof;
8504     }
8505     size += dof;
8506   }
8507   for (f = 1; f < numFields; ++f) {
8508     offsets[f+1] += offsets[f];
8509   }
8510   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8511   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8512   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8513   for (p = 0; p < numPoints*2; p += 2) {
8514     PetscInt     o = points[p+1];
8515     PetscInt     dof, off, d;
8516     PetscScalar *varr;
8517 
8518     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8519     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8520     varr = &vArray[off];
8521     if (numFields) {
8522       PetscInt fdof, foff, fcomp, f, c;
8523 
8524       for (f = 0, foff = 0; f < numFields; ++f) {
8525         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8526         if (o >= 0) {
8527           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8528             array[offsets[f]] = varr[foff+d];
8529           }
8530         } else {
8531           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8532           for (d = fdof/fcomp-1; d >= 0; --d) {
8533             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8534               array[offsets[f]] = varr[foff+d*fcomp+c];
8535             }
8536           }
8537         }
8538         foff += fdof;
8539       }
8540     } else {
8541       if (o >= 0) {
8542         for (d = 0; d < dof; ++d, ++offsets[0]) {
8543           array[offsets[0]] = varr[d];
8544         }
8545       } else {
8546         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8547           array[offsets[0]] = varr[d];
8548         }
8549       }
8550     }
8551   }
8552   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8553   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8554   if (csize) *csize = size;
8555   *values = array;
8556   PetscFunctionReturn(0);
8557 }
8558 
8559 #undef __FUNCT__
8560 #define __FUNCT__ "DMPlexVecRestoreClosure"
8561 /*@C
8562   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8563 
8564   Not collective
8565 
8566   Input Parameters:
8567 + dm - The DM
8568 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8569 . v - The local vector
8570 . point - The sieve point in the DM
8571 . csize - The number of values in the closure, or PETSC_NULL
8572 - values - The array of values, which is a borrowed array and should not be freed
8573 
8574   Level: intermediate
8575 
8576 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8577 @*/
8578 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8579 {
8580   PetscInt        size = 0;
8581   PetscErrorCode  ierr;
8582 
8583   PetscFunctionBegin;
8584   /* Should work without recalculating size */
8585   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8586   PetscFunctionReturn(0);
8587 }
8588 
8589 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8590 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8591 
8592 #undef __FUNCT__
8593 #define __FUNCT__ "updatePoint_private"
8594 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8595 {
8596   PetscInt        cdof;  /* The number of constraints on this point */
8597   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8598   PetscScalar    *a;
8599   PetscInt        off, cind = 0, k;
8600   PetscErrorCode  ierr;
8601 
8602   PetscFunctionBegin;
8603   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8604   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8605   a    = &array[off];
8606   if (!cdof || setBC) {
8607     if (orientation >= 0) {
8608       for (k = 0; k < dof; ++k) {
8609         fuse(&a[k], values[k]);
8610       }
8611     } else {
8612       for (k = 0; k < dof; ++k) {
8613         fuse(&a[k], values[dof-k-1]);
8614       }
8615     }
8616   } else {
8617     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8618     if (orientation >= 0) {
8619       for (k = 0; k < dof; ++k) {
8620         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8621         fuse(&a[k], values[k]);
8622       }
8623     } else {
8624       for (k = 0; k < dof; ++k) {
8625         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8626         fuse(&a[k], values[dof-k-1]);
8627       }
8628     }
8629   }
8630   PetscFunctionReturn(0);
8631 }
8632 
8633 #undef __FUNCT__
8634 #define __FUNCT__ "updatePointFields_private"
8635 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8636 {
8637   PetscScalar   *a;
8638   PetscInt       numFields, off, foff, f;
8639   PetscErrorCode ierr;
8640 
8641   PetscFunctionBegin;
8642   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8643   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8644   a    = &array[off];
8645   for (f = 0, foff = 0; f < numFields; ++f) {
8646     PetscInt        fdof, fcomp, fcdof;
8647     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8648     PetscInt        cind = 0, k, c;
8649 
8650     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8651     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8652     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8653     if (!fcdof || setBC) {
8654       if (orientation >= 0) {
8655         for (k = 0; k < fdof; ++k) {
8656           fuse(&a[foff+k], values[foffs[f]+k]);
8657         }
8658       } else {
8659         for (k = fdof/fcomp-1; k >= 0; --k) {
8660           for (c = 0; c < fcomp; ++c) {
8661             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8662           }
8663         }
8664       }
8665     } else {
8666       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8667       if (orientation >= 0) {
8668         for (k = 0; k < fdof; ++k) {
8669           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8670           fuse(&a[foff+k], values[foffs[f]+k]);
8671         }
8672       } else {
8673         for (k = fdof/fcomp-1; k >= 0; --k) {
8674           for (c = 0; c < fcomp; ++c) {
8675             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8676             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8677           }
8678         }
8679       }
8680     }
8681     foff     += fdof;
8682     foffs[f] += fdof;
8683   }
8684   PetscFunctionReturn(0);
8685 }
8686 
8687 #undef __FUNCT__
8688 #define __FUNCT__ "DMPlexVecSetClosure"
8689 /*@C
8690   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8691 
8692   Not collective
8693 
8694   Input Parameters:
8695 + dm - The DM
8696 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8697 . v - The local vector
8698 . point - The sieve point in the DM
8699 . values - The array of values, which is a borrowed array and should not be freed
8700 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8701 
8702   Level: intermediate
8703 
8704 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8705 @*/
8706 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8707 {
8708   PetscScalar    *array;
8709   PetscInt       *points = PETSC_NULL;
8710   PetscInt        offsets[32];
8711   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8712   PetscErrorCode  ierr;
8713 
8714   PetscFunctionBegin;
8715   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8716   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8717   if (!section) {
8718     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8719   }
8720   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8721   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8722   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8723   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8724   /* Compress out points not in the section */
8725   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8726   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8727     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8728       points[q*2]   = points[p];
8729       points[q*2+1] = points[p+1];
8730       ++q;
8731     }
8732   }
8733   numPoints = q;
8734   for (p = 0; p < numPoints*2; p += 2) {
8735     PetscInt fdof;
8736 
8737     for (f = 0; f < numFields; ++f) {
8738       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8739       offsets[f+1] += fdof;
8740     }
8741   }
8742   for (f = 1; f < numFields; ++f) {
8743     offsets[f+1] += offsets[f];
8744   }
8745   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8746   if (numFields) {
8747     switch (mode) {
8748     case INSERT_VALUES:
8749       for (p = 0; p < numPoints*2; p += 2) {
8750         PetscInt o = points[p+1];
8751         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8752       } break;
8753     case INSERT_ALL_VALUES:
8754       for (p = 0; p < numPoints*2; p += 2) {
8755         PetscInt o = points[p+1];
8756         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8757       } break;
8758     case ADD_VALUES:
8759       for (p = 0; p < numPoints*2; p += 2) {
8760         PetscInt o = points[p+1];
8761         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8762       } break;
8763     case ADD_ALL_VALUES:
8764       for (p = 0; p < numPoints*2; p += 2) {
8765         PetscInt o = points[p+1];
8766         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8767       } break;
8768     default:
8769       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8770     }
8771   } else {
8772     switch (mode) {
8773     case INSERT_VALUES:
8774       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8775         PetscInt o = points[p+1];
8776         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8777         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8778       } break;
8779     case INSERT_ALL_VALUES:
8780       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8781         PetscInt o = points[p+1];
8782         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8783         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8784       } break;
8785     case ADD_VALUES:
8786       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8787         PetscInt o = points[p+1];
8788         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8789         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8790       } break;
8791     case ADD_ALL_VALUES:
8792       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8793         PetscInt o = points[p+1];
8794         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8795         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8796       } break;
8797     default:
8798       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8799     }
8800   }
8801   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8802   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8803   PetscFunctionReturn(0);
8804 }
8805 
8806 #undef __FUNCT__
8807 #define __FUNCT__ "DMPlexPrintMatSetValues"
8808 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8809 {
8810   PetscMPIInt    rank;
8811   PetscInt       i, j;
8812   PetscErrorCode ierr;
8813 
8814   PetscFunctionBegin;
8815   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8816   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8817   for (i = 0; i < numIndices; i++) {
8818     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8819   }
8820   for (i = 0; i < numIndices; i++) {
8821     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8822     for (j = 0; j < numIndices; j++) {
8823 #if defined(PETSC_USE_COMPLEX)
8824       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8825 #else
8826       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8827 #endif
8828     }
8829     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8830   }
8831   PetscFunctionReturn(0);
8832 }
8833 
8834 #undef __FUNCT__
8835 #define __FUNCT__ "indicesPoint_private"
8836 /* . off - The global offset of this point */
8837 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8838 {
8839   PetscInt        cdof;  /* The number of constraints on this point */
8840   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8841   PetscInt        cind = 0, k;
8842   PetscErrorCode  ierr;
8843 
8844   PetscFunctionBegin;
8845   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8846   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8847   if (!cdof || setBC) {
8848     if (orientation >= 0) {
8849       for (k = 0; k < dof; ++k) {
8850         indices[k] = off+k;
8851       }
8852     } else {
8853       for (k = 0; k < dof; ++k) {
8854         indices[dof-k-1] = off+k;
8855       }
8856     }
8857   } else {
8858     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8859     if (orientation >= 0) {
8860       for (k = 0; k < dof; ++k) {
8861         if ((cind < cdof) && (k == cdofs[cind])) {
8862           /* Insert check for returning constrained indices */
8863           indices[k] = -(off+k+1);
8864           ++cind;
8865         } else {
8866           indices[k] = off+k-cind;
8867         }
8868       }
8869     } else {
8870       for (k = 0; k < dof; ++k) {
8871         if ((cind < cdof) && (k == cdofs[cind])) {
8872           /* Insert check for returning constrained indices */
8873           indices[dof-k-1] = -(off+k+1);
8874           ++cind;
8875         } else {
8876           indices[dof-k-1] = off+k-cind;
8877         }
8878       }
8879     }
8880   }
8881   PetscFunctionReturn(0);
8882 }
8883 
8884 #undef __FUNCT__
8885 #define __FUNCT__ "indicesPointFields_private"
8886 /* . off - The global offset of this point */
8887 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8888 {
8889   PetscInt       numFields, foff, f;
8890   PetscErrorCode ierr;
8891 
8892   PetscFunctionBegin;
8893   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8894   for (f = 0, foff = 0; f < numFields; ++f) {
8895     PetscInt        fdof, fcomp, cfdof;
8896     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8897     PetscInt        cind = 0, k, c;
8898 
8899     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8900     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8901     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8902     if (!cfdof || setBC) {
8903       if (orientation >= 0) {
8904         for (k = 0; k < fdof; ++k) {
8905           indices[foffs[f]+k] = off+foff+k;
8906         }
8907       } else {
8908         for (k = fdof/fcomp-1; k >= 0; --k) {
8909           for (c = 0; c < fcomp; ++c) {
8910             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8911           }
8912         }
8913       }
8914     } else {
8915       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8916       if (orientation >= 0) {
8917         for (k = 0; k < fdof; ++k) {
8918           if ((cind < cfdof) && (k == fcdofs[cind])) {
8919             indices[foffs[f]+k] = -(off+foff+k+1);
8920             ++cind;
8921           } else {
8922             indices[foffs[f]+k] = off+foff+k-cind;
8923           }
8924         }
8925       } else {
8926         for (k = fdof/fcomp-1; k >= 0; --k) {
8927           for (c = 0; c < fcomp; ++c) {
8928             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8929               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8930               ++cind;
8931             } else {
8932               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8933             }
8934           }
8935         }
8936       }
8937     }
8938     foff     += fdof - cfdof;
8939     foffs[f] += fdof;
8940   }
8941   PetscFunctionReturn(0);
8942 }
8943 
8944 #undef __FUNCT__
8945 #define __FUNCT__ "DMPlexMatSetClosure"
8946 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8947 {
8948   DM_Plex     *mesh   = (DM_Plex *) dm->data;
8949   PetscInt       *points = PETSC_NULL;
8950   PetscInt       *indices;
8951   PetscInt        offsets[32];
8952   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8953   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8954   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8955   PetscErrorCode  ierr;
8956 
8957   PetscFunctionBegin;
8958   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8959   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8960   if (useDefault) {
8961     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8962   }
8963   if (useGlobalDefault) {
8964     if (useDefault) {
8965       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8966     } else {
8967       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8968     }
8969   }
8970   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8971   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8972   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8973   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8974   /* Compress out points not in the section */
8975   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8976   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8977     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8978       points[q*2]   = points[p];
8979       points[q*2+1] = points[p+1];
8980       ++q;
8981     }
8982   }
8983   numPoints = q;
8984   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8985     PetscInt fdof;
8986 
8987     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8988     for (f = 0; f < numFields; ++f) {
8989       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8990       offsets[f+1] += fdof;
8991     }
8992     numIndices += dof;
8993   }
8994   for (f = 1; f < numFields; ++f) {
8995     offsets[f+1] += offsets[f];
8996   }
8997   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8998   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8999   if (numFields) {
9000     for (p = 0; p < numPoints*2; p += 2) {
9001       PetscInt o = points[p+1];
9002       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9003       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
9004     }
9005   } else {
9006     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
9007       PetscInt o = points[p+1];
9008       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9009       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
9010     }
9011   }
9012   if (useGlobalDefault && !useDefault) {
9013     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9014   }
9015   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
9016   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9017   if (ierr) {
9018     PetscMPIInt    rank;
9019     PetscErrorCode ierr2;
9020 
9021     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
9022     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9023     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9024     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9025     CHKERRQ(ierr);
9026   }
9027   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9028   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9029   PetscFunctionReturn(0);
9030 }
9031 
9032 #undef __FUNCT__
9033 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9034 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9035 {
9036   PetscSection       coordSection;
9037   Vec                coordinates;
9038   const PetscScalar *coords;
9039   const PetscInt     dim = 2;
9040   PetscInt           d, f;
9041   PetscErrorCode     ierr;
9042 
9043   PetscFunctionBegin;
9044   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9045   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9046   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9047   if (v0) {
9048     for (d = 0; d < dim; d++) {
9049       v0[d] = PetscRealPart(coords[d]);
9050     }
9051   }
9052   if (J) {
9053     for (d = 0; d < dim; d++) {
9054       for (f = 0; f < dim; f++) {
9055         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9056       }
9057     }
9058     *detJ = J[0]*J[3] - J[1]*J[2];
9059 #if 0
9060     if (detJ < 0.0) {
9061       const PetscReal xLength = mesh->periodicity[0];
9062 
9063       if (xLength != 0.0) {
9064         PetscReal v0x = coords[0*dim+0];
9065 
9066         if (v0x == 0.0) {
9067           v0x = v0[0] = xLength;
9068         }
9069         for (f = 0; f < dim; f++) {
9070           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9071 
9072           J[0*dim+f] = 0.5*(px - v0x);
9073         }
9074       }
9075       detJ = J[0]*J[3] - J[1]*J[2];
9076     }
9077 #endif
9078     PetscLogFlops(8.0 + 3.0);
9079   }
9080   if (invJ) {
9081     const PetscReal invDet = 1.0/(*detJ);
9082 
9083     invJ[0] =  invDet*J[3];
9084     invJ[1] = -invDet*J[1];
9085     invJ[2] = -invDet*J[2];
9086     invJ[3] =  invDet*J[0];
9087     PetscLogFlops(5.0);
9088   }
9089   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9090   PetscFunctionReturn(0);
9091 }
9092 
9093 #undef __FUNCT__
9094 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9095 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9096 {
9097   PetscSection       coordSection;
9098   Vec                coordinates;
9099   const PetscScalar *coords;
9100   const PetscInt     dim = 2;
9101   PetscInt           d, f;
9102   PetscErrorCode     ierr;
9103 
9104   PetscFunctionBegin;
9105   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9106   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9107   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9108   if (v0) {
9109     for (d = 0; d < dim; d++) {
9110       v0[d] = PetscRealPart(coords[d]);
9111     }
9112   }
9113   if (J) {
9114     for (d = 0; d < dim; d++) {
9115       for (f = 0; f < dim; f++) {
9116         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9117       }
9118     }
9119     *detJ = J[0]*J[3] - J[1]*J[2];
9120     PetscLogFlops(8.0 + 3.0);
9121   }
9122   if (invJ) {
9123     const PetscReal invDet = 1.0/(*detJ);
9124 
9125     invJ[0] =  invDet*J[3];
9126     invJ[1] = -invDet*J[1];
9127     invJ[2] = -invDet*J[2];
9128     invJ[3] =  invDet*J[0];
9129     PetscLogFlops(5.0);
9130   }
9131   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9132   PetscFunctionReturn(0);
9133 }
9134 
9135 #undef __FUNCT__
9136 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9137 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9138 {
9139   PetscSection       coordSection;
9140   Vec                coordinates;
9141   const PetscScalar *coords;
9142   const PetscInt     dim = 3;
9143   PetscInt           d, f;
9144   PetscErrorCode     ierr;
9145 
9146   PetscFunctionBegin;
9147   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9148   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9149   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9150   if (v0) {
9151     for (d = 0; d < dim; d++) {
9152       v0[d] = PetscRealPart(coords[d]);
9153     }
9154   }
9155   if (J) {
9156     for (d = 0; d < dim; d++) {
9157       for (f = 0; f < dim; f++) {
9158         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9159       }
9160     }
9161     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9162     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9163              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9164              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9165     PetscLogFlops(18.0 + 12.0);
9166   }
9167   if (invJ) {
9168     const PetscReal invDet = 1.0/(*detJ);
9169 
9170     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9171     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9172     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9173     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9174     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9175     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9176     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9177     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9178     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9179     PetscLogFlops(37.0);
9180   }
9181   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9182   PetscFunctionReturn(0);
9183 }
9184 
9185 #undef __FUNCT__
9186 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9187 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9188 {
9189   PetscSection       coordSection;
9190   Vec                coordinates;
9191   const PetscScalar *coords;
9192   const PetscInt     dim = 3;
9193   PetscInt           d;
9194   PetscErrorCode     ierr;
9195 
9196   PetscFunctionBegin;
9197   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9198   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9199   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9200   if (v0) {
9201     for (d = 0; d < dim; d++) {
9202       v0[d] = PetscRealPart(coords[d]);
9203     }
9204   }
9205   if (J) {
9206     for (d = 0; d < dim; d++) {
9207       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9208       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9209       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9210     }
9211     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9212              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9213              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9214     PetscLogFlops(18.0 + 12.0);
9215   }
9216   if (invJ) {
9217     const PetscReal invDet = -1.0/(*detJ);
9218 
9219     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9220     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9221     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9222     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9223     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9224     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9225     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9226     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9227     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9228     PetscLogFlops(37.0);
9229   }
9230   *detJ *= 8.0;
9231   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9232   PetscFunctionReturn(0);
9233 }
9234 
9235 #undef __FUNCT__
9236 #define __FUNCT__ "DMPlexComputeCellGeometry"
9237 /*@C
9238   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9239 
9240   Collective on DM
9241 
9242   Input Arguments:
9243 + dm   - the DM
9244 - cell - the cell
9245 
9246   Output Arguments:
9247 + v0   - the translation part of this affine transform
9248 . J    - the Jacobian of the transform to the reference element
9249 . invJ - the inverse of the Jacobian
9250 - detJ - the Jacobian determinant
9251 
9252   Level: advanced
9253 
9254 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9255 @*/
9256 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9257 {
9258   PetscInt       dim, coneSize;
9259   PetscErrorCode ierr;
9260 
9261   PetscFunctionBegin;
9262   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9263   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9264   switch (dim) {
9265   case 2:
9266     switch (coneSize) {
9267     case 3:
9268       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9269       break;
9270     case 4:
9271       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9272       break;
9273     default:
9274       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9275     }
9276     break;
9277   case 3:
9278     switch (coneSize) {
9279     case 4:
9280       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9281       break;
9282     case 8:
9283       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9284       break;
9285     default:
9286       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9287     }
9288     break;
9289   default:
9290     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9291   }
9292   PetscFunctionReturn(0);
9293 }
9294 
9295 #undef __FUNCT__
9296 #define __FUNCT__ "DMPlexGetFaceOrientation"
9297 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9298 {
9299   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9300   PetscBool      posOrient = PETSC_FALSE;
9301   const PetscInt debug     = 0;
9302   PetscInt       cellDim, faceSize, f;
9303   PetscErrorCode ierr;
9304 
9305   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9306   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9307 
9308   if (cellDim == numCorners-1) {
9309     /* Simplices */
9310     faceSize  = numCorners-1;
9311     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9312   } else if (cellDim == 1 && numCorners == 3) {
9313     /* Quadratic line */
9314     faceSize  = 1;
9315     posOrient = PETSC_TRUE;
9316   } else if (cellDim == 2 && numCorners == 4) {
9317     /* Quads */
9318     faceSize  = 2;
9319     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9320       posOrient = PETSC_TRUE;
9321     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9322       posOrient = PETSC_TRUE;
9323     } else {
9324       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9325         posOrient = PETSC_FALSE;
9326       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9327     }
9328   } else if (cellDim == 2 && numCorners == 6) {
9329     /* Quadratic triangle (I hate this) */
9330     /* Edges are determined by the first 2 vertices (corners of edges) */
9331     const PetscInt faceSizeTri = 3;
9332     PetscInt  sortedIndices[3], i, iFace;
9333     PetscBool found = PETSC_FALSE;
9334     PetscInt  faceVerticesTriSorted[9] = {
9335       0, 3,  4, /* bottom */
9336       1, 4,  5, /* right */
9337       2, 3,  5, /* left */
9338     };
9339     PetscInt  faceVerticesTri[9] = {
9340       0, 3,  4, /* bottom */
9341       1, 4,  5, /* right */
9342       2, 5,  3, /* left */
9343     };
9344 
9345     faceSize = faceSizeTri;
9346     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9347     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9348     for (iFace = 0; iFace < 3; ++iFace) {
9349       const PetscInt ii = iFace*faceSizeTri;
9350       PetscInt       fVertex, cVertex;
9351 
9352       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9353           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9354         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9355           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9356             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9357               faceVertices[fVertex] = origVertices[cVertex];
9358               break;
9359             }
9360           }
9361         }
9362         found = PETSC_TRUE;
9363         break;
9364       }
9365     }
9366     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9367     if (posOriented) {*posOriented = PETSC_TRUE;}
9368     PetscFunctionReturn(0);
9369   } else if (cellDim == 2 && numCorners == 9) {
9370     /* Quadratic quad (I hate this) */
9371     /* Edges are determined by the first 2 vertices (corners of edges) */
9372     const PetscInt faceSizeQuad = 3;
9373     PetscInt  sortedIndices[3], i, iFace;
9374     PetscBool found = PETSC_FALSE;
9375     PetscInt  faceVerticesQuadSorted[12] = {
9376       0, 1,  4, /* bottom */
9377       1, 2,  5, /* right */
9378       2, 3,  6, /* top */
9379       0, 3,  7, /* left */
9380     };
9381     PetscInt  faceVerticesQuad[12] = {
9382       0, 1,  4, /* bottom */
9383       1, 2,  5, /* right */
9384       2, 3,  6, /* top */
9385       3, 0,  7, /* left */
9386     };
9387 
9388     faceSize = faceSizeQuad;
9389     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9390     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9391     for (iFace = 0; iFace < 4; ++iFace) {
9392       const PetscInt ii = iFace*faceSizeQuad;
9393       PetscInt       fVertex, cVertex;
9394 
9395       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9396           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9397         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9398           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9399             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9400               faceVertices[fVertex] = origVertices[cVertex];
9401               break;
9402             }
9403           }
9404         }
9405         found = PETSC_TRUE;
9406         break;
9407       }
9408     }
9409     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9410     if (posOriented) {*posOriented = PETSC_TRUE;}
9411     PetscFunctionReturn(0);
9412   } else if (cellDim == 3 && numCorners == 8) {
9413     /* Hexes
9414        A hex is two oriented quads with the normal of the first
9415        pointing up at the second.
9416 
9417           7---6
9418          /|  /|
9419         4---5 |
9420         | 3-|-2
9421         |/  |/
9422         0---1
9423 
9424         Faces are determined by the first 4 vertices (corners of faces) */
9425     const PetscInt faceSizeHex = 4;
9426     PetscInt  sortedIndices[4], i, iFace;
9427     PetscBool found = PETSC_FALSE;
9428     PetscInt faceVerticesHexSorted[24] = {
9429       0, 1, 2, 3,  /* bottom */
9430       4, 5, 6, 7,  /* top */
9431       0, 1, 4, 5,  /* front */
9432       1, 2, 5, 6,  /* right */
9433       2, 3, 6, 7,  /* back */
9434       0, 3, 4, 7,  /* left */
9435     };
9436     PetscInt faceVerticesHex[24] = {
9437       3, 2, 1, 0,  /* bottom */
9438       4, 5, 6, 7,  /* top */
9439       0, 1, 5, 4,  /* front */
9440       1, 2, 6, 5,  /* right */
9441       2, 3, 7, 6,  /* back */
9442       3, 0, 4, 7,  /* left */
9443     };
9444 
9445     faceSize = faceSizeHex;
9446     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9447     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9448     for (iFace = 0; iFace < 6; ++iFace) {
9449       const PetscInt ii = iFace*faceSizeHex;
9450       PetscInt       fVertex, cVertex;
9451 
9452       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9453           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9454           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9455           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9456         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9457           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9458             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9459               faceVertices[fVertex] = origVertices[cVertex];
9460               break;
9461             }
9462           }
9463         }
9464         found = PETSC_TRUE;
9465         break;
9466       }
9467     }
9468     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9469     if (posOriented) {*posOriented = PETSC_TRUE;}
9470     PetscFunctionReturn(0);
9471   } else if (cellDim == 3 && numCorners == 10) {
9472     /* Quadratic tet */
9473     /* Faces are determined by the first 3 vertices (corners of faces) */
9474     const PetscInt faceSizeTet = 6;
9475     PetscInt  sortedIndices[6], i, iFace;
9476     PetscBool found = PETSC_FALSE;
9477     PetscInt faceVerticesTetSorted[24] = {
9478       0, 1, 2,  6, 7, 8, /* bottom */
9479       0, 3, 4,  6, 7, 9,  /* front */
9480       1, 4, 5,  7, 8, 9,  /* right */
9481       2, 3, 5,  6, 8, 9,  /* left */
9482     };
9483     PetscInt faceVerticesTet[24] = {
9484       0, 1, 2,  6, 7, 8, /* bottom */
9485       0, 4, 3,  6, 7, 9,  /* front */
9486       1, 5, 4,  7, 8, 9,  /* right */
9487       2, 3, 5,  8, 6, 9,  /* left */
9488     };
9489 
9490     faceSize = faceSizeTet;
9491     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9492     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9493     for (iFace=0; iFace < 4; ++iFace) {
9494       const PetscInt ii = iFace*faceSizeTet;
9495       PetscInt       fVertex, cVertex;
9496 
9497       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9498           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9499           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9500           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9501         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9502           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9503             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9504               faceVertices[fVertex] = origVertices[cVertex];
9505               break;
9506             }
9507           }
9508         }
9509         found = PETSC_TRUE;
9510         break;
9511       }
9512     }
9513     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9514     if (posOriented) {*posOriented = PETSC_TRUE;}
9515     PetscFunctionReturn(0);
9516   } else if (cellDim == 3 && numCorners == 27) {
9517     /* Quadratic hexes (I hate this)
9518        A hex is two oriented quads with the normal of the first
9519        pointing up at the second.
9520 
9521          7---6
9522         /|  /|
9523        4---5 |
9524        | 3-|-2
9525        |/  |/
9526        0---1
9527 
9528        Faces are determined by the first 4 vertices (corners of faces) */
9529     const PetscInt faceSizeQuadHex = 9;
9530     PetscInt  sortedIndices[9], i, iFace;
9531     PetscBool found = PETSC_FALSE;
9532     PetscInt faceVerticesQuadHexSorted[54] = {
9533       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9534       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9535       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9536       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9537       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9538       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9539     };
9540     PetscInt faceVerticesQuadHex[54] = {
9541       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9542       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9543       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9544       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9545       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9546       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9547     };
9548 
9549     faceSize = faceSizeQuadHex;
9550     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9551     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9552     for (iFace = 0; iFace < 6; ++iFace) {
9553       const PetscInt ii = iFace*faceSizeQuadHex;
9554       PetscInt       fVertex, cVertex;
9555 
9556       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9557           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9558           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9559           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9560         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9561           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9562             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9563               faceVertices[fVertex] = origVertices[cVertex];
9564               break;
9565             }
9566           }
9567         }
9568         found = PETSC_TRUE;
9569         break;
9570       }
9571     }
9572     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9573     if (posOriented) {*posOriented = PETSC_TRUE;}
9574     PetscFunctionReturn(0);
9575   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9576   if (!posOrient) {
9577     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9578     for (f = 0; f < faceSize; ++f) {
9579       faceVertices[f] = origVertices[faceSize-1 - f];
9580     }
9581   } else {
9582     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9583     for (f = 0; f < faceSize; ++f) {
9584       faceVertices[f] = origVertices[f];
9585     }
9586   }
9587   if (posOriented) {*posOriented = posOrient;}
9588   PetscFunctionReturn(0);
9589 }
9590 
9591 #undef __FUNCT__
9592 #define __FUNCT__ "DMPlexGetOrientedFace"
9593 /*
9594     Given a cell and a face, as a set of vertices,
9595       return the oriented face, as a set of vertices, in faceVertices
9596     The orientation is such that the face normal points out of the cell
9597 */
9598 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9599 {
9600   const PetscInt *cone = PETSC_NULL;
9601   PetscInt        coneSize, v, f, v2;
9602   PetscInt        oppositeVertex = -1;
9603   PetscErrorCode  ierr;
9604 
9605   PetscFunctionBegin;
9606   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9607   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9608   for (v = 0, v2 = 0; v < coneSize; ++v) {
9609     PetscBool found  = PETSC_FALSE;
9610 
9611     for (f = 0; f < faceSize; ++f) {
9612       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9613     }
9614     if (found) {
9615       indices[v2]      = v;
9616       origVertices[v2] = cone[v];
9617       ++v2;
9618     } else {
9619       oppositeVertex = v;
9620     }
9621   }
9622   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9623   PetscFunctionReturn(0);
9624 }
9625 
9626 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9627 {
9628   switch (i) {
9629   case 0:
9630     switch (j) {
9631     case 0: return 0;
9632     case 1:
9633       switch (k) {
9634       case 0: return 0;
9635       case 1: return 0;
9636       case 2: return 1;
9637       }
9638     case 2:
9639       switch (k) {
9640       case 0: return 0;
9641       case 1: return -1;
9642       case 2: return 0;
9643       }
9644     }
9645   case 1:
9646     switch (j) {
9647     case 0:
9648       switch (k) {
9649       case 0: return 0;
9650       case 1: return 0;
9651       case 2: return -1;
9652       }
9653     case 1: return 0;
9654     case 2:
9655       switch (k) {
9656       case 0: return 1;
9657       case 1: return 0;
9658       case 2: return 0;
9659       }
9660     }
9661   case 2:
9662     switch (j) {
9663     case 0:
9664       switch (k) {
9665       case 0: return 0;
9666       case 1: return 1;
9667       case 2: return 0;
9668       }
9669     case 1:
9670       switch (k) {
9671       case 0: return -1;
9672       case 1: return 0;
9673       case 2: return 0;
9674       }
9675     case 2: return 0;
9676     }
9677   }
9678   return 0;
9679 }
9680 
9681 #undef __FUNCT__
9682 #define __FUNCT__ "DMPlexCreateRigidBody"
9683 /*@C
9684   DMPlexCreateRigidBody - create rigid body modes from coordinates
9685 
9686   Collective on DM
9687 
9688   Input Arguments:
9689 + dm - the DM
9690 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9691 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9692 
9693   Output Argument:
9694 . sp - the null space
9695 
9696   Note: This is necessary to take account of Dirichlet conditions on the displacements
9697 
9698   Level: advanced
9699 
9700 .seealso: MatNullSpaceCreate()
9701 @*/
9702 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9703 {
9704   MPI_Comm       comm = ((PetscObject) dm)->comm;
9705   Vec            coordinates, localMode, mode[6];
9706   PetscSection   coordSection;
9707   PetscScalar   *coords;
9708   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9709   PetscErrorCode ierr;
9710 
9711   PetscFunctionBegin;
9712   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9713   if (dim == 1) {
9714     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9715     PetscFunctionReturn(0);
9716   }
9717   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9718   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9719   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9720   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9721   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9722   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9723   m    = (dim*(dim+1))/2;
9724   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9725   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9726   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9727   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9728   /* Assume P1 */
9729   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9730   for (d = 0; d < dim; ++d) {
9731     PetscScalar values[3] = {0.0, 0.0, 0.0};
9732 
9733     values[d] = 1.0;
9734     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9735     for (v = vStart; v < vEnd; ++v) {
9736       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9737     }
9738     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9739     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9740   }
9741   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9742   for (d = dim; d < dim*(dim+1)/2; ++d) {
9743     PetscInt i, j, k = dim > 2 ? d - dim : d;
9744 
9745     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9746     for (v = vStart; v < vEnd; ++v) {
9747       PetscScalar values[3] = {0.0, 0.0, 0.0};
9748       PetscInt    off;
9749 
9750       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9751       for (i = 0; i < dim; ++i) {
9752         for (j = 0; j < dim; ++j) {
9753           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9754         }
9755       }
9756       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9757     }
9758     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9759     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9760   }
9761   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9762   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9763   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9764   /* Orthonormalize system */
9765   for (i = dim; i < m; ++i) {
9766     PetscScalar dots[6];
9767 
9768     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9769     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9770     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9771     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9772   }
9773   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9774   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9775   PetscFunctionReturn(0);
9776 }
9777 
9778 #undef __FUNCT__
9779 #define __FUNCT__ "DMPlexGetHybridBounds"
9780 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9781 {
9782   DM_Plex       *mesh = (DM_Plex *) dm->data;
9783   PetscInt       dim;
9784   PetscErrorCode ierr;
9785 
9786   PetscFunctionBegin;
9787   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9788   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9789   if (cMax) *cMax = mesh->hybridPointMax[dim];
9790   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9791   if (eMax) *eMax = mesh->hybridPointMax[1];
9792   if (vMax) *vMax = mesh->hybridPointMax[0];
9793   PetscFunctionReturn(0);
9794 }
9795 
9796 #undef __FUNCT__
9797 #define __FUNCT__ "DMPlexSetHybridBounds"
9798 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9799 {
9800   DM_Plex       *mesh = (DM_Plex *) dm->data;
9801   PetscInt       dim;
9802   PetscErrorCode ierr;
9803 
9804   PetscFunctionBegin;
9805   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9806   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9807   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9808   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9809   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9810   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9811   PetscFunctionReturn(0);
9812 }
9813 
9814 #undef __FUNCT__
9815 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9816 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9817 {
9818   DM_Plex *mesh = (DM_Plex *) dm->data;
9819 
9820   PetscFunctionBegin;
9821   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9822   PetscValidPointer(cellHeight, 2);
9823   *cellHeight = mesh->vtkCellHeight;
9824   PetscFunctionReturn(0);
9825 }
9826 
9827 #undef __FUNCT__
9828 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9829 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9830 {
9831   DM_Plex *mesh = (DM_Plex *) dm->data;
9832 
9833   PetscFunctionBegin;
9834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9835   mesh->vtkCellHeight = cellHeight;
9836   PetscFunctionReturn(0);
9837 }
9838 
9839 #undef __FUNCT__
9840 #define __FUNCT__ "DMPlexInsertFace_Private"
9841 /*
9842   DMPlexInsertFace_Private - Puts a face into the mesh
9843 
9844   Not collective
9845 
9846   Input Parameters:
9847   + dm              - The DMPlex
9848   . numFaceVertex   - The number of vertices in the face
9849   . faceVertices    - The vertices in the face for dm
9850   . subfaceVertices - The vertices in the face for subdm
9851   . numCorners      - The number of vertices in the cell
9852   . cell            - A cell in dm containing the face
9853   . subcell         - A cell in subdm containing the face
9854   . firstFace       - First face in the mesh
9855   - newFacePoint    - Next face in the mesh
9856 
9857   Output Parameters:
9858   . newFacePoint - Contains next face point number on input, updated on output
9859 
9860   Level: developer
9861 */
9862 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)
9863 {
9864   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9865   DM_Plex     *submesh = (DM_Plex *) subdm->data;
9866   const PetscInt *faces;
9867   PetscInt        numFaces, coneSize;
9868   PetscErrorCode  ierr;
9869 
9870   PetscFunctionBegin;
9871   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9872   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9873 #if 0
9874   /* Cannot use this because support() has not been constructed yet */
9875   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9876 #else
9877   {
9878     PetscInt f;
9879 
9880     numFaces = 0;
9881     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
9882     for (f = firstFace; f < *newFacePoint; ++f) {
9883       PetscInt dof, off, d;
9884 
9885       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9886       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9887       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9888       for (d = 0; d < dof; ++d) {
9889         const PetscInt p = submesh->cones[off+d];
9890         PetscInt       v;
9891 
9892         for (v = 0; v < numFaceVertices; ++v) {
9893           if (subfaceVertices[v] == p) break;
9894         }
9895         if (v == numFaceVertices) break;
9896       }
9897       if (d == dof) {
9898         numFaces = 1;
9899         ((PetscInt *) faces)[0] = f;
9900       }
9901     }
9902   }
9903 #endif
9904   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
9905   else if (numFaces == 1) {
9906     /* Add the other cell neighbor for this face */
9907     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
9908   } else {
9909     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
9910     PetscBool posOriented;
9911 
9912     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9913     origVertices = &orientedVertices[numFaceVertices];
9914     indices      = &orientedVertices[numFaceVertices*2];
9915     orientedSubVertices = &orientedVertices[numFaceVertices*3];
9916     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
9917     /* TODO: I know that routine should return a permutation, not the indices */
9918     for (v = 0; v < numFaceVertices; ++v) {
9919       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
9920       for (ov = 0; ov < numFaceVertices; ++ov) {
9921         if (orientedVertices[ov] == vertex) {
9922           orientedSubVertices[ov] = subvertex;
9923           break;
9924         }
9925       }
9926       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
9927     }
9928     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
9929     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
9930     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9931     ++(*newFacePoint);
9932   }
9933   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9934   PetscFunctionReturn(0);
9935 }
9936 
9937 #undef __FUNCT__
9938 #define __FUNCT__ "DMPlexCreateSubmesh"
9939 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
9940 {
9941   MPI_Comm        comm = ((PetscObject) dm)->comm;
9942   DM_Plex     *submesh;
9943   PetscBool       boundaryFaces = PETSC_FALSE;
9944   PetscSection    coordSection, subCoordSection;
9945   Vec             coordinates, subCoordinates;
9946   PetscScalar    *coords, *subCoords;
9947   IS              labelIS;
9948   const PetscInt *subVertices;
9949   PetscInt       *subVerticesActive, *tmpPoints;
9950   PetscInt       *subCells = PETSC_NULL;
9951   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
9952   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
9953   PetscInt        dim; /* Right now, do not specify dimension */
9954   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
9955   PetscErrorCode  ierr;
9956 
9957   PetscFunctionBegin;
9958   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9959   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9960   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9961   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
9962   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9963   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9964   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9965   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9966   subface = &face[maxConeSize];
9967   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
9968   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
9969   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
9970   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
9971   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
9972   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
9973   maxSubCells = numSubVertices;
9974   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
9975   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
9976   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
9977   for (v = 0; v < numSubVertices; ++v) {
9978     const PetscInt vertex = subVertices[v];
9979     PetscInt *star = PETSC_NULL;
9980     PetscInt  starSize, numCells = 0;
9981 
9982     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9983     for (p = 0; p < starSize*2; p += 2) {
9984       const PetscInt point = star[p];
9985       if ((point >= cStart) && (point < cEnd)) {
9986         star[numCells++] = point;
9987       }
9988     }
9989     numOldSubCells = numSubCells;
9990     for (c = 0; c < numCells; ++c) {
9991       const PetscInt cell    = star[c];
9992       PetscInt      *closure = PETSC_NULL;
9993       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9994       PetscInt       cellLoc;
9995 
9996       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9997       if (cellLoc >= 0) continue;
9998       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9999       for (p = 0; p < closureSize*2; p += 2) {
10000         const PetscInt point = closure[p];
10001         if ((point >= vStart) && (point < vEnd)) {
10002           closure[numCorners++] = point;
10003         }
10004       }
10005       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
10006       for (corner = 0; corner < numCorners; ++corner) {
10007         const PetscInt cellVertex = closure[corner];
10008         PetscInt       subVertex;
10009 
10010         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
10011         if (subVertex >= 0) { /* contains submesh vertex */
10012           for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10013           if (i == faceSize) {
10014             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
10015             face[faceSize]    = cellVertex;
10016             subface[faceSize] = subVertex;
10017             ++faceSize;
10018           }
10019         }
10020       }
10021       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10022       if (faceSize >= nFV) {
10023         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10024         if (numSubCells >= maxSubCells) {
10025           PetscInt *tmpCells;
10026           maxSubCells *= 2;
10027           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
10028           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
10029           ierr = PetscFree(subCells);CHKERRQ(ierr);
10030           subCells = tmpCells;
10031         }
10032         /* TOOD: Maybe overestimate then squeeze out empty faces */
10033         if (faceSize > nFV) {
10034           /* TODO: This is tricky. Maybe just add all faces */
10035           numSubFaces++;
10036         } else {
10037           numSubFaces++;
10038         }
10039         for (f = 0; f < faceSize; ++f) {
10040           subVerticesActive[subface[f]] = 1;
10041         }
10042         subCells[numSubCells++] = cell;
10043       }
10044     }
10045     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10046     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
10047   }
10048   /* Pick out active subvertices */
10049   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
10050     if (subVerticesActive[v]) {
10051       subVerticesActive[numSubVerticesActive++] = subVertices[v];
10052     }
10053   }
10054   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
10055   /* Set cone sizes */
10056   firstSubVertex = numSubCells;
10057   firstSubFace   = numSubCells+numSubVerticesActive;
10058   newFacePoint   = firstSubFace;
10059   for (c = 0; c < numSubCells; ++c) {
10060     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
10061   }
10062   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
10063     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
10064   }
10065   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
10066   /* Create face cones */
10067   for (c = 0; c < numSubCells; ++c) {
10068     const PetscInt cell    = subCells[c];
10069     PetscInt      *closure = PETSC_NULL;
10070     PetscInt       closureSize, numCorners = 0, faceSize = 0;
10071 
10072     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10073     for (p = 0; p < closureSize*2; p += 2) {
10074       const PetscInt point = closure[p];
10075       if ((point >= vStart) && (point < vEnd)) {
10076         closure[numCorners++] = point;
10077       }
10078     }
10079     for (corner = 0; corner < numCorners; ++corner) {
10080       const PetscInt cellVertex = closure[corner];
10081       PetscInt       subVertex;
10082 
10083       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
10084       if (subVertex >= 0) { /* contains submesh vertex */
10085         for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10086         if (i == faceSize) {
10087           face[faceSize]    = cellVertex;
10088           subface[faceSize] = numSubCells+subVertex;
10089           ++faceSize;
10090         }
10091       }
10092     }
10093     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10094     if (faceSize >= nFV) {
10095       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10096       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
10097       /*   We have to take all the faces, and discard those in the interior */
10098       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
10099 #if 0
10100       /* This object just calls insert on each face that comes from subsets() */
10101       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
10102       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
10103       PointArray                          faceVec(face->begin(), face->end());
10104 
10105       subsets(faceVec, nFV, inserter);
10106 #endif
10107       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10108     }
10109   }
10110   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
10111   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
10112   /* Build coordinates */
10113   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10114   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10115   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
10116   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10117   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10118     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10119   }
10120   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10121   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10122   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
10123   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10124   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10125   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10126   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10127   for (v = 0; v < numSubVerticesActive; ++v) {
10128     const PetscInt vertex    = subVerticesActive[v];
10129     const PetscInt subVertex = firstSubVertex+v;
10130     PetscInt dof, off, sdof, soff;
10131 
10132     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10133     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10134     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10135     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10136     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10137     for (d = 0; d < dof; ++d) {
10138       subCoords[soff+d] = coords[off+d];
10139     }
10140   }
10141   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10142   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10143   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
10144   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10145 
10146   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
10147   /* Create map from submesh points to original mesh points */
10148   submesh = (DM_Plex *) (*subdm)->data;
10149   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10150   for (c = 0; c < numSubCells; ++c) {
10151     tmpPoints[c] = subCells[c];
10152   }
10153   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
10154     tmpPoints[v] = subVerticesActive[v-numSubCells];
10155   }
10156   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
10157 
10158   ierr = PetscFree(subCells);CHKERRQ(ierr);
10159   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10160   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10161   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10162   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10163   PetscFunctionReturn(0);
10164 }
10165 
10166 #undef __FUNCT__
10167 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10168 /* We can easily have a form that takes an IS instead */
10169 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10170 {
10171   PetscSection   section, globalSection;
10172   PetscInt      *numbers, p;
10173   PetscErrorCode ierr;
10174 
10175   PetscFunctionBegin;
10176   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10177   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10178   for (p = pStart; p < pEnd; ++p) {
10179     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10180   }
10181   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10182   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10183   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10184   for (p = pStart; p < pEnd; ++p) {
10185     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10186   }
10187   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10188   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10189   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10190   PetscFunctionReturn(0);
10191 }
10192 
10193 #undef __FUNCT__
10194 #define __FUNCT__ "DMPlexGetCellNumbering"
10195 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10196 {
10197   DM_Plex    *mesh = (DM_Plex *) dm->data;
10198   PetscInt       cellHeight, cStart, cEnd, cMax;
10199   PetscErrorCode ierr;
10200 
10201   PetscFunctionBegin;
10202   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10203   if (!mesh->globalCellNumbers) {
10204     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10205     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10206     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10207     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10208     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10209   }
10210   *globalCellNumbers = mesh->globalCellNumbers;
10211   PetscFunctionReturn(0);
10212 }
10213 
10214 #undef __FUNCT__
10215 #define __FUNCT__ "DMPlexGetVertexNumbering"
10216 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10217 {
10218   DM_Plex    *mesh = (DM_Plex *) dm->data;
10219   PetscInt       vStart, vEnd, vMax;
10220   PetscErrorCode ierr;
10221 
10222   PetscFunctionBegin;
10223   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10224   if (!mesh->globalVertexNumbers) {
10225     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10226     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10227     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10228     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10229   }
10230   *globalVertexNumbers = mesh->globalVertexNumbers;
10231   PetscFunctionReturn(0);
10232 }
10233 
10234 #undef __FUNCT__
10235 #define __FUNCT__ "DMPlexGetSubpointMap"
10236 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10237 {
10238   DM_Plex *mesh = (DM_Plex *) dm->data;
10239 
10240   PetscFunctionBegin;
10241   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10242   PetscValidPointer(subpointMap, 2);
10243   *subpointMap = mesh->subpointMap;
10244   PetscFunctionReturn(0);
10245 }
10246 
10247 #undef __FUNCT__
10248 #define __FUNCT__ "DMPlexSetSubpointMap"
10249 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10250 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10251 {
10252   DM_Plex *mesh = (DM_Plex *) dm->data;
10253 
10254   PetscFunctionBegin;
10255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10256   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10257   mesh->subpointMap = subpointMap;
10258   PetscFunctionReturn(0);
10259 }
10260 
10261 #undef __FUNCT__
10262 #define __FUNCT__ "DMPlexGetScale"
10263 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10264 {
10265   DM_Plex *mesh = (DM_Plex *) dm->data;
10266 
10267   PetscFunctionBegin;
10268   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10269   PetscValidPointer(scale, 3);
10270   *scale = mesh->scale[unit];
10271   PetscFunctionReturn(0);
10272 }
10273 
10274 #undef __FUNCT__
10275 #define __FUNCT__ "DMPlexSetScale"
10276 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10277 {
10278   DM_Plex *mesh = (DM_Plex *) dm->data;
10279 
10280   PetscFunctionBegin;
10281   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10282   mesh->scale[unit] = scale;
10283   PetscFunctionReturn(0);
10284 }
10285 
10286 
10287 /*******************************************************************************
10288 This should be in a separate Discretization object, but I am not sure how to lay
10289 it out yet, so I am stuffing things here while I experiment.
10290 *******************************************************************************/
10291 #undef __FUNCT__
10292 #define __FUNCT__ "DMPlexSetFEMIntegration"
10293 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10294                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10295                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10296                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10297                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10298                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10299                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10300                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10301                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10302                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10303                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10304                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10305                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10306                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10307                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10308                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10309                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10310 {
10311   DM_Plex *mesh = (DM_Plex *) dm->data;
10312 
10313   PetscFunctionBegin;
10314   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10315   mesh->integrateResidualFEM       = integrateResidualFEM;
10316   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10317   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10318   PetscFunctionReturn(0);
10319 }
10320 
10321 #undef __FUNCT__
10322 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10323 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10324 {
10325   Vec            coordinates;
10326   PetscSection   section, cSection;
10327   PetscInt       dim, vStart, vEnd, v, c, d;
10328   PetscScalar   *values, *cArray;
10329   PetscReal     *coords;
10330   PetscErrorCode ierr;
10331 
10332   PetscFunctionBegin;
10333   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10334   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10335   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10336   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10337   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10338   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10339   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10340   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10341   for (v = vStart; v < vEnd; ++v) {
10342     PetscInt dof, off;
10343 
10344     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10345     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10346     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10347     for (d = 0; d < dof; ++d) {
10348       coords[d] = PetscRealPart(cArray[off+d]);
10349     }
10350     for (c = 0; c < numComp; ++c) {
10351       values[c] = (*funcs[c])(coords);
10352     }
10353     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10354   }
10355   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10356   /* Temporary, must be replaced by a projection on the finite element basis */
10357   {
10358     PetscInt eStart = 0, eEnd = 0, e, depth;
10359 
10360     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10361     --depth;
10362     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10363     for (e = eStart; e < eEnd; ++e) {
10364       const PetscInt *cone = PETSC_NULL;
10365       PetscInt        coneSize, d;
10366       PetscScalar    *coordsA, *coordsB;
10367 
10368       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10369       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10370       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10371       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10372       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10373       for (d = 0; d < dim; ++d) {
10374         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10375       }
10376       for (c = 0; c < numComp; ++c) {
10377         values[c] = (*funcs[c])(coords);
10378       }
10379       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10380     }
10381   }
10382 
10383   ierr = PetscFree(coords);CHKERRQ(ierr);
10384   ierr = PetscFree(values);CHKERRQ(ierr);
10385 #if 0
10386   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10387   PetscReal      detJ;
10388 
10389   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10390   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10391   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10392 
10393   for (PetscInt c = cStart; c < cEnd; ++c) {
10394     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10395     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10396     const int                          oSize   = pV.getSize();
10397     int                                v       = 0;
10398 
10399     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10400     for (PetscInt cl = 0; cl < oSize; ++cl) {
10401       const PetscInt fDim;
10402 
10403       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10404       if (pointDim) {
10405         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10406           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10407         }
10408       }
10409     }
10410     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10411     pV.clear();
10412   }
10413   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10414   ierr = PetscFree(values);CHKERRQ(ierr);
10415 #endif
10416   PetscFunctionReturn(0);
10417 }
10418 
10419 #undef __FUNCT__
10420 #define __FUNCT__ "DMPlexProjectFunction"
10421 /*@C
10422   DMPlexProjectFunction - This projects the given function into the function space provided.
10423 
10424   Input Parameters:
10425 + dm      - The DM
10426 . numComp - The number of components (functions)
10427 . funcs   - The coordinate functions to evaluate
10428 - mode    - The insertion mode for values
10429 
10430   Output Parameter:
10431 . X - vector
10432 
10433   Level: developer
10434 
10435   Note:
10436   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10437   We will eventually fix it.
10438 
10439 ,seealso: DMPlexComputeL2Diff()
10440 */
10441 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10442 {
10443   Vec            localX;
10444   PetscErrorCode ierr;
10445 
10446   PetscFunctionBegin;
10447   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10448   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10449   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10450   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10451   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10452   PetscFunctionReturn(0);
10453 }
10454 
10455 #undef __FUNCT__
10456 #define __FUNCT__ "DMPlexComputeL2Diff"
10457 /*@C
10458   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10459 
10460   Input Parameters:
10461 + dm    - The DM
10462 . quad  - The PetscQuadrature object for each field
10463 . funcs - The functions to evaluate for each field component
10464 - X     - The coefficient vector u_h
10465 
10466   Output Parameter:
10467 . diff - The diff ||u - u_h||_2
10468 
10469   Level: developer
10470 
10471 .seealso: DMPlexProjectFunction()
10472 */
10473 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10474 {
10475   const PetscInt   debug = 0;
10476   PetscSection     section;
10477   Vec              localX;
10478   PetscReal       *coords, *v0, *J, *invJ, detJ;
10479   PetscReal        localDiff = 0.0;
10480   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10481   PetscErrorCode   ierr;
10482 
10483   PetscFunctionBegin;
10484   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10485   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10486   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10487   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10488   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10489   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10490   for (field = 0; field < numFields; ++field) {
10491     numComponents += quad[field].numComponents;
10492   }
10493   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10494   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10495   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10496   for (c = cStart; c < cEnd; ++c) {
10497     const PetscScalar *x;
10498     PetscReal          elemDiff = 0.0;
10499 
10500     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10501     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10502     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10503 
10504     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10505       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10506       const PetscReal *quadPoints    = quad[field].quadPoints;
10507       const PetscReal *quadWeights   = quad[field].quadWeights;
10508       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10509       const PetscInt   numBasisComps = quad[field].numComponents;
10510       const PetscReal *basis         = quad[field].basis;
10511       PetscInt         q, d, e, fc, f;
10512 
10513       if (debug) {
10514         char title[1024];
10515         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10516         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10517       }
10518       for (q = 0; q < numQuadPoints; ++q) {
10519         for (d = 0; d < dim; d++) {
10520           coords[d] = v0[d];
10521           for (e = 0; e < dim; e++) {
10522             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10523           }
10524         }
10525         for (fc = 0; fc < numBasisComps; ++fc) {
10526           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10527           PetscReal       interpolant = 0.0;
10528           for (f = 0; f < numBasisFuncs; ++f) {
10529             const PetscInt fidx = f*numBasisComps+fc;
10530             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10531           }
10532           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10533           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10534         }
10535       }
10536       comp        += numBasisComps;
10537       fieldOffset += numBasisFuncs*numBasisComps;
10538     }
10539     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10540     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10541     localDiff += elemDiff;
10542   }
10543   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10544   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10545   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10546   *diff = PetscSqrtReal(*diff);
10547   PetscFunctionReturn(0);
10548 }
10549 
10550 #undef __FUNCT__
10551 #define __FUNCT__ "DMPlexComputeResidualFEM"
10552 /*@
10553   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10554 
10555   Input Parameters:
10556 + dm - The mesh
10557 . X  - Local input vector
10558 - user - The user context
10559 
10560   Output Parameter:
10561 . F  - Local output vector
10562 
10563   Note:
10564   The second member of the user context must be an FEMContext.
10565 
10566   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10567   like a GPU, or vectorize on a multicore machine.
10568 
10569 .seealso: DMPlexComputeJacobianActionFEM()
10570 */
10571 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10572 {
10573   DM_Plex      *mesh = (DM_Plex *) dm->data;
10574   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10575   PetscQuadrature *quad = fem->quad;
10576   PetscSection     section;
10577   PetscReal       *v0, *J, *invJ, *detJ;
10578   PetscScalar     *elemVec, *u;
10579   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10580   PetscInt         cellDof = 0, numComponents = 0;
10581   PetscErrorCode   ierr;
10582 
10583   PetscFunctionBegin;
10584   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10585   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10586   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10587   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10588   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10589   numCells = cEnd - cStart;
10590   for (field = 0; field < numFields; ++field) {
10591     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10592     numComponents += quad[field].numComponents;
10593   }
10594   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10595   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10596   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);
10597   for (c = cStart; c < cEnd; ++c) {
10598     const PetscScalar *x;
10599     PetscInt           i;
10600 
10601     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10602     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10603     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10604 
10605     for (i = 0; i < cellDof; ++i) {
10606       u[c*cellDof+i] = x[i];
10607     }
10608     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10609   }
10610   for (field = 0; field < numFields; ++field) {
10611     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10612     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10613     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10614     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10615     /* Conforming batches */
10616     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10617     PetscInt numBlocks  = 1;
10618     PetscInt batchSize  = numBlocks * blockSize;
10619     PetscInt numBatches = numBatchesTmp;
10620     PetscInt numChunks  = numCells / (numBatches*batchSize);
10621     /* Remainder */
10622     PetscInt numRemainder = numCells % (numBatches * batchSize);
10623     PetscInt offset       = numCells - numRemainder;
10624 
10625     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10626     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10627                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10628   }
10629   for (c = cStart; c < cEnd; ++c) {
10630     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10631     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10632   }
10633   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10634   if (mesh->printFEM) {
10635     PetscMPIInt rank, numProcs;
10636     PetscInt    p;
10637 
10638     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10639     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10640     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10641     for (p = 0; p < numProcs; ++p) {
10642       if (p == rank) {
10643         Vec f;
10644 
10645         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10646         ierr = VecCopy(F, f);CHKERRQ(ierr);
10647         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10648         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10649         ierr = VecDestroy(&f);CHKERRQ(ierr);
10650         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10651       }
10652       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10653     }
10654   }
10655   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10656   PetscFunctionReturn(0);
10657 }
10658 
10659 #undef __FUNCT__
10660 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10661 /*@C
10662   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10663 
10664   Input Parameters:
10665 + dm - The mesh
10666 . J  - The Jacobian shell matrix
10667 . X  - Local input vector
10668 - user - The user context
10669 
10670   Output Parameter:
10671 . F  - Local output vector
10672 
10673   Note:
10674   The second member of the user context must be an FEMContext.
10675 
10676   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10677   like a GPU, or vectorize on a multicore machine.
10678 
10679 .seealso: DMPlexComputeResidualFEM()
10680 */
10681 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10682 {
10683   DM_Plex      *mesh = (DM_Plex *) dm->data;
10684   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10685   PetscQuadrature *quad = fem->quad;
10686   PetscSection     section;
10687   JacActionCtx    *jctx;
10688   PetscReal       *v0, *J, *invJ, *detJ;
10689   PetscScalar     *elemVec, *u, *a;
10690   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10691   PetscInt         cellDof = 0;
10692   PetscErrorCode   ierr;
10693 
10694   PetscFunctionBegin;
10695   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10696   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10697   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10698   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10699   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10700   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10701   numCells = cEnd - cStart;
10702   for (field = 0; field < numFields; ++field) {
10703     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10704   }
10705   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10706   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);
10707   for (c = cStart; c < cEnd; ++c) {
10708     const PetscScalar *x;
10709     PetscInt           i;
10710 
10711     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10712     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10713     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10714     for (i = 0; i < cellDof; ++i) {
10715       u[c*cellDof+i] = x[i];
10716     }
10717     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10718     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10719     for (i = 0; i < cellDof; ++i) {
10720       a[c*cellDof+i] = x[i];
10721     }
10722     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10723   }
10724   for (field = 0; field < numFields; ++field) {
10725     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10726     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10727     /* Conforming batches */
10728     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10729     PetscInt numBlocks  = 1;
10730     PetscInt batchSize  = numBlocks * blockSize;
10731     PetscInt numBatches = numBatchesTmp;
10732     PetscInt numChunks  = numCells / (numBatches*batchSize);
10733     /* Remainder */
10734     PetscInt numRemainder = numCells % (numBatches * batchSize);
10735     PetscInt offset       = numCells - numRemainder;
10736 
10737     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);
10738     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],
10739                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10740   }
10741   for (c = cStart; c < cEnd; ++c) {
10742     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10743     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10744   }
10745   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10746   if (mesh->printFEM) {
10747     PetscMPIInt rank, numProcs;
10748     PetscInt    p;
10749 
10750     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10751     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10752     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10753     for (p = 0; p < numProcs; ++p) {
10754       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10755       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10756     }
10757   }
10758   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10759   PetscFunctionReturn(0);
10760 }
10761 
10762 #undef __FUNCT__
10763 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10764 /*@
10765   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10766 
10767   Input Parameters:
10768 + dm - The mesh
10769 . X  - Local input vector
10770 - user - The user context
10771 
10772   Output Parameter:
10773 . Jac  - Jacobian matrix
10774 
10775   Note:
10776   The second member of the user context must be an FEMContext.
10777 
10778   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10779   like a GPU, or vectorize on a multicore machine.
10780 
10781 .seealso: FormFunctionLocal()
10782 */
10783 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10784 {
10785   DM_Plex      *mesh = (DM_Plex *) dm->data;
10786   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10787   PetscQuadrature *quad = fem->quad;
10788   PetscSection     section;
10789   PetscReal       *v0, *J, *invJ, *detJ;
10790   PetscScalar     *elemMat, *u;
10791   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10792   PetscInt         cellDof = 0, numComponents = 0;
10793   PetscBool        isShell;
10794   PetscErrorCode   ierr;
10795 
10796   PetscFunctionBegin;
10797   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10798   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10799   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10800   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10801   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10802   numCells = cEnd - cStart;
10803   for (field = 0; field < numFields; ++field) {
10804     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10805     numComponents += quad[field].numComponents;
10806   }
10807   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10808   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10809   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);
10810   for (c = cStart; c < cEnd; ++c) {
10811     const PetscScalar *x;
10812     PetscInt           i;
10813 
10814     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10815     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10816     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10817 
10818     for (i = 0; i < cellDof; ++i) {
10819       u[c*cellDof+i] = x[i];
10820     }
10821     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10822   }
10823   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10824   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10825     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10826     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10827     PetscInt       fieldJ;
10828 
10829     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10830       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10831       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10832       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10833       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10834       /* Conforming batches */
10835       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10836       PetscInt numBlocks  = 1;
10837       PetscInt batchSize  = numBlocks * blockSize;
10838       PetscInt numBatches = numBatchesTmp;
10839       PetscInt numChunks  = numCells / (numBatches*batchSize);
10840       /* Remainder */
10841       PetscInt numRemainder = numCells % (numBatches * batchSize);
10842       PetscInt offset       = numCells - numRemainder;
10843 
10844       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10845       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10846                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10847     }
10848   }
10849   for (c = cStart; c < cEnd; ++c) {
10850     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10851     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10852   }
10853   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10854 
10855   /* Assemble matrix, using the 2-step process:
10856        MatAssemblyBegin(), MatAssemblyEnd(). */
10857   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10858   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10859 
10860   if (mesh->printFEM) {
10861     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10862     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10863     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10864   }
10865   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10866   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10867   if (isShell) {
10868     JacActionCtx *jctx;
10869 
10870     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10871     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10872   }
10873   *str = SAME_NONZERO_PATTERN;
10874   PetscFunctionReturn(0);
10875 }
10876 
10877 
10878 #undef __FUNCT__
10879 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10880 /*@C
10881   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10882   the local section and an SF describing the section point overlap.
10883 
10884   Input Parameters:
10885   + s - The PetscSection for the local field layout
10886   . sf - The SF describing parallel layout of the section points
10887   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10888   . label - The label specifying the points
10889   - labelValue - The label stratum specifying the points
10890 
10891   Output Parameter:
10892   . gsection - The PetscSection for the global field layout
10893 
10894   Note: This gives negative sizes and offsets to points not owned by this process
10895 
10896   Level: developer
10897 
10898 .seealso: PetscSectionCreate()
10899 @*/
10900 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10901 {
10902   PetscInt      *neg;
10903   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10904   PetscErrorCode ierr;
10905 
10906   PetscFunctionBegin;
10907   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10908   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10909   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10910   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10911   /* Mark ghost points with negative dof */
10912   for (p = pStart; p < pEnd; ++p) {
10913     PetscInt value;
10914 
10915     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10916     if (value != labelValue) continue;
10917     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10918     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10919     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10920     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10921     neg[p-pStart] = -(dof+1);
10922   }
10923   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10924   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10925   if (nroots >= 0) {
10926     if (nroots > pEnd - pStart) {
10927       PetscInt *tmpDof;
10928       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10929       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10930       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10931       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10932       for (p = pStart; p < pEnd; ++p) {
10933         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
10934       }
10935       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10936     } else {
10937       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10938       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10939     }
10940   }
10941   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10942   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10943     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10944     (*gsection)->atlasOff[p] = off;
10945     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10946   }
10947   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10948   globalOff -= off;
10949   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10950     (*gsection)->atlasOff[p] += globalOff;
10951     neg[p] = -((*gsection)->atlasOff[p]+1);
10952   }
10953   /* Put in negative offsets for ghost points */
10954   if (nroots >= 0) {
10955     if (nroots > pEnd - pStart) {
10956       PetscInt *tmpOff;
10957       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10958       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10959       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10960       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10961       for (p = pStart; p < pEnd; ++p) {
10962         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
10963       }
10964       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10965     } else {
10966       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10967       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10968     }
10969   }
10970   ierr = PetscFree(neg);CHKERRQ(ierr);
10971   PetscFunctionReturn(0);
10972 }
10973