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