xref: /petsc/src/dm/impls/plex/plex.c (revision 978fe32243d9c5fe191a2c59e66093f308b6d890)
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     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
167     if (size > 1) {
168       PetscSF sf;
169 
170       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
171       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
172     }
173     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
174   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
175     const char  *name;
176     const char  *colors[3] = {"red", "blue", "green"};
177     const int    numColors  = 3;
178     PetscReal    scale      = 2.0;
179     PetscScalar *coords;
180     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
181     PetscMPIInt  rank, size;
182 
183     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
184     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
185     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
186     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
187     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
188     ierr = PetscViewerASCIIPrintf(viewer, "\
189 \\documentclass[crop,multi=false]{standalone}\n\n\
190 \\usepackage{tikz}\n\
191 \\usepackage{pgflibraryshapes}\n\
192 \\usetikzlibrary{backgrounds}\n\
193 \\usetikzlibrary{arrows}\n\
194 \\begin{document}\n\
195 \\section{%s}\n\
196 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
197     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
198     for (p = 0; p < size; ++p) {
199       if (p > 0 && p == size-1) {
200         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
201       } else if (p > 0) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
203       }
204       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
205     }
206     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
207 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
208     /* Plot vertices */
209     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
210     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
211     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
212     for (v = vStart; v < vEnd; ++v) {
213       PetscInt off, dof, d;
214 
215       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
216       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
217       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
218       for (d = 0; d < dof; ++d) {
219         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
220         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
221       }
222       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
223     }
224     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
225     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
226     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
227     /* Plot edges */
228     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
229     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
230     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
231     for (e = eStart; e < eEnd; ++e) {
232       const PetscInt *cone;
233       PetscInt        coneSize, offA, offB, dof, d;
234 
235       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
236       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
237       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
238       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
239       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
240       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
241       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
242       for (d = 0; d < dof; ++d) {
243         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
244         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
245       }
246       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
247     }
248     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
249     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
250     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
251     /* Plot cells */
252     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
253     for (c = cStart; c < cEnd; ++c) {
254       PetscInt *closure = PETSC_NULL;
255       PetscInt  closureSize, firstPoint = -1;
256 
257       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
258       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
259       for (p = 0; p < closureSize*2; p += 2) {
260         const PetscInt point = closure[p];
261 
262         if ((point < vStart) || (point >= vEnd)) continue;
263         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
264         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
265         if (firstPoint < 0) firstPoint = point;
266       }
267       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
268       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
269       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
270     }
271     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
272     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
273     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
274   } else {
275     MPI_Comm    comm = ((PetscObject) dm)->comm;
276     PetscInt   *sizes;
277     PetscInt    locDepth, depth, dim, d;
278     PetscInt    pStart, pEnd, p;
279     PetscMPIInt size;
280 
281     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
282     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
283     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
284     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
285     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
286     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
287     if (depth == 1) {
288       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
289       pEnd = pEnd - pStart;
290       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
291       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
292       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
293       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
294       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
295       pEnd = pEnd - pStart;
296       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
297       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
298       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
299       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
300     } else {
301       for (d = 0; d <= dim; d++) {
302         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
303         pEnd = pEnd - pStart;
304         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
305         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
306         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
307         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
308       }
309     }
310     ierr = PetscFree(sizes);CHKERRQ(ierr);
311   }
312   PetscFunctionReturn(0);
313 }
314 
315 #undef __FUNCT__
316 #define __FUNCT__ "DMView_Plex"
317 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
318 {
319   PetscBool      iascii, isbinary;
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
324   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
325   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
326   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
327   if (iascii) {
328     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
329 #if 0
330   } else if (isbinary) {
331     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
332 #endif
333   }
334   PetscFunctionReturn(0);
335 }
336 
337 #undef __FUNCT__
338 #define __FUNCT__ "DMDestroy_Plex"
339 PetscErrorCode DMDestroy_Plex(DM dm)
340 {
341   DM_Plex       *mesh = (DM_Plex*) dm->data;
342   DMLabel        next  = mesh->labels;
343   PetscErrorCode ierr;
344 
345   PetscFunctionBegin;
346   if (--mesh->refct > 0) PetscFunctionReturn(0);
347   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
348   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
349   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
350   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
353   while (next) {
354     DMLabel tmp = next->next;
355 
356     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
357     next = tmp;
358   }
359   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
360   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
361   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
362   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
363   ierr = PetscFree(mesh);CHKERRQ(ierr);
364   PetscFunctionReturn(0);
365 }
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
369 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
370 {
371   const PetscInt *support = PETSC_NULL;
372   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
373   PetscErrorCode  ierr;
374 
375   PetscFunctionBegin;
376   if (useClosure) {
377     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
378     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
379     for (s = 0; s < supportSize; ++s) {
380       const PetscInt *cone = PETSC_NULL;
381       PetscInt        coneSize, c, q;
382 
383       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
384       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
385       for (c = 0; c < coneSize; ++c) {
386         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
387           if (cone[c] == adj[q]) break;
388         }
389         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
390       }
391     }
392   } else {
393     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
394     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
395     for (s = 0; s < supportSize; ++s) {
396       const PetscInt *cone = PETSC_NULL;
397       PetscInt        coneSize, c, q;
398 
399       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
400       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
401       for (c = 0; c < coneSize; ++c) {
402         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
403           if (cone[c] == adj[q]) break;
404         }
405         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
406       }
407     }
408   }
409   *adjSize = numAdj;
410   PetscFunctionReturn(0);
411 }
412 
413 #undef __FUNCT__
414 #define __FUNCT__ "DMPlexGetAdjacency_Private"
415 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
416 {
417   const PetscInt *star  = tmpClosure;
418   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
419   PetscErrorCode  ierr;
420 
421   PetscFunctionBegin;
422   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
423   for (s = 2; s < starSize*2; s += 2) {
424     const PetscInt *closure = PETSC_NULL;
425     PetscInt        closureSize, c, q;
426 
427     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
428     for (c = 0; c < closureSize*2; c += 2) {
429       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
430         if (closure[c] == adj[q]) break;
431       }
432       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
433     }
434     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
435   }
436   *adjSize = numAdj;
437   PetscFunctionReturn(0);
438 }
439 
440 #undef __FUNCT__
441 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
442 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
443 {
444   DM_Plex *mesh = (DM_Plex*) dm->data;
445 
446   PetscFunctionBegin;
447   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
448   mesh->preallocCenterDim = preallocCenterDim;
449   PetscFunctionReturn(0);
450 }
451 
452 #undef __FUNCT__
453 #define __FUNCT__ "DMPlexPreallocateOperator"
454 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
455 {
456   DM_Plex           *mesh = (DM_Plex*) dm->data;
457   MPI_Comm           comm  = ((PetscObject) dm)->comm;
458   PetscSF            sf, sfDof, sfAdj;
459   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
460   PetscInt           nleaves, l, p;
461   const PetscInt    *leaves;
462   const PetscSFNode *remotes;
463   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
464   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
465   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
466   PetscLayout        rLayout;
467   PetscInt           locRows, rStart, rEnd, r;
468   PetscMPIInt        size;
469   PetscBool          useClosure, debug = PETSC_FALSE;
470   PetscErrorCode     ierr;
471 
472   PetscFunctionBegin;
473   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
474   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
475   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
476   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
477   /* Create dof SF based on point SF */
478   if (debug) {
479     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
480     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
481     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
485   }
486   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
487   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
488   if (debug) {
489     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
490     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
491   }
492   /* Create section for dof adjacency (dof ==> # adj dof) */
493   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
494   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
495   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
496   if (mesh->preallocCenterDim == dim) {
497     useClosure = PETSC_FALSE;
498   } else if (mesh->preallocCenterDim == 0) {
499     useClosure = PETSC_TRUE;
500   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
501 
502   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
503   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
504   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
505   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
508   /*   Fill in the ghost dofs on the interface */
509   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
510   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
511   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
512 
513   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
514   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
515 
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) rootAdj[r] = -1;
639   if (size > 1) {
640     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
641     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
642   }
643   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
644   ierr = PetscFree(adj);CHKERRQ(ierr);
645   /* Debugging */
646   if (debug) {
647     IS tmp;
648     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
649     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
650     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
651   }
652   /* Add in local adjacency indices for owned dofs on interface (roots) */
653   for (p = pStart; p < pEnd; ++p) {
654     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
655 
656     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
657     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
658     if (!dof) continue;
659     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
660     if (adof <= 0) continue;
661     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
662     for (d = off; d < off+dof; ++d) {
663       PetscInt adof, aoff, i;
664 
665       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
666       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
667       i    = adof-1;
668       for (q = 0; q < numAdj; ++q) {
669         PetscInt ndof, ncdof, ngoff, nd;
670 
671         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
672         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
673         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
674         for (nd = 0; nd < ndof-ncdof; ++nd) {
675           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
676           --i;
677         }
678       }
679     }
680   }
681   /* Debugging */
682   if (debug) {
683     IS tmp;
684     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
685     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
686     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
687   }
688   /* Compress indices */
689   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
690   for (p = pStart; p < pEnd; ++p) {
691     PetscInt dof, cdof, off, d;
692     PetscInt adof, aoff;
693 
694     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
695     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
696     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
697     if (!dof) continue;
698     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
699     if (adof <= 0) continue;
700     for (d = off; d < off+dof-cdof; ++d) {
701       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
702       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
703       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
704       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
705     }
706   }
707   /* Debugging */
708   if (debug) {
709     IS tmp;
710     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
711     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
712     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
713     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
714     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
715   }
716   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
717   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
718   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
719   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
720   for (p = pStart; p < pEnd; ++p) {
721     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
722     PetscBool found  = PETSC_TRUE;
723 
724     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
725     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
726     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
727     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
728     for (d = 0; d < dof-cdof; ++d) {
729       PetscInt ldof, rdof;
730 
731       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
732       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
733       if (ldof > 0) {
734         /* We do not own this point */
735       } else if (rdof > 0) {
736         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
737       } else {
738         found = PETSC_FALSE;
739       }
740     }
741     if (found) continue;
742     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
743     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
744     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
745     for (q = 0; q < numAdj; ++q) {
746       PetscInt ndof, ncdof, noff;
747 
748       /* Adjacent points may not be in the section chart */
749       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
750       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
751       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
752       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
753       for (d = goff; d < goff+dof-cdof; ++d) {
754         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
755       }
756     }
757   }
758   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
759   if (debug) {
760     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
761     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
762   }
763   /* Get adjacent indices */
764   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
765   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
766   for (p = pStart; p < pEnd; ++p) {
767     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
768     PetscBool found  = PETSC_TRUE;
769 
770     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
771     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
772     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
773     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
774     for (d = 0; d < dof-cdof; ++d) {
775       PetscInt ldof, rdof;
776 
777       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
778       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
779       if (ldof > 0) {
780         /* We do not own this point */
781       } else if (rdof > 0) {
782         PetscInt aoff, roff;
783 
784         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
785         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
786         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
787       } else {
788         found = PETSC_FALSE;
789       }
790     }
791     if (found) continue;
792     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
793     for (d = goff; d < goff+dof-cdof; ++d) {
794       PetscInt adof, aoff, i = 0;
795 
796       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
797       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
798       for (q = 0; q < numAdj; ++q) {
799         PetscInt        ndof, ncdof, ngoff, nd;
800         const PetscInt *ncind;
801 
802         /* Adjacent points may not be in the section chart */
803         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
804         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
805         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
806         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
807         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
808         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
809           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
810         }
811       }
812       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);
813     }
814   }
815   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
816   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
817   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
818   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
819   /* Debugging */
820   if (debug) {
821     IS tmp;
822     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
823     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
824     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
825   }
826   /* Create allocation vectors from adjacency graph */
827   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
828   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
829   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
830   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
831   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
832   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
833   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
834   /* Only loop over blocks of rows */
835   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);
836   for (r = rStart/bs; r < rEnd/bs; ++r) {
837     const PetscInt row = r*bs;
838     PetscInt       numCols, cStart, c;
839 
840     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
841     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
842     for (c = cStart; c < cStart+numCols; ++c) {
843       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
844         ++dnz[r-rStart];
845         if (cols[c] >= row) ++dnzu[r-rStart];
846       } else {
847         ++onz[r-rStart];
848         if (cols[c] >= row) ++onzu[r-rStart];
849       }
850     }
851   }
852   if (bs > 1) {
853     for (r = 0; r < locRows/bs; ++r) {
854       dnz[r]  /= bs;
855       onz[r]  /= bs;
856       dnzu[r] /= bs;
857       onzu[r] /= bs;
858     }
859   }
860   /* Set matrix pattern */
861   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
862   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
863   /* Fill matrix with zeros */
864   if (fillMatrix) {
865     PetscScalar *values;
866     PetscInt     maxRowLen = 0;
867 
868     for (r = rStart; r < rEnd; ++r) {
869       PetscInt len;
870 
871       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
872       maxRowLen = PetscMax(maxRowLen, len);
873     }
874     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
875     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
876     for (r = rStart; r < rEnd; ++r) {
877       PetscInt numCols, cStart;
878 
879       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
880       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
881       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
882     }
883     ierr = PetscFree(values);CHKERRQ(ierr);
884     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
885     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
886   }
887   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
888   ierr = PetscFree(cols);CHKERRQ(ierr);
889   PetscFunctionReturn(0);
890 }
891 
892 #if 0
893 #undef __FUNCT__
894 #define __FUNCT__ "DMPlexPreallocateOperator_2"
895 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
896 {
897   PetscInt       *tmpClosure,*tmpAdj,*visits;
898   PetscInt        c,cStart,cEnd,pStart,pEnd;
899   PetscErrorCode  ierr;
900 
901   PetscFunctionBegin;
902   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
903   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
904   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
905 
906   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
907 
908   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910 
911   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
912   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
914   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
915   for (c=cStart; c<cEnd; c++) {
916     PetscInt *support = tmpClosure;
917     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
918     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
919   }
920   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
921   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
923   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924 
925   ierr = PetscSFGetRanks();CHKERRQ(ierr);
926 
927 
928   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
929   for (c=cStart; c<cEnd; c++) {
930     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
931     /*
932      Depth-first walk of transitive closure.
933      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.
934      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
935      */
936   }
937 
938   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
939   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
940   PetscFunctionReturn(0);
941 }
942 #endif
943 
944 #undef __FUNCT__
945 #define __FUNCT__ "DMCreateMatrix_Plex"
946 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
947 {
948   PetscSection   section, sectionGlobal;
949   PetscInt       bs = -1;
950   PetscInt       localSize;
951   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
952   PetscErrorCode ierr;
953 
954   PetscFunctionBegin;
955 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
956   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
957 #endif
958   if (!mtype) mtype = MATAIJ;
959   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
960   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
961   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
962   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
963   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
964   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
965   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
966   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
967   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
974   /* Check for symmetric storage */
975   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
976   if (isSymmetric) {
977     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
978   }
979   if (!isShell) {
980     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
981     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
982 
983     if (bs < 0) {
984       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
985         PetscInt pStart, pEnd, p, dof, cdof;
986 
987         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
988         for (p = pStart; p < pEnd; ++p) {
989           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
990           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
991           if (dof-cdof) {
992             if (bs < 0) {
993               bs = dof-cdof;
994             } else if (bs != dof-cdof) {
995               /* Layout does not admit a pointwise block size */
996               bs = 1;
997               break;
998             }
999           }
1000         }
1001         /* Must have same blocksize on all procs (some might have no points) */
1002         bsLocal = bs;
1003         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1004         bsLocal = bs < 0 ? bsMax : bs;
1005         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1006         if (bsMin != bsMax) {
1007           bs = 1;
1008         } else {
1009           bs = bsMax;
1010         }
1011       } else {
1012         bs = 1;
1013       }
1014     }
1015     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1016     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1017     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1018     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1019     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1020     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1021     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1022   }
1023   PetscFunctionReturn(0);
1024 }
1025 
1026 #undef __FUNCT__
1027 #define __FUNCT__ "DMPlexGetDimension"
1028 /*@
1029   DMPlexGetDimension - Return the topological mesh dimension
1030 
1031   Not collective
1032 
1033   Input Parameter:
1034 . mesh - The DMPlex
1035 
1036   Output Parameter:
1037 . dim - The topological mesh dimension
1038 
1039   Level: beginner
1040 
1041 .seealso: DMPlexCreate()
1042 @*/
1043 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1044 {
1045   DM_Plex *mesh = (DM_Plex*) dm->data;
1046 
1047   PetscFunctionBegin;
1048   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1049   PetscValidPointer(dim, 2);
1050   *dim = mesh->dim;
1051   PetscFunctionReturn(0);
1052 }
1053 
1054 #undef __FUNCT__
1055 #define __FUNCT__ "DMPlexSetDimension"
1056 /*@
1057   DMPlexSetDimension - Set the topological mesh dimension
1058 
1059   Collective on mesh
1060 
1061   Input Parameters:
1062 + mesh - The DMPlex
1063 - dim - The topological mesh dimension
1064 
1065   Level: beginner
1066 
1067 .seealso: DMPlexCreate()
1068 @*/
1069 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1070 {
1071   DM_Plex *mesh = (DM_Plex*) dm->data;
1072 
1073   PetscFunctionBegin;
1074   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1075   PetscValidLogicalCollectiveInt(dm, dim, 2);
1076   mesh->dim               = dim;
1077   mesh->preallocCenterDim = dim;
1078   PetscFunctionReturn(0);
1079 }
1080 
1081 #undef __FUNCT__
1082 #define __FUNCT__ "DMPlexGetChart"
1083 /*@
1084   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1085 
1086   Not collective
1087 
1088   Input Parameter:
1089 . mesh - The DMPlex
1090 
1091   Output Parameters:
1092 + pStart - The first mesh point
1093 - pEnd   - The upper bound for mesh points
1094 
1095   Level: beginner
1096 
1097 .seealso: DMPlexCreate(), DMPlexSetChart()
1098 @*/
1099 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1100 {
1101   DM_Plex       *mesh = (DM_Plex*) dm->data;
1102   PetscErrorCode ierr;
1103 
1104   PetscFunctionBegin;
1105   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1106   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1107   PetscFunctionReturn(0);
1108 }
1109 
1110 #undef __FUNCT__
1111 #define __FUNCT__ "DMPlexSetChart"
1112 /*@
1113   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1114 
1115   Not collective
1116 
1117   Input Parameters:
1118 + mesh - The DMPlex
1119 . pStart - The first mesh point
1120 - pEnd   - The upper bound for mesh points
1121 
1122   Output Parameters:
1123 
1124   Level: beginner
1125 
1126 .seealso: DMPlexCreate(), DMPlexGetChart()
1127 @*/
1128 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1129 {
1130   DM_Plex       *mesh = (DM_Plex*) dm->data;
1131   PetscErrorCode ierr;
1132 
1133   PetscFunctionBegin;
1134   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1135   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1136   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1137   PetscFunctionReturn(0);
1138 }
1139 
1140 #undef __FUNCT__
1141 #define __FUNCT__ "DMPlexGetConeSize"
1142 /*@
1143   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1144 
1145   Not collective
1146 
1147   Input Parameters:
1148 + mesh - The DMPlex
1149 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1150 
1151   Output Parameter:
1152 . size - The cone size for point p
1153 
1154   Level: beginner
1155 
1156 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1157 @*/
1158 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1159 {
1160   DM_Plex       *mesh = (DM_Plex*) dm->data;
1161   PetscErrorCode ierr;
1162 
1163   PetscFunctionBegin;
1164   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1165   PetscValidPointer(size, 3);
1166   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1167   PetscFunctionReturn(0);
1168 }
1169 
1170 #undef __FUNCT__
1171 #define __FUNCT__ "DMPlexSetConeSize"
1172 /*@
1173   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1174 
1175   Not collective
1176 
1177   Input Parameters:
1178 + mesh - The DMPlex
1179 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1180 - size - The cone size for point p
1181 
1182   Output Parameter:
1183 
1184   Note:
1185   This should be called after DMPlexSetChart().
1186 
1187   Level: beginner
1188 
1189 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1190 @*/
1191 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1192 {
1193   DM_Plex       *mesh = (DM_Plex*) dm->data;
1194   PetscErrorCode ierr;
1195 
1196   PetscFunctionBegin;
1197   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1198   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1199 
1200   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1201   PetscFunctionReturn(0);
1202 }
1203 
1204 #undef __FUNCT__
1205 #define __FUNCT__ "DMPlexGetCone"
1206 /*@C
1207   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1208 
1209   Not collective
1210 
1211   Input Parameters:
1212 + mesh - The DMPlex
1213 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1214 
1215   Output Parameter:
1216 . cone - An array of points which are on the in-edges for point p
1217 
1218   Level: beginner
1219 
1220   Note:
1221   This routine is not available in Fortran.
1222 
1223 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1224 @*/
1225 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1226 {
1227   DM_Plex       *mesh = (DM_Plex*) dm->data;
1228   PetscInt       off;
1229   PetscErrorCode ierr;
1230 
1231   PetscFunctionBegin;
1232   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1233   PetscValidPointer(cone, 3);
1234   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1235   *cone = &mesh->cones[off];
1236   PetscFunctionReturn(0);
1237 }
1238 
1239 #undef __FUNCT__
1240 #define __FUNCT__ "DMPlexSetCone"
1241 /*@
1242   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1243 
1244   Not collective
1245 
1246   Input Parameters:
1247 + mesh - The DMPlex
1248 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1249 - cone - An array of points which are on the in-edges for point p
1250 
1251   Output Parameter:
1252 
1253   Note:
1254   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1255 
1256   Level: beginner
1257 
1258 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1259 @*/
1260 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1261 {
1262   DM_Plex       *mesh = (DM_Plex*) dm->data;
1263   PetscInt       pStart, pEnd;
1264   PetscInt       dof, off, c;
1265   PetscErrorCode ierr;
1266 
1267   PetscFunctionBegin;
1268   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1269   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1270   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1271   if (dof) PetscValidPointer(cone, 3);
1272   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1273   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);
1274   for (c = 0; c < dof; ++c) {
1275     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);
1276     mesh->cones[off+c] = cone[c];
1277   }
1278   PetscFunctionReturn(0);
1279 }
1280 
1281 #undef __FUNCT__
1282 #define __FUNCT__ "DMPlexGetConeOrientation"
1283 /*@C
1284   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1285 
1286   Not collective
1287 
1288   Input Parameters:
1289 + mesh - The DMPlex
1290 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1291 
1292   Output Parameter:
1293 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1294                     integer giving the prescription for cone traversal. If it is negative, the cone is
1295                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1296                     the index of the cone point on which to start.
1297 
1298   Level: beginner
1299 
1300   Note:
1301   This routine is not available in Fortran.
1302 
1303 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1304 @*/
1305 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1306 {
1307   DM_Plex       *mesh = (DM_Plex*) dm->data;
1308   PetscInt       off;
1309   PetscErrorCode ierr;
1310 
1311   PetscFunctionBegin;
1312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1313 #if defined(PETSC_USE_DEBUG)
1314   {
1315     PetscInt dof;
1316     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1317     if (dof) PetscValidPointer(coneOrientation, 3);
1318   }
1319 #endif
1320   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1321 
1322   *coneOrientation = &mesh->coneOrientations[off];
1323   PetscFunctionReturn(0);
1324 }
1325 
1326 #undef __FUNCT__
1327 #define __FUNCT__ "DMPlexSetConeOrientation"
1328 /*@
1329   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1330 
1331   Not collective
1332 
1333   Input Parameters:
1334 + mesh - The DMPlex
1335 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1336 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1337                     integer giving the prescription for cone traversal. If it is negative, the cone is
1338                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1339                     the index of the cone point on which to start.
1340 
1341   Output Parameter:
1342 
1343   Note:
1344   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1345 
1346   Level: beginner
1347 
1348 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1349 @*/
1350 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1351 {
1352   DM_Plex       *mesh = (DM_Plex*) dm->data;
1353   PetscInt       pStart, pEnd;
1354   PetscInt       dof, off, c;
1355   PetscErrorCode ierr;
1356 
1357   PetscFunctionBegin;
1358   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1359   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1360   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1361   if (dof) PetscValidPointer(coneOrientation, 3);
1362   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1363   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);
1364   for (c = 0; c < dof; ++c) {
1365     PetscInt cdof, o = coneOrientation[c];
1366 
1367     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1368     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);
1369     mesh->coneOrientations[off+c] = o;
1370   }
1371   PetscFunctionReturn(0);
1372 }
1373 
1374 #undef __FUNCT__
1375 #define __FUNCT__ "DMPlexInsertCone"
1376 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1377 {
1378   DM_Plex       *mesh = (DM_Plex*) dm->data;
1379   PetscInt       pStart, pEnd;
1380   PetscInt       dof, off;
1381   PetscErrorCode ierr;
1382 
1383   PetscFunctionBegin;
1384   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1385   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1386   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1387   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1388   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);
1389   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);
1390   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);
1391   mesh->cones[off+conePos] = conePoint;
1392   PetscFunctionReturn(0);
1393 }
1394 
1395 #undef __FUNCT__
1396 #define __FUNCT__ "DMPlexGetSupportSize"
1397 /*@
1398   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1399 
1400   Not collective
1401 
1402   Input Parameters:
1403 + mesh - The DMPlex
1404 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1405 
1406   Output Parameter:
1407 . size - The support size for point p
1408 
1409   Level: beginner
1410 
1411 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1412 @*/
1413 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1414 {
1415   DM_Plex       *mesh = (DM_Plex*) dm->data;
1416   PetscErrorCode ierr;
1417 
1418   PetscFunctionBegin;
1419   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1420   PetscValidPointer(size, 3);
1421   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1422   PetscFunctionReturn(0);
1423 }
1424 
1425 #undef __FUNCT__
1426 #define __FUNCT__ "DMPlexSetSupportSize"
1427 /*@
1428   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1429 
1430   Not collective
1431 
1432   Input Parameters:
1433 + mesh - The DMPlex
1434 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1435 - size - The support size for point p
1436 
1437   Output Parameter:
1438 
1439   Note:
1440   This should be called after DMPlexSetChart().
1441 
1442   Level: beginner
1443 
1444 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1445 @*/
1446 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1447 {
1448   DM_Plex       *mesh = (DM_Plex*) dm->data;
1449   PetscErrorCode ierr;
1450 
1451   PetscFunctionBegin;
1452   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1453   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1454 
1455   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1456   PetscFunctionReturn(0);
1457 }
1458 
1459 #undef __FUNCT__
1460 #define __FUNCT__ "DMPlexGetSupport"
1461 /*@C
1462   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1463 
1464   Not collective
1465 
1466   Input Parameters:
1467 + mesh - The DMPlex
1468 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1469 
1470   Output Parameter:
1471 . support - An array of points which are on the out-edges for point p
1472 
1473   Level: beginner
1474 
1475 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1476 @*/
1477 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1478 {
1479   DM_Plex       *mesh = (DM_Plex*) dm->data;
1480   PetscInt       off;
1481   PetscErrorCode ierr;
1482 
1483   PetscFunctionBegin;
1484   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1485   PetscValidPointer(support, 3);
1486   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1487   *support = &mesh->supports[off];
1488   PetscFunctionReturn(0);
1489 }
1490 
1491 #undef __FUNCT__
1492 #define __FUNCT__ "DMPlexSetSupport"
1493 /*@
1494   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1495 
1496   Not collective
1497 
1498   Input Parameters:
1499 + mesh - The DMPlex
1500 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1501 - support - An array of points which are on the in-edges for point p
1502 
1503   Output Parameter:
1504 
1505   Note:
1506   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1507 
1508   Level: beginner
1509 
1510 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1511 @*/
1512 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1513 {
1514   DM_Plex       *mesh = (DM_Plex*) dm->data;
1515   PetscInt       pStart, pEnd;
1516   PetscInt       dof, off, c;
1517   PetscErrorCode ierr;
1518 
1519   PetscFunctionBegin;
1520   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1521   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1522   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1523   if (dof) PetscValidPointer(support, 3);
1524   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1525   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);
1526   for (c = 0; c < dof; ++c) {
1527     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);
1528     mesh->supports[off+c] = support[c];
1529   }
1530   PetscFunctionReturn(0);
1531 }
1532 
1533 #undef __FUNCT__
1534 #define __FUNCT__ "DMPlexInsertSupport"
1535 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1536 {
1537   DM_Plex       *mesh = (DM_Plex*) dm->data;
1538   PetscInt       pStart, pEnd;
1539   PetscInt       dof, off;
1540   PetscErrorCode ierr;
1541 
1542   PetscFunctionBegin;
1543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1544   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1545   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1546   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1547   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);
1548   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);
1549   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);
1550   mesh->supports[off+supportPos] = supportPoint;
1551   PetscFunctionReturn(0);
1552 }
1553 
1554 #undef __FUNCT__
1555 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1556 /*@C
1557   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1558 
1559   Not collective
1560 
1561   Input Parameters:
1562 + mesh - The DMPlex
1563 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1564 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1565 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1566 
1567   Output Parameters:
1568 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1569 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1570 
1571   Note:
1572   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1573 
1574   Level: beginner
1575 
1576 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1577 @*/
1578 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1579 {
1580   DM_Plex        *mesh = (DM_Plex*) dm->data;
1581   PetscInt       *closure, *fifo;
1582   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1583   PetscInt        tmpSize, t;
1584   PetscInt        depth       = 0, maxSize;
1585   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1586   PetscErrorCode  ierr;
1587 
1588   PetscFunctionBegin;
1589   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1590   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1591   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1592   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1593   if (*points) {
1594     closure = *points;
1595   } else {
1596     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1597   }
1598   closure[0] = p; closure[1] = 0;
1599   /* This is only 1-level */
1600   if (useCone) {
1601     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1602     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1603     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1604   } else {
1605     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1606     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1607   }
1608   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1609     const PetscInt cp = tmp[t];
1610     const PetscInt co = tmpO ? tmpO[t] : 0;
1611 
1612     closure[closureSize]   = cp;
1613     closure[closureSize+1] = co;
1614     fifo[fifoSize]         = cp;
1615     fifo[fifoSize+1]       = co;
1616   }
1617   while (fifoSize - fifoStart) {
1618     const PetscInt q   = fifo[fifoStart];
1619     const PetscInt o   = fifo[fifoStart+1];
1620     const PetscInt rev = o >= 0 ? 0 : 1;
1621     const PetscInt off = rev ? -(o+1) : o;
1622 
1623     if (useCone) {
1624       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1625       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1626       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1627     } else {
1628       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1629       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1630       tmpO = PETSC_NULL;
1631     }
1632     for (t = 0; t < tmpSize; ++t) {
1633       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1634       const PetscInt cp = tmp[i];
1635       /* Must propogate orientation */
1636       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1637       PetscInt       c;
1638 
1639       /* Check for duplicate */
1640       for (c = 0; c < closureSize; c += 2) {
1641         if (closure[c] == cp) break;
1642       }
1643       if (c == closureSize) {
1644         closure[closureSize]   = cp;
1645         closure[closureSize+1] = co;
1646         fifo[fifoSize]         = cp;
1647         fifo[fifoSize+1]       = co;
1648         closureSize           += 2;
1649         fifoSize              += 2;
1650       }
1651     }
1652     fifoStart += 2;
1653   }
1654   if (numPoints) *numPoints = closureSize/2;
1655   if (points)    *points    = closure;
1656   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1657   PetscFunctionReturn(0);
1658 }
1659 
1660 #undef __FUNCT__
1661 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1662 /*@C
1663   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1664 
1665   Not collective
1666 
1667   Input Parameters:
1668 + mesh - The DMPlex
1669 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1670 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1671 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1672 
1673   Output Parameters:
1674 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1675 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1676 
1677   Note:
1678   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1679 
1680   Level: beginner
1681 
1682 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1683 @*/
1684 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1685 {
1686   PetscErrorCode ierr;
1687 
1688   PetscFunctionBegin;
1689   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1690   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1691   PetscFunctionReturn(0);
1692 }
1693 
1694 #undef __FUNCT__
1695 #define __FUNCT__ "DMPlexGetFaces"
1696 /*
1697   DMPlexGetFaces -
1698 
1699   Note: This will only work for cell-vertex meshes.
1700 */
1701 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1702 {
1703   DM_Plex        *mesh = (DM_Plex*) dm->data;
1704   const PetscInt *cone = PETSC_NULL;
1705   PetscInt        depth = 0, dim, coneSize;
1706   PetscErrorCode  ierr;
1707 
1708   PetscFunctionBegin;
1709   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1710   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1711   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1712   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1713   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1714   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1715   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1716   switch (dim) {
1717   case 2:
1718     switch (coneSize) {
1719     case 3:
1720       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1721       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1722       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1723       *numFaces         = 3;
1724       *faceSize         = 2;
1725       *faces            = mesh->facesTmp;
1726       break;
1727     case 4:
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[3];
1731       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1732       *numFaces         = 4;
1733       *faceSize         = 2;
1734       *faces            = mesh->facesTmp;
1735       break;
1736     default:
1737       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1738     }
1739     break;
1740   case 3:
1741     switch (coneSize) {
1742     case 3:
1743       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1744       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1745       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1746       *numFaces         = 3;
1747       *faceSize         = 2;
1748       *faces            = mesh->facesTmp;
1749       break;
1750     case 4:
1751       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1752       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1753       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1754       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1755       *numFaces         = 4;
1756       *faceSize         = 3;
1757       *faces            = mesh->facesTmp;
1758       break;
1759     default:
1760       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1761     }
1762     break;
1763   default:
1764     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1765   }
1766   PetscFunctionReturn(0);
1767 }
1768 
1769 #undef __FUNCT__
1770 #define __FUNCT__ "DMPlexGetMaxSizes"
1771 /*@
1772   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1773 
1774   Not collective
1775 
1776   Input Parameter:
1777 . mesh - The DMPlex
1778 
1779   Output Parameters:
1780 + maxConeSize - The maximum number of in-edges
1781 - maxSupportSize - The maximum number of out-edges
1782 
1783   Level: beginner
1784 
1785 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1786 @*/
1787 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1788 {
1789   DM_Plex *mesh = (DM_Plex*) dm->data;
1790 
1791   PetscFunctionBegin;
1792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1793   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1794   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1795   PetscFunctionReturn(0);
1796 }
1797 
1798 #undef __FUNCT__
1799 #define __FUNCT__ "DMSetUp_Plex"
1800 PetscErrorCode DMSetUp_Plex(DM dm)
1801 {
1802   DM_Plex       *mesh = (DM_Plex*) dm->data;
1803   PetscInt       size;
1804   PetscErrorCode ierr;
1805 
1806   PetscFunctionBegin;
1807   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1808   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1809   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1810   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1811   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1812   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1813   if (mesh->maxSupportSize) {
1814     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1815     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1816     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1817   }
1818   PetscFunctionReturn(0);
1819 }
1820 
1821 #undef __FUNCT__
1822 #define __FUNCT__ "DMCreateSubDM_Plex"
1823 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1824 {
1825   PetscSection   section, sectionGlobal;
1826   PetscInt      *subIndices;
1827   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1828   PetscErrorCode ierr;
1829 
1830   PetscFunctionBegin;
1831   if (!numFields) PetscFunctionReturn(0);
1832   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1833   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1834   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1835   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1836   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1837   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);
1838   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1839   for (p = pStart; p < pEnd; ++p) {
1840     PetscInt gdof;
1841 
1842     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1843     if (gdof > 0) {
1844       for (f = 0; f < numFields; ++f) {
1845         PetscInt fdof, fcdof;
1846 
1847         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1848         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1849         subSize += fdof-fcdof;
1850       }
1851     }
1852   }
1853   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1854   for (p = pStart; p < pEnd; ++p) {
1855     PetscInt gdof, goff;
1856 
1857     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1858     if (gdof > 0) {
1859       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1860       for (f = 0; f < numFields; ++f) {
1861         PetscInt fdof, fcdof, fc, f2, poff = 0;
1862 
1863         /* Can get rid of this loop by storing field information in the global section */
1864         for (f2 = 0; f2 < fields[f]; ++f2) {
1865           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1866           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1867           poff += fdof-fcdof;
1868         }
1869         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1870         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1871         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1872           subIndices[subOff] = goff+poff+fc;
1873         }
1874       }
1875     }
1876   }
1877   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1878   if (subdm) {
1879     PetscSection subsection;
1880     PetscBool    haveNull = PETSC_FALSE;
1881     PetscInt     f, nf = 0;
1882 
1883     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1884     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1885     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1886     for (f = 0; f < numFields; ++f) {
1887       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1888       if ((*subdm)->nullspaceConstructors[f]) {
1889         haveNull = PETSC_TRUE;
1890         nf       = f;
1891       }
1892     }
1893     if (haveNull) {
1894       MatNullSpace nullSpace;
1895 
1896       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1897       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1898       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1899     }
1900     if (dm->fields) {
1901       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);
1902       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1903       for (f = 0; f < numFields; ++f) {
1904         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1905       }
1906       if (numFields == 1) {
1907         MatNullSpace space;
1908         Mat          pmat;
1909 
1910         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1911         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1912         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1913         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1914         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1915         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1916       }
1917     }
1918   }
1919   PetscFunctionReturn(0);
1920 }
1921 
1922 #undef __FUNCT__
1923 #define __FUNCT__ "DMPlexSymmetrize"
1924 /*@
1925   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1926 
1927   Not collective
1928 
1929   Input Parameter:
1930 . mesh - The DMPlex
1931 
1932   Output Parameter:
1933 
1934   Note:
1935   This should be called after all calls to DMPlexSetCone()
1936 
1937   Level: beginner
1938 
1939 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1940 @*/
1941 PetscErrorCode DMPlexSymmetrize(DM dm)
1942 {
1943   DM_Plex       *mesh = (DM_Plex*) dm->data;
1944   PetscInt      *offsets;
1945   PetscInt       supportSize;
1946   PetscInt       pStart, pEnd, p;
1947   PetscErrorCode ierr;
1948 
1949   PetscFunctionBegin;
1950   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1951   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1952   /* Calculate support sizes */
1953   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1954   for (p = pStart; p < pEnd; ++p) {
1955     PetscInt dof, off, c;
1956 
1957     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1958     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1959     for (c = off; c < off+dof; ++c) {
1960       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1961     }
1962   }
1963   for (p = pStart; p < pEnd; ++p) {
1964     PetscInt dof;
1965 
1966     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1967 
1968     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1969   }
1970   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1971   /* Calculate supports */
1972   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1973   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1974   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1975   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1976   for (p = pStart; p < pEnd; ++p) {
1977     PetscInt dof, off, c;
1978 
1979     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1980     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1981     for (c = off; c < off+dof; ++c) {
1982       const PetscInt q = mesh->cones[c];
1983       PetscInt       offS;
1984 
1985       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1986 
1987       mesh->supports[offS+offsets[q]] = p;
1988       ++offsets[q];
1989     }
1990   }
1991   ierr = PetscFree(offsets);CHKERRQ(ierr);
1992   PetscFunctionReturn(0);
1993 }
1994 
1995 #undef __FUNCT__
1996 #define __FUNCT__ "DMPlexSetDepth_Private"
1997 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1998 {
1999   PetscInt       d;
2000   PetscErrorCode ierr;
2001 
2002   PetscFunctionBegin;
2003   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2004   if (d < 0) {
2005     /* We are guaranteed that the point has a cone since the depth was not yet set */
2006     const PetscInt *cone = PETSC_NULL;
2007     PetscInt        dCone;
2008 
2009     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2010     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2011     d    = dCone+1;
2012     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2013   }
2014   *depth = d;
2015   PetscFunctionReturn(0);
2016 }
2017 
2018 #undef __FUNCT__
2019 #define __FUNCT__ "DMPlexStratify"
2020 /*@
2021   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2022   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2023   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2024   the DAG.
2025 
2026   Not collective
2027 
2028   Input Parameter:
2029 . mesh - The DMPlex
2030 
2031   Output Parameter:
2032 
2033   Notes:
2034   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2035   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2036 
2037   This should be called after all calls to DMPlexSymmetrize()
2038 
2039   Level: beginner
2040 
2041 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2042 @*/
2043 PetscErrorCode DMPlexStratify(DM dm)
2044 {
2045   DM_Plex       *mesh = (DM_Plex*) dm->data;
2046   PetscInt       pStart, pEnd, p;
2047   PetscInt       numRoots = 0, numLeaves = 0;
2048   PetscErrorCode ierr;
2049 
2050   PetscFunctionBegin;
2051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2052   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2053   /* Calculate depth */
2054   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2055   /* Initialize roots and count leaves */
2056   for (p = pStart; p < pEnd; ++p) {
2057     PetscInt coneSize, supportSize;
2058 
2059     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2060     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2061     if (!coneSize && supportSize) {
2062       ++numRoots;
2063       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2064     } else if (!supportSize && coneSize) {
2065       ++numLeaves;
2066     } else if (!supportSize && !coneSize) {
2067       /* Isolated points */
2068       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2069     }
2070   }
2071   if (numRoots + numLeaves == (pEnd - pStart)) {
2072     for (p = pStart; p < pEnd; ++p) {
2073       PetscInt coneSize, supportSize;
2074 
2075       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2076       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2077       if (!supportSize && coneSize) {
2078         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2079       }
2080     }
2081   } else {
2082     /* This might be slow since lookup is not fast */
2083     for (p = pStart; p < pEnd; ++p) {
2084       PetscInt depth;
2085 
2086       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2087     }
2088   }
2089   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2090   PetscFunctionReturn(0);
2091 }
2092 
2093 #undef __FUNCT__
2094 #define __FUNCT__ "DMPlexGetJoin"
2095 /*@C
2096   DMPlexGetJoin - Get an array for the join of the set of points
2097 
2098   Not Collective
2099 
2100   Input Parameters:
2101 + dm - The DMPlex object
2102 . numPoints - The number of input points for the join
2103 - points - The input points
2104 
2105   Output Parameters:
2106 + numCoveredPoints - The number of points in the join
2107 - coveredPoints - The points in the join
2108 
2109   Level: intermediate
2110 
2111   Note: Currently, this is restricted to a single level join
2112 
2113 .keywords: mesh
2114 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2115 @*/
2116 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2117 {
2118   DM_Plex       *mesh = (DM_Plex*) dm->data;
2119   PetscInt      *join[2];
2120   PetscInt       joinSize, i = 0;
2121   PetscInt       dof, off, p, c, m;
2122   PetscErrorCode ierr;
2123 
2124   PetscFunctionBegin;
2125   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2126   PetscValidPointer(points, 2);
2127   PetscValidPointer(numCoveredPoints, 3);
2128   PetscValidPointer(coveredPoints, 4);
2129   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2130   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2131   /* Copy in support of first point */
2132   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2133   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2134   for (joinSize = 0; joinSize < dof; ++joinSize) {
2135     join[i][joinSize] = mesh->supports[off+joinSize];
2136   }
2137   /* Check each successive support */
2138   for (p = 1; p < numPoints; ++p) {
2139     PetscInt newJoinSize = 0;
2140 
2141     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2142     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2143     for (c = 0; c < dof; ++c) {
2144       const PetscInt point = mesh->supports[off+c];
2145 
2146       for (m = 0; m < joinSize; ++m) {
2147         if (point == join[i][m]) {
2148           join[1-i][newJoinSize++] = point;
2149           break;
2150         }
2151       }
2152     }
2153     joinSize = newJoinSize;
2154     i        = 1-i;
2155   }
2156   *numCoveredPoints = joinSize;
2157   *coveredPoints    = join[i];
2158   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2159   PetscFunctionReturn(0);
2160 }
2161 
2162 #undef __FUNCT__
2163 #define __FUNCT__ "DMPlexRestoreJoin"
2164 /*@C
2165   DMPlexRestoreJoin - Restore an array for the join of the set of points
2166 
2167   Not Collective
2168 
2169   Input Parameters:
2170 + dm - The DMPlex object
2171 . numPoints - The number of input points for the join
2172 - points - The input points
2173 
2174   Output Parameters:
2175 + numCoveredPoints - The number of points in the join
2176 - coveredPoints - The points in the join
2177 
2178   Level: intermediate
2179 
2180 .keywords: mesh
2181 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2182 @*/
2183 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2184 {
2185   PetscErrorCode ierr;
2186 
2187   PetscFunctionBegin;
2188   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2189   PetscValidPointer(coveredPoints, 4);
2190   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2191   PetscFunctionReturn(0);
2192 }
2193 
2194 #undef __FUNCT__
2195 #define __FUNCT__ "DMPlexGetFullJoin"
2196 /*@C
2197   DMPlexGetFullJoin - Get an array for the join of the set of points
2198 
2199   Not Collective
2200 
2201   Input Parameters:
2202 + dm - The DMPlex object
2203 . numPoints - The number of input points for the join
2204 - points - The input points
2205 
2206   Output Parameters:
2207 + numCoveredPoints - The number of points in the join
2208 - coveredPoints - The points in the join
2209 
2210   Level: intermediate
2211 
2212 .keywords: mesh
2213 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2214 @*/
2215 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2216 {
2217   DM_Plex       *mesh = (DM_Plex*) dm->data;
2218   PetscInt      *offsets, **closures;
2219   PetscInt      *join[2];
2220   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2221   PetscInt       p, d, c, m;
2222   PetscErrorCode ierr;
2223 
2224   PetscFunctionBegin;
2225   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2226   PetscValidPointer(points, 2);
2227   PetscValidPointer(numCoveredPoints, 3);
2228   PetscValidPointer(coveredPoints, 4);
2229 
2230   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2231   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2232   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2233   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2234   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2235   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2236   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2237 
2238   for (p = 0; p < numPoints; ++p) {
2239     PetscInt closureSize;
2240 
2241     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2242 
2243     offsets[p*(depth+2)+0] = 0;
2244     for (d = 0; d < depth+1; ++d) {
2245       PetscInt pStart, pEnd, i;
2246 
2247       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2248       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2249         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2250           offsets[p*(depth+2)+d+1] = i;
2251           break;
2252         }
2253       }
2254       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2255     }
2256     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);
2257   }
2258   for (d = 0; d < depth+1; ++d) {
2259     PetscInt dof;
2260 
2261     /* Copy in support of first point */
2262     dof = offsets[d+1] - offsets[d];
2263     for (joinSize = 0; joinSize < dof; ++joinSize) {
2264       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2265     }
2266     /* Check each successive cone */
2267     for (p = 1; p < numPoints && joinSize; ++p) {
2268       PetscInt newJoinSize = 0;
2269 
2270       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2271       for (c = 0; c < dof; ++c) {
2272         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2273 
2274         for (m = 0; m < joinSize; ++m) {
2275           if (point == join[i][m]) {
2276             join[1-i][newJoinSize++] = point;
2277             break;
2278           }
2279         }
2280       }
2281       joinSize = newJoinSize;
2282       i        = 1-i;
2283     }
2284     if (joinSize) break;
2285   }
2286   *numCoveredPoints = joinSize;
2287   *coveredPoints    = join[i];
2288   for (p = 0; p < numPoints; ++p) {
2289     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2290   }
2291   ierr = PetscFree(closures);CHKERRQ(ierr);
2292   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2293   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2294   PetscFunctionReturn(0);
2295 }
2296 
2297 #undef __FUNCT__
2298 #define __FUNCT__ "DMPlexGetMeet"
2299 /*@C
2300   DMPlexGetMeet - Get an array for the meet of the set of points
2301 
2302   Not Collective
2303 
2304   Input Parameters:
2305 + dm - The DMPlex object
2306 . numPoints - The number of input points for the meet
2307 - points - The input points
2308 
2309   Output Parameters:
2310 + numCoveredPoints - The number of points in the meet
2311 - coveredPoints - The points in the meet
2312 
2313   Level: intermediate
2314 
2315   Note: Currently, this is restricted to a single level meet
2316 
2317 .keywords: mesh
2318 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2319 @*/
2320 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2321 {
2322   DM_Plex       *mesh = (DM_Plex*) dm->data;
2323   PetscInt      *meet[2];
2324   PetscInt       meetSize, i = 0;
2325   PetscInt       dof, off, p, c, m;
2326   PetscErrorCode ierr;
2327 
2328   PetscFunctionBegin;
2329   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2330   PetscValidPointer(points, 2);
2331   PetscValidPointer(numCoveringPoints, 3);
2332   PetscValidPointer(coveringPoints, 4);
2333   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2334   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2335   /* Copy in cone of first point */
2336   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2337   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2338   for (meetSize = 0; meetSize < dof; ++meetSize) {
2339     meet[i][meetSize] = mesh->cones[off+meetSize];
2340   }
2341   /* Check each successive cone */
2342   for (p = 1; p < numPoints; ++p) {
2343     PetscInt newMeetSize = 0;
2344 
2345     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2346     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2347     for (c = 0; c < dof; ++c) {
2348       const PetscInt point = mesh->cones[off+c];
2349 
2350       for (m = 0; m < meetSize; ++m) {
2351         if (point == meet[i][m]) {
2352           meet[1-i][newMeetSize++] = point;
2353           break;
2354         }
2355       }
2356     }
2357     meetSize = newMeetSize;
2358     i        = 1-i;
2359   }
2360   *numCoveringPoints = meetSize;
2361   *coveringPoints    = meet[i];
2362   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2363   PetscFunctionReturn(0);
2364 }
2365 
2366 #undef __FUNCT__
2367 #define __FUNCT__ "DMPlexRestoreMeet"
2368 /*@C
2369   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2370 
2371   Not Collective
2372 
2373   Input Parameters:
2374 + dm - The DMPlex object
2375 . numPoints - The number of input points for the meet
2376 - points - The input points
2377 
2378   Output Parameters:
2379 + numCoveredPoints - The number of points in the meet
2380 - coveredPoints - The points in the meet
2381 
2382   Level: intermediate
2383 
2384 .keywords: mesh
2385 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2386 @*/
2387 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2388 {
2389   PetscErrorCode ierr;
2390 
2391   PetscFunctionBegin;
2392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2393   PetscValidPointer(coveredPoints, 4);
2394   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2395   PetscFunctionReturn(0);
2396 }
2397 
2398 #undef __FUNCT__
2399 #define __FUNCT__ "DMPlexGetFullMeet"
2400 /*@C
2401   DMPlexGetFullMeet - Get an array for the meet of the set of points
2402 
2403   Not Collective
2404 
2405   Input Parameters:
2406 + dm - The DMPlex object
2407 . numPoints - The number of input points for the meet
2408 - points - The input points
2409 
2410   Output Parameters:
2411 + numCoveredPoints - The number of points in the meet
2412 - coveredPoints - The points in the meet
2413 
2414   Level: intermediate
2415 
2416 .keywords: mesh
2417 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2418 @*/
2419 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2420 {
2421   DM_Plex       *mesh = (DM_Plex*) dm->data;
2422   PetscInt      *offsets, **closures;
2423   PetscInt      *meet[2];
2424   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2425   PetscInt       p, h, c, m;
2426   PetscErrorCode ierr;
2427 
2428   PetscFunctionBegin;
2429   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2430   PetscValidPointer(points, 2);
2431   PetscValidPointer(numCoveredPoints, 3);
2432   PetscValidPointer(coveredPoints, 4);
2433 
2434   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2435   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2436   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2437   maxSize = PetscPowInt(mesh->maxConeSize,height);
2438   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2439   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2440 
2441   for (p = 0; p < numPoints; ++p) {
2442     PetscInt closureSize;
2443 
2444     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2445 
2446     offsets[p*(height+2)+0] = 0;
2447     for (h = 0; h < height+1; ++h) {
2448       PetscInt pStart, pEnd, i;
2449 
2450       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2451       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2452         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2453           offsets[p*(height+2)+h+1] = i;
2454           break;
2455         }
2456       }
2457       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2458     }
2459     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);
2460   }
2461   for (h = 0; h < height+1; ++h) {
2462     PetscInt dof;
2463 
2464     /* Copy in cone of first point */
2465     dof = offsets[h+1] - offsets[h];
2466     for (meetSize = 0; meetSize < dof; ++meetSize) {
2467       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2468     }
2469     /* Check each successive cone */
2470     for (p = 1; p < numPoints && meetSize; ++p) {
2471       PetscInt newMeetSize = 0;
2472 
2473       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2474       for (c = 0; c < dof; ++c) {
2475         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2476 
2477         for (m = 0; m < meetSize; ++m) {
2478           if (point == meet[i][m]) {
2479             meet[1-i][newMeetSize++] = point;
2480             break;
2481           }
2482         }
2483       }
2484       meetSize = newMeetSize;
2485       i        = 1-i;
2486     }
2487     if (meetSize) break;
2488   }
2489   *numCoveredPoints = meetSize;
2490   *coveredPoints    = meet[i];
2491   for (p = 0; p < numPoints; ++p) {
2492     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2493   }
2494   ierr = PetscFree(closures);CHKERRQ(ierr);
2495   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2496   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2497   PetscFunctionReturn(0);
2498 }
2499 
2500 #undef __FUNCT__
2501 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2502 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2503 {
2504   MPI_Comm       comm = ((PetscObject) dm)->comm;
2505   PetscInt       cellDim;
2506   PetscErrorCode ierr;
2507 
2508   PetscFunctionBegin;
2509   PetscValidPointer(numFaceVertices,3);
2510   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2511   switch (cellDim) {
2512   case 0:
2513     *numFaceVertices = 0;
2514     break;
2515   case 1:
2516     *numFaceVertices = 1;
2517     break;
2518   case 2:
2519     switch (numCorners) {
2520     case 3: /* triangle */
2521       *numFaceVertices = 2; /* Edge has 2 vertices */
2522       break;
2523     case 4: /* quadrilateral */
2524       *numFaceVertices = 2; /* Edge has 2 vertices */
2525       break;
2526     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2527       *numFaceVertices = 3; /* Edge has 3 vertices */
2528       break;
2529     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2530       *numFaceVertices = 3; /* Edge has 3 vertices */
2531       break;
2532     default:
2533       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2534     }
2535     break;
2536   case 3:
2537     switch (numCorners) {
2538     case 4: /* tetradehdron */
2539       *numFaceVertices = 3; /* Face has 3 vertices */
2540       break;
2541     case 6: /* tet cohesive cells */
2542       *numFaceVertices = 4; /* Face has 4 vertices */
2543       break;
2544     case 8: /* hexahedron */
2545       *numFaceVertices = 4; /* Face has 4 vertices */
2546       break;
2547     case 9: /* tet cohesive Lagrange cells */
2548       *numFaceVertices = 6; /* Face has 6 vertices */
2549       break;
2550     case 10: /* quadratic tetrahedron */
2551       *numFaceVertices = 6; /* Face has 6 vertices */
2552       break;
2553     case 12: /* hex cohesive Lagrange cells */
2554       *numFaceVertices = 6; /* Face has 6 vertices */
2555       break;
2556     case 18: /* quadratic tet cohesive Lagrange cells */
2557       *numFaceVertices = 6; /* Face has 6 vertices */
2558       break;
2559     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2560       *numFaceVertices = 9; /* Face has 9 vertices */
2561       break;
2562     default:
2563       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2564     }
2565     break;
2566   default:
2567     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2568   }
2569   PetscFunctionReturn(0);
2570 }
2571 
2572 #undef __FUNCT__
2573 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2574 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2575 {
2576   const PetscInt maxFaceCases = 30;
2577   PetscInt       numFaceCases = 0;
2578   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2579   PetscInt      *off, *adj;
2580   PetscInt      *neighborCells, *tmpClosure;
2581   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2582   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2583   PetscErrorCode ierr;
2584 
2585   PetscFunctionBegin;
2586   /* For parallel partitioning, I think you have to communicate supports */
2587   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2588   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2589   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2590   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2591   if (cEnd - cStart == 0) {
2592     if (numVertices) *numVertices = 0;
2593     if (offsets)   *offsets   = PETSC_NULL;
2594     if (adjacency) *adjacency = PETSC_NULL;
2595     PetscFunctionReturn(0);
2596   }
2597   numCells = cEnd - cStart;
2598   /* Setup face recognition */
2599   if (depth == 1) {
2600     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 */
2601 
2602     for (c = cStart; c < cEnd; ++c) {
2603       PetscInt corners;
2604 
2605       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2606       if (!cornersSeen[corners]) {
2607         PetscInt nFV;
2608 
2609         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2610         cornersSeen[corners] = 1;
2611 
2612         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2613 
2614         numFaceVertices[numFaceCases++] = nFV;
2615       }
2616     }
2617   }
2618   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2619   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2620   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2621   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2622   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2623   /* Count neighboring cells */
2624   for (cell = cStart; cell < cEnd; ++cell) {
2625     PetscInt numNeighbors = maxNeighbors, n;
2626 
2627     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2628     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2629     for (n = 0; n < numNeighbors; ++n) {
2630       PetscInt        cellPair[2];
2631       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2632       PetscInt        meetSize = 0;
2633       const PetscInt *meet    = PETSC_NULL;
2634 
2635       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2636       if (cellPair[0] == cellPair[1]) continue;
2637       if (!found) {
2638         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2639         if (meetSize) {
2640           PetscInt f;
2641 
2642           for (f = 0; f < numFaceCases; ++f) {
2643             if (numFaceVertices[f] == meetSize) {
2644               found = PETSC_TRUE;
2645               break;
2646             }
2647           }
2648         }
2649         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2650       }
2651       if (found) ++off[cell-cStart+1];
2652     }
2653   }
2654   /* Prefix sum */
2655   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2656 
2657   if (adjacency) {
2658     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2659     /* Get neighboring cells */
2660     for (cell = cStart; cell < cEnd; ++cell) {
2661       PetscInt numNeighbors = maxNeighbors, n;
2662       PetscInt cellOffset   = 0;
2663 
2664       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2665       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2666       for (n = 0; n < numNeighbors; ++n) {
2667         PetscInt        cellPair[2];
2668         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2669         PetscInt        meetSize = 0;
2670         const PetscInt *meet    = PETSC_NULL;
2671 
2672         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2673         if (cellPair[0] == cellPair[1]) continue;
2674         if (!found) {
2675           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2676           if (meetSize) {
2677             PetscInt f;
2678 
2679             for (f = 0; f < numFaceCases; ++f) {
2680               if (numFaceVertices[f] == meetSize) {
2681                 found = PETSC_TRUE;
2682                 break;
2683               }
2684             }
2685           }
2686           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2687         }
2688         if (found) {
2689           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2690           ++cellOffset;
2691         }
2692       }
2693     }
2694   }
2695   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2696   if (numVertices) *numVertices = numCells;
2697   if (offsets)   *offsets   = off;
2698   if (adjacency) *adjacency = adj;
2699   PetscFunctionReturn(0);
2700 }
2701 
2702 #if defined(PETSC_HAVE_CHACO)
2703 #if defined(PETSC_HAVE_UNISTD_H)
2704 #include <unistd.h>
2705 #endif
2706 /* Chaco does not have an include file */
2707 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2708                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2709                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2710                        int mesh_dims[3], double *goal, int global_method, int local_method,
2711                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2712 
2713 extern int FREE_GRAPH;
2714 
2715 #undef __FUNCT__
2716 #define __FUNCT__ "DMPlexPartition_Chaco"
2717 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2718 {
2719   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2720   MPI_Comm       comm           = ((PetscObject) dm)->comm;
2721   int            nvtxs          = numVertices; /* number of vertices in full graph */
2722   int           *vwgts          = NULL;   /* weights for all vertices */
2723   float         *ewgts          = NULL;   /* weights for all edges */
2724   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2725   char          *outassignname  = NULL;   /*  name of assignment output file */
2726   char          *outfilename    = NULL;   /* output file name */
2727   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2728   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2729   int            mesh_dims[3];            /* dimensions of mesh of processors */
2730   double        *goal          = NULL;    /* desired set sizes for each set */
2731   int            global_method = 1;       /* global partitioning algorithm */
2732   int            local_method  = 1;       /* local partitioning algorithm */
2733   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2734   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2735   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2736   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2737   long           seed          = 123636512; /* for random graph mutations */
2738   short int     *assignment;              /* Output partition */
2739   int            fd_stdout, fd_pipe[2];
2740   PetscInt      *points;
2741   PetscMPIInt    commSize;
2742   int            i, v, p;
2743   PetscErrorCode ierr;
2744 
2745   PetscFunctionBegin;
2746   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2747   if (!numVertices) {
2748     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2749     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2750     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2751     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2752     PetscFunctionReturn(0);
2753   }
2754   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2755   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2756 
2757   if (global_method == INERTIAL_METHOD) {
2758     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2759     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2760   }
2761   mesh_dims[0] = commSize;
2762   mesh_dims[1] = 1;
2763   mesh_dims[2] = 1;
2764   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2765   /* Chaco outputs to stdout. We redirect this to a buffer. */
2766   /* TODO: check error codes for UNIX calls */
2767 #if defined(PETSC_HAVE_UNISTD_H)
2768   {
2769     int piperet;
2770     piperet = pipe(fd_pipe);
2771     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2772     fd_stdout = dup(1);
2773     close(1);
2774     dup2(fd_pipe[1], 1);
2775   }
2776 #endif
2777   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2778                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2779                    vmax, ndims, eigtol, seed);
2780 #if defined(PETSC_HAVE_UNISTD_H)
2781   {
2782     char msgLog[10000];
2783     int  count;
2784 
2785     fflush(stdout);
2786     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2787     if (count < 0) count = 0;
2788     msgLog[count] = 0;
2789     close(1);
2790     dup2(fd_stdout, 1);
2791     close(fd_stdout);
2792     close(fd_pipe[0]);
2793     close(fd_pipe[1]);
2794     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2795   }
2796 #endif
2797   /* Convert to PetscSection+IS */
2798   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2799   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2800   for (v = 0; v < nvtxs; ++v) {
2801     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2802   }
2803   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2804   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2805   for (p = 0, i = 0; p < commSize; ++p) {
2806     for (v = 0; v < nvtxs; ++v) {
2807       if (assignment[v] == p) points[i++] = v;
2808     }
2809   }
2810   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2811   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2812   if (global_method == INERTIAL_METHOD) {
2813     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2814   }
2815   ierr = PetscFree(assignment);CHKERRQ(ierr);
2816   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2817   PetscFunctionReturn(0);
2818 }
2819 #endif
2820 
2821 #if defined(PETSC_HAVE_PARMETIS)
2822 #undef __FUNCT__
2823 #define __FUNCT__ "DMPlexPartition_ParMetis"
2824 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2825 {
2826   PetscFunctionBegin;
2827   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2828   PetscFunctionReturn(0);
2829 }
2830 #endif
2831 
2832 #undef __FUNCT__
2833 #define __FUNCT__ "DMPlexEnlargePartition"
2834 /* Expand the partition by BFS on the adjacency graph */
2835 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2836 {
2837   PetscHashI      h;
2838   const PetscInt *points;
2839   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2840   PetscInt        pStart, pEnd, part, q;
2841   PetscErrorCode  ierr;
2842 
2843   PetscFunctionBegin;
2844   PetscHashICreate(h);
2845   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2846   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2847   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2848   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2849   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2850   for (part = pStart; part < pEnd; ++part) {
2851     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2852 
2853     PetscHashIClear(h);
2854     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2855     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2856     /* Add all existing points to h */
2857     for (p = 0; p < numPoints; ++p) {
2858       const PetscInt point = points[off+p];
2859       PetscHashIAdd(h, point, 1);
2860     }
2861     PetscHashISize(h, nP);
2862     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2863     /* Add all points in next BFS level */
2864     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2865     for (p = 0; p < numPoints; ++p) {
2866       const PetscInt point = points[off+p];
2867       PetscInt       s     = start[point], e = start[point+1], a;
2868 
2869       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2870     }
2871     PetscHashISize(h, numNewPoints);
2872     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2873     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2874     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2875     totPoints += numNewPoints;
2876   }
2877   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2878   PetscHashIDestroy(h);
2879   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2880   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2881   for (part = pStart, q = 0; part < pEnd; ++part) {
2882     PetscInt numPoints, p;
2883 
2884     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2885     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2886     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2887   }
2888   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2889   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2890   PetscFunctionReturn(0);
2891 }
2892 
2893 #undef __FUNCT__
2894 #define __FUNCT__ "DMPlexCreatePartition"
2895 /*
2896   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2897 
2898   Collective on DM
2899 
2900   Input Parameters:
2901   + dm - The DM
2902   . height - The height for points in the partition
2903   - enlarge - Expand each partition with neighbors
2904 
2905   Output Parameters:
2906   + partSection - The PetscSection giving the division of points by partition
2907   . partition - The list of points by partition
2908   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2909   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2910 
2911   Level: developer
2912 
2913 .seealso DMPlexDistribute()
2914 */
2915 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2916 {
2917   PetscMPIInt    size;
2918   PetscErrorCode ierr;
2919 
2920   PetscFunctionBegin;
2921   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2922 
2923   *origPartSection = PETSC_NULL;
2924   *origPartition   = PETSC_NULL;
2925   if (size == 1) {
2926     PetscInt *points;
2927     PetscInt  cStart, cEnd, c;
2928 
2929     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2930     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2931     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2932     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2933     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2934     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2935     for (c = cStart; c < cEnd; ++c) points[c] = c;
2936     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2937     PetscFunctionReturn(0);
2938   }
2939   if (height == 0) {
2940     PetscInt  numVertices;
2941     PetscInt *start     = PETSC_NULL;
2942     PetscInt *adjacency = PETSC_NULL;
2943 
2944     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2945     if (1) {
2946 #if defined(PETSC_HAVE_CHACO)
2947       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2948 #endif
2949     } else {
2950 #if defined(PETSC_HAVE_PARMETIS)
2951       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2952 #endif
2953     }
2954     if (enlarge) {
2955       *origPartSection = *partSection;
2956       *origPartition   = *partition;
2957 
2958       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2959     }
2960     ierr = PetscFree(start);CHKERRQ(ierr);
2961     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2962 # if 0
2963   } else if (height == 1) {
2964     /* Build the dual graph for faces and partition the hypergraph */
2965     PetscInt numEdges;
2966 
2967     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2968     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2969     destroyCSR(numEdges, start, adjacency);
2970 #endif
2971   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2972   PetscFunctionReturn(0);
2973 }
2974 
2975 #undef __FUNCT__
2976 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2977 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2978 {
2979   /* const PetscInt  height = 0; */
2980   const PetscInt *partArray;
2981   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2982   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2983   PetscErrorCode  ierr;
2984 
2985   PetscFunctionBegin;
2986   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2987   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2988   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2989   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2990   for (rank = rStart; rank < rEnd; ++rank) {
2991     PetscInt partSize = 0;
2992     PetscInt numPoints, offset, p;
2993 
2994     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2995     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2996     for (p = 0; p < numPoints; ++p) {
2997       PetscInt  point   = partArray[offset+p], closureSize, c;
2998       PetscInt *closure = PETSC_NULL;
2999 
3000       /* TODO Include support for height > 0 case */
3001       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3002       /* Merge into existing points */
3003       if (partSize+closureSize > maxPartSize) {
3004         PetscInt *tmpPoints;
3005 
3006         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3007         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3008         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3009         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3010 
3011         partPoints = tmpPoints;
3012       }
3013       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3014       partSize += closureSize;
3015 
3016       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3017       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3018     }
3019     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3020   }
3021   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3022   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3023   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3024 
3025   for (rank = rStart; rank < rEnd; ++rank) {
3026     PetscInt partSize = 0, newOffset;
3027     PetscInt numPoints, offset, p;
3028 
3029     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3030     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3031     for (p = 0; p < numPoints; ++p) {
3032       PetscInt  point   = partArray[offset+p], closureSize, c;
3033       PetscInt *closure = PETSC_NULL;
3034 
3035       /* TODO Include support for height > 0 case */
3036       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3037       /* Merge into existing points */
3038       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3039       partSize += closureSize;
3040 
3041       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3042       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3043     }
3044     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3045     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3046   }
3047   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3048   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3049   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3050   PetscFunctionReturn(0);
3051 }
3052 
3053 #undef __FUNCT__
3054 #define __FUNCT__ "DMPlexDistributeField"
3055 /*
3056   Input Parameters:
3057 . originalSection
3058 , originalVec
3059 
3060   Output Parameters:
3061 . newSection
3062 . newVec
3063 */
3064 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3065 {
3066   PetscSF        fieldSF;
3067   PetscInt      *remoteOffsets, fieldSize;
3068   PetscScalar   *originalValues, *newValues;
3069   PetscErrorCode ierr;
3070 
3071   PetscFunctionBegin;
3072   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3073 
3074   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3075   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3076   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3077 
3078   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3079   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3080   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3081   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3082   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3083   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3084   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3085   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3086   PetscFunctionReturn(0);
3087 }
3088 
3089 #undef __FUNCT__
3090 #define __FUNCT__ "DMPlexDistribute"
3091 /*@C
3092   DMPlexDistribute - Distributes the mesh and any associated sections.
3093 
3094   Not Collective
3095 
3096   Input Parameter:
3097 + dm  - The original DMPlex object
3098 . partitioner - The partitioning package, or NULL for the default
3099 - overlap - The overlap of partitions, 0 is the default
3100 
3101   Output Parameter:
3102 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3103 
3104   Note: If the mesh was not distributed, the return value is PETSC_NULL
3105 
3106   Level: intermediate
3107 
3108 .keywords: mesh, elements
3109 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3110 @*/
3111 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3112 {
3113   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3114   MPI_Comm               comm   = ((PetscObject) dm)->comm;
3115   const PetscInt         height = 0;
3116   PetscInt               dim, numRemoteRanks;
3117   IS                     origCellPart,        cellPart,        part;
3118   PetscSection           origCellPartSection, cellPartSection, partSection;
3119   PetscSFNode           *remoteRanks;
3120   PetscSF                partSF, pointSF, coneSF;
3121   ISLocalToGlobalMapping renumbering;
3122   PetscSection           originalConeSection, newConeSection;
3123   PetscInt              *remoteOffsets;
3124   PetscInt              *cones, *newCones, newConesSize;
3125   PetscBool              flg;
3126   PetscMPIInt            rank, numProcs, p;
3127   PetscErrorCode         ierr;
3128 
3129   PetscFunctionBegin;
3130   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3131   PetscValidPointer(dmParallel,4);
3132 
3133   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3134   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3135   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3136 
3137   *dmParallel = PETSC_NULL;
3138   if (numProcs == 1) PetscFunctionReturn(0);
3139 
3140   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3141   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3142   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3143   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3144   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3145   if (!rank) numRemoteRanks = numProcs;
3146   else       numRemoteRanks = 0;
3147   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3148   for (p = 0; p < numRemoteRanks; ++p) {
3149     remoteRanks[p].rank  = p;
3150     remoteRanks[p].index = 0;
3151   }
3152   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3153   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3154   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3155   if (flg) {
3156     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3157     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3158     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3159     if (origCellPart) {
3160       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3161       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3162       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3163     }
3164     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3165   }
3166   /* Close the partition over the mesh */
3167   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3168   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3169   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3170   /* Create new mesh */
3171   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3172   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3173   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3174   pmesh = (DM_Plex*) (*dmParallel)->data;
3175   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3176   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3177   if (flg) {
3178     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3179     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3180     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3181     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3182     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3183     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3184   }
3185   /* Distribute cone section */
3186   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3187   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3188   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3189   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3190   {
3191     PetscInt pStart, pEnd, p;
3192 
3193     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3194     for (p = pStart; p < pEnd; ++p) {
3195       PetscInt coneSize;
3196       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3197       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3198     }
3199   }
3200   /* Communicate and renumber cones */
3201   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3202   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3203   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3204   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3205   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3206   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3207   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3208   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3209   if (flg) {
3210     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3211     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3212     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3213     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3214     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3215   }
3216   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3217   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3218   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3219   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3220   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3221   /* Create supports and stratify sieve */
3222   {
3223     PetscInt pStart, pEnd;
3224 
3225     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3226     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3227   }
3228   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3229   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3230   /* Distribute Coordinates */
3231   {
3232     PetscSection originalCoordSection, newCoordSection;
3233     Vec          originalCoordinates, newCoordinates;
3234     const char  *name;
3235 
3236     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3237     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3238     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3239     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3240     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3241     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3242 
3243     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3244     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3245     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3246   }
3247   /* Distribute labels */
3248   {
3249     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3250     PetscInt numLabels = 0, l;
3251 
3252     /* Bcast number of labels */
3253     while (next) {
3254       ++numLabels; next = next->next;
3255     }
3256     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3257     next = mesh->labels;
3258     for (l = 0; l < numLabels; ++l) {
3259       DMLabel         newLabel;
3260       const PetscInt *partArray;
3261       char           *name;
3262       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3263       PetscMPIInt    *sendcnts     = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3264       PetscInt        nameSize, s, p;
3265       PetscBool       isdepth;
3266       size_t          len = 0;
3267 
3268       /* Bcast name (could filter for no points) */
3269       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3270       nameSize = len;
3271       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3272       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3273       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3274       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3275       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3276       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3277       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3278       newLabel->name = name;
3279       /* Bcast numStrata (could filter for no points in stratum) */
3280       if (!rank) newLabel->numStrata = next->numStrata;
3281       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3282       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3283                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3284                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3285       /* Bcast stratumValues (could filter for no points in stratum) */
3286       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3287       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3288       /* Find size on each process and Scatter */
3289       if (!rank) {
3290         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3291         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3292         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3293         for (s = 0; s < next->numStrata; ++s) {
3294           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3295             const PetscInt point = next->points[p];
3296             PetscInt       proc;
3297 
3298             for (proc = 0; proc < numProcs; ++proc) {
3299               PetscInt dof, off, pPart;
3300 
3301               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3302               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3303               for (pPart = off; pPart < off+dof; ++pPart) {
3304                 if (partArray[pPart] == point) {
3305                   ++stratumSizes[proc*next->numStrata+s];
3306                   break;
3307                 }
3308               }
3309             }
3310           }
3311         }
3312         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3313       }
3314       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3315       /* Calculate stratumOffsets */
3316       newLabel->stratumOffsets[0] = 0;
3317       for (s = 0; s < newLabel->numStrata; ++s) {
3318         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3319       }
3320       /* Pack points and Scatter */
3321       if (!rank) {
3322         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3323         displs[0] = 0;
3324         for (p = 0; p < numProcs; ++p) {
3325           sendcnts[p] = 0;
3326           for (s = 0; s < next->numStrata; ++s) {
3327             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3328           }
3329           offsets[p]  = displs[p];
3330           displs[p+1] = displs[p] + sendcnts[p];
3331         }
3332         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3333         for (s = 0; s < next->numStrata; ++s) {
3334           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3335             const PetscInt point = next->points[p];
3336             PetscInt       proc;
3337 
3338             for (proc = 0; proc < numProcs; ++proc) {
3339               PetscInt dof, off, pPart;
3340 
3341               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3342               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3343               for (pPart = off; pPart < off+dof; ++pPart) {
3344                 if (partArray[pPart] == point) {
3345                   points[offsets[proc]++] = point;
3346                   break;
3347                 }
3348               }
3349             }
3350           }
3351         }
3352       }
3353       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3354       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3355       ierr = PetscFree(points);CHKERRQ(ierr);
3356       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3357       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3358       /* Renumber points */
3359       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3360       /* Sort points */
3361       for (s = 0; s < newLabel->numStrata; ++s) {
3362         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3363       }
3364       /* Insert into list */
3365       if (newNext) newNext->next = newLabel;
3366       else pmesh->labels = newLabel;
3367       newNext = newLabel;
3368       if (!rank) next = next->next;
3369     }
3370   }
3371   /* Cleanup Partition */
3372   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3373   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3374   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3375   ierr = ISDestroy(&part);CHKERRQ(ierr);
3376   /* Create point SF for parallel mesh */
3377   {
3378     const PetscInt *leaves;
3379     PetscSFNode    *remotePoints, *rowners, *lowners;
3380     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3381     PetscInt        pStart, pEnd;
3382 
3383     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3384     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3385     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3386     for (p=0; p<numRoots; p++) {
3387       rowners[p].rank  = -1;
3388       rowners[p].index = -1;
3389     }
3390     if (origCellPart) {
3391       /* Make sure cells in the original partition are not assigned to other procs */
3392       const PetscInt *origCells;
3393 
3394       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3395       for (p = 0; p < numProcs; ++p) {
3396         PetscInt dof, off, d;
3397 
3398         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3399         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3400         for (d = off; d < off+dof; ++d) {
3401           rowners[origCells[d]].rank = p;
3402         }
3403       }
3404       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3405     }
3406     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3407     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3408 
3409     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3410     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3411     for (p = 0; p < numLeaves; ++p) {
3412       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3413         lowners[p].rank  = rank;
3414         lowners[p].index = leaves ? leaves[p] : p;
3415       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3416         lowners[p].rank  = -2;
3417         lowners[p].index = -2;
3418       }
3419     }
3420     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3421       rowners[p].rank  = -3;
3422       rowners[p].index = -3;
3423     }
3424     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3425     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3426     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3427     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3428     for (p = 0; p < numLeaves; ++p) {
3429       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3430       if (lowners[p].rank != rank) ++numGhostPoints;
3431     }
3432     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3433     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3434     for (p = 0, gp = 0; p < numLeaves; ++p) {
3435       if (lowners[p].rank != rank) {
3436         ghostPoints[gp]        = leaves ? leaves[p] : p;
3437         remotePoints[gp].rank  = lowners[p].rank;
3438         remotePoints[gp].index = lowners[p].index;
3439         ++gp;
3440       }
3441     }
3442     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3443     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3444     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3445   }
3446   /* Cleanup */
3447   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3448   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3449   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3450   PetscFunctionReturn(0);
3451 }
3452 
3453 #undef __FUNCT__
3454 #define __FUNCT__ "DMPlexRenumber_Private"
3455 /*
3456   Reasons to renumber:
3457 
3458   1) Permute points, e.g. bandwidth reduction (Renumber)
3459 
3460     a) Must not mix strata
3461 
3462   2) Shift numbers for point insertion (Shift)
3463 
3464     a) Want operation brken into parts so that insertion can be interleaved
3465 
3466   renumbering - An IS which provides the new numbering
3467 */
3468 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3469 {
3470   PetscFunctionBegin;
3471   PetscFunctionReturn(0);
3472 }
3473 
3474 #undef __FUNCT__
3475 #define __FUNCT__ "DMPlexShiftPoint_Private"
3476 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3477 {
3478   if (depth < 0) return p;
3479   /* Cells    */ if (p < depthEnd[depth])   return p;
3480   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3481   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3482   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3483 }
3484 
3485 #undef __FUNCT__
3486 #define __FUNCT__ "DMPlexShiftSizes_Private"
3487 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3488 {
3489   PetscInt      *depthEnd;
3490   PetscInt       depth = 0, d, pStart, pEnd, p;
3491   PetscErrorCode ierr;
3492 
3493   PetscFunctionBegin;
3494   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3495   if (depth < 0) PetscFunctionReturn(0);
3496   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3497   /* Step 1: Expand chart */
3498   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3499   for (d = 0; d <= depth; ++d) {
3500     pEnd += depthShift[d];
3501     ierr  = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3502   }
3503   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3504   /* Step 2: Set cone and support sizes */
3505   for (d = 0; d <= depth; ++d) {
3506     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3507     for (p = pStart; p < pEnd; ++p) {
3508       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3509       PetscInt size;
3510 
3511       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3512       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3513       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3514       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3515     }
3516   }
3517   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3518   PetscFunctionReturn(0);
3519 }
3520 
3521 #undef __FUNCT__
3522 #define __FUNCT__ "DMPlexShiftPoints_Private"
3523 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3524 {
3525   PetscInt      *depthEnd, *newpoints;
3526   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3527   PetscErrorCode ierr;
3528 
3529   PetscFunctionBegin;
3530   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3531   if (depth < 0) PetscFunctionReturn(0);
3532   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3533   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3534   for (d = 0; d <= depth; ++d) {
3535     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3536   }
3537   /* Step 5: Set cones and supports */
3538   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3539   for (p = pStart; p < pEnd; ++p) {
3540     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3541     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3542 
3543     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3544     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3545     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3546     for (i = 0; i < size; ++i) {
3547       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3548     }
3549     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3550     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3551     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3552     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3553     for (i = 0; i < size; ++i) {
3554       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3555     }
3556     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3557   }
3558   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3559   PetscFunctionReturn(0);
3560 }
3561 
3562 #undef __FUNCT__
3563 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3564 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3565 {
3566   PetscSection   coordSection, newCoordSection;
3567   Vec            coordinates, newCoordinates;
3568   PetscScalar   *coords, *newCoords;
3569   PetscInt      *depthEnd, coordSize;
3570   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3571   PetscErrorCode ierr;
3572 
3573   PetscFunctionBegin;
3574   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3575   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3576   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3577   for (d = 0; d <= depth; ++d) {
3578     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3579   }
3580   /* Step 8: Convert coordinates */
3581   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3582   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3583   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3584   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3585   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3586   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3587   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3588   for (v = vStartNew; v < vEndNew; ++v) {
3589     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3590     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3591   }
3592   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3593   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3594   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3595   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3596   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3597   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3598   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3599   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3600   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3601   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3602   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3603   for (v = vStart; v < vEnd; ++v) {
3604     PetscInt dof, off, noff, d;
3605 
3606     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3607     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3608     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3609     for (d = 0; d < dof; ++d) {
3610       newCoords[noff+d] = coords[off+d];
3611     }
3612   }
3613   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3614   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3615   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3616   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3617   PetscFunctionReturn(0);
3618 }
3619 
3620 #undef __FUNCT__
3621 #define __FUNCT__ "DMPlexShiftSF_Private"
3622 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3623 {
3624   PetscInt          *depthEnd;
3625   PetscInt           depth = 0, d;
3626   PetscSF            sfPoint, sfPointNew;
3627   const PetscSFNode *remotePoints;
3628   PetscSFNode       *gremotePoints;
3629   const PetscInt    *localPoints;
3630   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3631   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3632   PetscMPIInt        numProcs;
3633   PetscErrorCode     ierr;
3634 
3635   PetscFunctionBegin;
3636   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3637   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3638   for (d = 0; d <= depth; ++d) {
3639     totShift += depthShift[d];
3640     ierr      = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3641   }
3642   /* Step 9: Convert pointSF */
3643   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3644   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3645   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3646   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3647   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3648   if (numRoots >= 0) {
3649     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3650     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3651     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3652     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3653     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3654     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3655     for (l = 0; l < numLeaves; ++l) {
3656       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3657       gremotePoints[l].rank  = remotePoints[l].rank;
3658       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3659     }
3660     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3661     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3662   }
3663   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3664   PetscFunctionReturn(0);
3665 }
3666 
3667 #undef __FUNCT__
3668 #define __FUNCT__ "DMPlexShiftLabels_Private"
3669 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3670 {
3671   PetscSF            sfPoint;
3672   DMLabel            vtkLabel, ghostLabel;
3673   PetscInt          *depthEnd;
3674   const PetscSFNode *leafRemote;
3675   const PetscInt    *leafLocal;
3676   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3677   PetscMPIInt        rank;
3678   PetscErrorCode     ierr;
3679 
3680   PetscFunctionBegin;
3681   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3682   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3683   for (d = 0; d <= depth; ++d) {
3684     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3685   }
3686   /* Step 10: Convert labels */
3687   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3688   for (l = 0; l < numLabels; ++l) {
3689     DMLabel         label, newlabel;
3690     const char     *lname;
3691     PetscBool       isDepth;
3692     IS              valueIS;
3693     const PetscInt *values;
3694     PetscInt        numValues, val;
3695 
3696     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3697     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3698     if (isDepth) continue;
3699     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3700     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3701     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3702     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3703     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3704     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3705     for (val = 0; val < numValues; ++val) {
3706       IS              pointIS;
3707       const PetscInt *points;
3708       PetscInt        numPoints, p;
3709 
3710       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3711       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3712       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3713       for (p = 0; p < numPoints; ++p) {
3714         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3715 
3716         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3717       }
3718       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3719       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3720     }
3721     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3722     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3723   }
3724   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3725   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3726   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3727   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3728   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3729   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3730   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3731   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3732   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3733   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3734   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3735     for (; c < leafLocal[l] && c < cEnd; ++c) {
3736       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3737     }
3738     if (leafLocal[l] >= cEnd) break;
3739     if (leafRemote[l].rank == rank) {
3740       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3741     } else {
3742       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3743     }
3744   }
3745   for (; c < cEnd; ++c) {
3746     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3747   }
3748   if (0) {
3749     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3750     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3751     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3752   }
3753   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3754   for (f = fStart; f < fEnd; ++f) {
3755     PetscInt numCells;
3756 
3757     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3758     if (numCells < 2) {
3759       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3760     } else {
3761       const PetscInt *cells = PETSC_NULL;
3762       PetscInt        vA, vB;
3763 
3764       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3765       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3766       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3767       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3768     }
3769   }
3770   if (0) {
3771     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3772     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3773     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3774   }
3775   PetscFunctionReturn(0);
3776 }
3777 
3778 #undef __FUNCT__
3779 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3780 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3781 {
3782   DMLabel         label;
3783   IS              valueIS;
3784   const PetscInt *values;
3785   PetscInt       *depthShift;
3786   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3787   PetscErrorCode  ierr;
3788 
3789   PetscFunctionBegin;
3790   /* Count ghost cells */
3791   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3792   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3793   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3794   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3795 
3796   *numGhostCells = 0;
3797   for (fs = 0; fs < numFS; ++fs) {
3798     PetscInt numBdFaces;
3799 
3800     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3801 
3802     *numGhostCells += numBdFaces;
3803   }
3804   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3805   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3806   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3807   if (depth >= 0) depthShift[depth] = *numGhostCells;
3808   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3809   /* Step 3: Set cone/support sizes for new points */
3810   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3811   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3812     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3813   }
3814   for (fs = 0; fs < numFS; ++fs) {
3815     IS              faceIS;
3816     const PetscInt *faces;
3817     PetscInt        numFaces, f;
3818 
3819     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3820     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3821     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3822     for (f = 0; f < numFaces; ++f) {
3823       PetscInt size;
3824 
3825       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3826       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3827       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3828     }
3829     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3830     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3831   }
3832   /* Step 4: Setup ghosted DM */
3833   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3834   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3835   /* Step 6: Set cones and supports for new points */
3836   ghostCell = cEnd;
3837   for (fs = 0; fs < numFS; ++fs) {
3838     IS              faceIS;
3839     const PetscInt *faces;
3840     PetscInt        numFaces, f;
3841 
3842     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3843     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3844     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3845     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3846       PetscInt newFace = faces[f] + *numGhostCells;
3847 
3848       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3849       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3850     }
3851     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3852     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3853   }
3854   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3855   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3856   /* Step 7: Stratify */
3857   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3858   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3859   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3860   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3861   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3862   PetscFunctionReturn(0);
3863 }
3864 
3865 #undef __FUNCT__
3866 #define __FUNCT__ "DMPlexConstructGhostCells"
3867 /*@C
3868   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3869 
3870   Collective on dm
3871 
3872   Input Parameters:
3873 + dm - The original DM
3874 - labelName - The label specifying the boundary faces (this could be auto-generated)
3875 
3876   Output Parameters:
3877 + numGhostCells - The number of ghost cells added to the DM
3878 - dmGhosted - The new DM
3879 
3880   Level: developer
3881 
3882 .seealso: DMCreate()
3883 */
3884 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3885 {
3886   DM             gdm;
3887   PetscInt       dim;
3888   PetscErrorCode ierr;
3889 
3890   PetscFunctionBegin;
3891   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3892   PetscValidPointer(numGhostCells, 3);
3893   PetscValidPointer(dmGhosted, 4);
3894   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3895   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3896   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3897   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3898   switch (dim) {
3899   case 2:
3900     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3901     break;
3902   default:
3903     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3904   }
3905   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3906   *dmGhosted = gdm;
3907   PetscFunctionReturn(0);
3908 }
3909 
3910 #undef __FUNCT__
3911 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3912 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3913 {
3914   MPI_Comm        comm = ((PetscObject) dm)->comm;
3915   IS              valueIS, *pointIS;
3916   const PetscInt *values, **splitPoints;
3917   PetscSection    coordSection;
3918   Vec             coordinates;
3919   PetscScalar    *coords;
3920   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3921   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3922   PetscErrorCode  ierr;
3923 
3924   PetscFunctionBegin;
3925   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3926   /* Count split points and add cohesive cells */
3927   if (label) {
3928     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3929     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3930     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3931   }
3932   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3933   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3934   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3935   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3936   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3937   for (d = 0; d <= depth; ++d) {
3938     ierr              = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3939     numSplitPoints[d] = 0;
3940     splitPoints[d]    = PETSC_NULL;
3941     pointIS[d]        = PETSC_NULL;
3942   }
3943   for (sp = 0; sp < numSP; ++sp) {
3944     const PetscInt dep = values[sp];
3945 
3946     if ((dep < 0) || (dep > depth)) continue;
3947     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3948     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3949     if (pointIS[dep]) {
3950       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3951       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3952     }
3953   }
3954   if (depth >= 0) {
3955     /* Calculate number of additional points */
3956     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3957     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3958     /* Calculate hybrid bound for each dimension */
3959     pMaxNew[0] += depthShift[depth];
3960     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3961     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3962 
3963     /* Calculate point offset for each dimension */
3964     depthOffset[depth] = 0;
3965     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3966     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3967     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3968   }
3969   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3970   /* Step 3: Set cone/support sizes for new points */
3971   for (dep = 0; dep <= depth; ++dep) {
3972     for (p = 0; p < numSplitPoints[dep]; ++p) {
3973       const PetscInt  oldp   = splitPoints[dep][p];
3974       const PetscInt  newp   = depthOffset[dep] + oldp;
3975       const PetscInt  splitp = pMaxNew[dep] + p;
3976       const PetscInt *support;
3977       PetscInt        coneSize, supportSize, q, e;
3978 
3979       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3980       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3981       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3982       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3983       if (dep == depth-1) {
3984         const PetscInt ccell = pMaxNew[depth] + p;
3985         /* Add cohesive cells, they are prisms */
3986         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3987       } else if (dep == 0) {
3988         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3989 
3990         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3991         /* Split old vertex: Edges in old split faces and new cohesive edge */
3992         for (e = 0, q = 0; e < supportSize; ++e) {
3993           PetscInt val;
3994 
3995           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3996           if ((val == 1) || (val == (shift + 1))) ++q;
3997         }
3998         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3999         /* Split new vertex: Edges in new split faces and new cohesive edge */
4000         for (e = 0, q = 0; e < supportSize; ++e) {
4001           PetscInt val;
4002 
4003           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4004           if ((val == 1) || (val == -(shift + 1))) ++q;
4005         }
4006         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4007         /* Add cohesive edges */
4008         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4009         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4010       } else if (dep == dim-2) {
4011         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4012         /* Split old edge: Faces in positive side cells and old split faces */
4013         for (e = 0, q = 0; e < supportSize; ++e) {
4014           PetscInt val;
4015 
4016           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4017           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4018         }
4019         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4020         /* Split new edge: Faces in negative side cells and new split faces */
4021         for (e = 0, q = 0; e < supportSize; ++e) {
4022           PetscInt val;
4023 
4024           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4025           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4026         }
4027         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4028       }
4029     }
4030   }
4031   /* Step 4: Setup split DM */
4032   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4033   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4034   /* Step 6: Set cones and supports for new points */
4035   for (dep = 0; dep <= depth; ++dep) {
4036     for (p = 0; p < numSplitPoints[dep]; ++p) {
4037       const PetscInt  oldp   = splitPoints[dep][p];
4038       const PetscInt  newp   = depthOffset[dep] + oldp;
4039       const PetscInt  splitp = pMaxNew[dep] + p;
4040       const PetscInt *cone, *support, *ornt;
4041       PetscInt        coneSize, supportSize, q, v, e, s;
4042 
4043       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4044       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4045       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4046       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4047       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4048       if (dep == depth-1) {
4049         const PetscInt  ccell = pMaxNew[depth] + p;
4050         const PetscInt *supportF;
4051 
4052         /* Split face:       copy in old face to new face to start */
4053         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4054         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4055         /* Split old face:   old vertices/edges in cone so no change */
4056         /* Split new face:   new vertices/edges in cone */
4057         for (q = 0; q < coneSize; ++q) {
4058           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4059 
4060           coneNew[2+q] = pMaxNew[dim-2] + v;
4061         }
4062         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4063         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4064         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4065         coneNew[0] = newp;
4066         coneNew[1] = splitp;
4067         for (q = 0; q < coneSize; ++q) {
4068           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4069         }
4070         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4071 
4072 
4073         for (s = 0; s < supportSize; ++s) {
4074           PetscInt val;
4075 
4076           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4077           if (val < 0) {
4078             /* Split old face:   Replace negative side cell with cohesive cell */
4079             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4080           } else {
4081             /* Split new face:   Replace positive side cell with cohesive cell */
4082             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4083           }
4084         }
4085       } else if (dep == 0) {
4086         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4087 
4088         /* Split old vertex: Edges in old split faces and new cohesive edge */
4089         for (e = 0, q = 0; e < supportSize; ++e) {
4090           PetscInt val;
4091 
4092           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4093           if ((val == 1) || (val == (shift + 1))) {
4094             supportNew[q++] = depthOffset[1] + support[e];
4095           }
4096         }
4097         supportNew[q] = cedge;
4098 
4099         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4100         /* Split new vertex: Edges in new split faces and new cohesive edge */
4101         for (e = 0, q = 0; e < supportSize; ++e) {
4102           PetscInt val, edge;
4103 
4104           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4105           if (val == 1) {
4106             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4107             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4108             supportNew[q++] = pMaxNew[1] + edge;
4109           } else if (val == -(shift + 1)) {
4110             supportNew[q++] = depthOffset[1] + support[e];
4111           }
4112         }
4113         supportNew[q] = cedge;
4114         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4115         /* Cohesive edge:    Old and new split vertex, punting on support */
4116         coneNew[0] = newp;
4117         coneNew[1] = splitp;
4118         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4119       } else if (dep == dim-2) {
4120         /* Split old edge:   old vertices in cone so no change */
4121         /* Split new edge:   new vertices in cone */
4122         for (q = 0; q < coneSize; ++q) {
4123           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4124 
4125           coneNew[q] = pMaxNew[dim-3] + v;
4126         }
4127         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4128         /* Split old edge: Faces in positive side cells and old split faces */
4129         for (e = 0, q = 0; e < supportSize; ++e) {
4130           PetscInt val;
4131 
4132           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4133           if ((val == dim-1) || (val == (shift + dim-1))) {
4134             supportNew[q++] = depthOffset[dim-1] + support[e];
4135           }
4136         }
4137         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4138         /* Split new edge: Faces in negative side cells and new split faces */
4139         for (e = 0, q = 0; e < supportSize; ++e) {
4140           PetscInt val, face;
4141 
4142           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4143           if (val == dim-1) {
4144             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4145             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4146             supportNew[q++] = pMaxNew[dim-1] + face;
4147           } else if (val == -(shift + dim-1)) {
4148             supportNew[q++] = depthOffset[dim-1] + support[e];
4149           }
4150         }
4151         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4152       }
4153     }
4154   }
4155   /* Step 6b: Replace split points in negative side cones */
4156   for (sp = 0; sp < numSP; ++sp) {
4157     PetscInt        dep = values[sp];
4158     IS              pIS;
4159     PetscInt        numPoints;
4160     const PetscInt *points;
4161 
4162     if (dep >= 0) continue;
4163     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4164     if (!pIS) continue;
4165     dep  = -dep - shift;
4166     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4167     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4168     for (p = 0; p < numPoints; ++p) {
4169       const PetscInt  oldp = points[p];
4170       const PetscInt  newp = depthOffset[dep] + oldp;
4171       const PetscInt *cone;
4172       PetscInt        coneSize, c;
4173       PetscBool       replaced = PETSC_FALSE;
4174 
4175       /* Negative edge: replace split vertex */
4176       /* Negative cell: replace split face */
4177       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4178       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4179       for (c = 0; c < coneSize; ++c) {
4180         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4181         PetscInt       csplitp, cp, val;
4182 
4183         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4184         if (val == dep-1) {
4185           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4186           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4187           csplitp  = pMaxNew[dep-1] + cp;
4188           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4189           replaced = PETSC_TRUE;
4190         }
4191       }
4192       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4193     }
4194     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4195     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4196   }
4197   /* Step 7: Stratify */
4198   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4199   /* Step 8: Coordinates */
4200   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4201   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4202   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4203   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4204   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4205     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4206     const PetscInt splitp = pMaxNew[0] + v;
4207     PetscInt       dof, off, soff, d;
4208 
4209     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4210     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4211     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4212     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4213   }
4214   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4215   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4216   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4217   /* Step 10: Labels */
4218   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4219   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4220   for (dep = 0; dep <= depth; ++dep) {
4221     for (p = 0; p < numSplitPoints[dep]; ++p) {
4222       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4223       const PetscInt splitp = pMaxNew[dep] + p;
4224       PetscInt       l;
4225 
4226       for (l = 0; l < numLabels; ++l) {
4227         DMLabel     mlabel;
4228         const char *lname;
4229         PetscInt    val;
4230 
4231         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4232         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4233         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4234         if (val >= 0) {
4235           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4236           if (dep == 0) {
4237             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4238             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4239           }
4240         }
4241       }
4242     }
4243   }
4244   for (sp = 0; sp < numSP; ++sp) {
4245     const PetscInt dep = values[sp];
4246 
4247     if ((dep < 0) || (dep > depth)) continue;
4248     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4249     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4250   }
4251   if (label) {
4252     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4253     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4254   }
4255   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4256   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4257   PetscFunctionReturn(0);
4258 }
4259 
4260 #undef __FUNCT__
4261 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4262 /*@C
4263   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4264 
4265   Collective on dm
4266 
4267   Input Parameters:
4268 + dm - The original DM
4269 - labelName - The label specifying the boundary faces (this could be auto-generated)
4270 
4271   Output Parameters:
4272 - dmSplit - The new DM
4273 
4274   Level: developer
4275 
4276 .seealso: DMCreate()
4277 */
4278 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4279 {
4280   DM             sdm;
4281   PetscInt       dim;
4282   PetscErrorCode ierr;
4283 
4284   PetscFunctionBegin;
4285   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4286   PetscValidPointer(dmSplit, 4);
4287   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4288   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4289   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4290   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4291   switch (dim) {
4292   case 2:
4293   case 3:
4294     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4295     break;
4296   default:
4297     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4298   }
4299   *dmSplit = sdm;
4300   PetscFunctionReturn(0);
4301 }
4302 
4303 #undef __FUNCT__
4304 #define __FUNCT__ "DMLabelCohesiveComplete"
4305 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4306 {
4307   IS              dimIS;
4308   const PetscInt *points;
4309   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4310   PetscErrorCode  ierr;
4311 
4312   PetscFunctionBegin;
4313   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4314   /* Cell orientation for face gives the side of the fault */
4315   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4316   if (!dimIS) PetscFunctionReturn(0);
4317   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4318   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4319   for (p = 0; p < numPoints; ++p) {
4320     const PetscInt *support;
4321     PetscInt        supportSize, s;
4322 
4323     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4324     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4325     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4326     for (s = 0; s < supportSize; ++s) {
4327       const PetscInt *cone, *ornt;
4328       PetscInt        coneSize, c;
4329       PetscBool       pos = PETSC_TRUE;
4330 
4331       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4332       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4333       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4334       for (c = 0; c < coneSize; ++c) {
4335         if (cone[c] == points[p]) {
4336           if (ornt[c] >= 0) {
4337             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4338           } else {
4339             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4340             pos  = PETSC_FALSE;
4341           }
4342           break;
4343         }
4344       }
4345       if (c == coneSize) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4346       /* Put faces touching the fault in the label */
4347       for (c = 0; c < coneSize; ++c) {
4348         const PetscInt point = cone[c];
4349 
4350         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4351         if (val == -1) {
4352           PetscInt *closure = PETSC_NULL;
4353           PetscInt  closureSize, cl;
4354 
4355           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4356           for (cl = 0; cl < closureSize*2; cl += 2) {
4357             const PetscInt clp = closure[cl];
4358 
4359             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4360             if ((val >= 0) && (val < dim-1)) {
4361               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4362               break;
4363             }
4364           }
4365           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4366         }
4367       }
4368     }
4369   }
4370   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4371   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4372   /* Search for other cells/faces/edges connected to the fault by a vertex */
4373   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4374   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4375   if (!dimIS) PetscFunctionReturn(0);
4376   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4377   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4378   for (p = 0; p < numPoints; ++p) {
4379     PetscInt *star = PETSC_NULL;
4380     PetscInt  starSize, s;
4381     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4382 
4383     /* First mark cells connected to the fault */
4384     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4385     while (again) {
4386       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4387       again = 0;
4388       for (s = 0; s < starSize*2; s += 2) {
4389         const PetscInt  point = star[s];
4390         const PetscInt *cone;
4391         PetscInt        coneSize, c;
4392 
4393         if ((point < cStart) || (point >= cEnd)) continue;
4394         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4395         if (val != -1) continue;
4396         again = 2;
4397         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4398         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4399         for (c = 0; c < coneSize; ++c) {
4400           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4401           if (val != -1) {
4402             if (abs(val) < shift) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4403             if (val > 0) {
4404               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4405             } else {
4406               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4407             }
4408             again = 1;
4409             break;
4410           }
4411         }
4412       }
4413     }
4414     /* Classify the rest by cell membership */
4415     for (s = 0; s < starSize*2; s += 2) {
4416       const PetscInt point = star[s];
4417 
4418       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4419       if (val == -1) {
4420         PetscInt  *sstar = PETSC_NULL;
4421         PetscInt   sstarSize, ss;
4422         PetscBool  marked = PETSC_FALSE;
4423 
4424         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4425         for (ss = 0; ss < sstarSize*2; ss += 2) {
4426           const PetscInt spoint = sstar[ss];
4427 
4428           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4429           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4430           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4431           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4432           if (val > 0) {
4433             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4434           } else {
4435             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4436           }
4437           marked = PETSC_TRUE;
4438           break;
4439         }
4440         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4441         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4442       }
4443     }
4444     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4445   }
4446   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4447   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4448   PetscFunctionReturn(0);
4449 }
4450 
4451 #undef __FUNCT__
4452 #define __FUNCT__ "DMPlexInterpolate_2D"
4453 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4454 {
4455   DM             idm;
4456   DM_Plex       *mesh;
4457   PetscHashIJ    edgeTable;
4458   PetscInt      *off;
4459   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4460   PetscInt       numEdges, firstEdge, edge, e;
4461   PetscErrorCode ierr;
4462 
4463   PetscFunctionBegin;
4464   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4465   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4466   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4467   numCells    = cEnd - cStart;
4468   numVertices = vEnd - vStart;
4469   firstEdge   = numCells + numVertices;
4470   numEdges    = 0;
4471   /* Count edges using algorithm from CreateNeighborCSR */
4472   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4473   if (off) {
4474     PetscInt numCorners = 0;
4475 
4476     numEdges = off[numCells]/2;
4477 #if 0
4478     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4479     numEdges += 3*numCells - off[numCells];
4480 #else
4481     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4482     for (c = cStart; c < cEnd; ++c) {
4483       PetscInt coneSize;
4484 
4485       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4486       numCorners += coneSize;
4487     }
4488     numEdges += numCorners - off[numCells];
4489 #endif
4490   }
4491 #if 0
4492   /* Check Euler characteristic V - E + F = 1 */
4493   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4494 #endif
4495   /* Create interpolated mesh */
4496   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4497   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4498   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4499   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4500   for (c = 0; c < numCells; ++c) {
4501     PetscInt numCorners;
4502 
4503     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4504     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4505   }
4506   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4507     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4508   }
4509   ierr = DMSetUp(idm);CHKERRQ(ierr);
4510   /* Get edge cones from subsets of cell vertices */
4511   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4512   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4513 
4514   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4515     const PetscInt *cellFaces;
4516     PetscInt        numCellFaces, faceSize, cf;
4517 
4518     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4519     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4520     for (cf = 0; cf < numCellFaces; ++cf) {
4521 #if 1
4522       PetscHashIJKey key;
4523 
4524       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4525       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4526       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4527       if (e < 0) {
4528         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4529         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4530         e    = edge++;
4531       }
4532 #else
4533       PetscBool found = PETSC_FALSE;
4534 
4535       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4536       for (e = firstEdge; e < edge; ++e) {
4537         const PetscInt *cone;
4538 
4539         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4540         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4541             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4542           found = PETSC_TRUE;
4543           break;
4544         }
4545       }
4546       if (!found) {
4547         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4548         ++edge;
4549       }
4550 #endif
4551       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4552     }
4553   }
4554   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4555   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4556   ierr = PetscFree(off);CHKERRQ(ierr);
4557   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4558   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4559   mesh = (DM_Plex*) (idm)->data;
4560   /* Orient edges */
4561   for (c = 0; c < numCells; ++c) {
4562     const PetscInt *cone = PETSC_NULL, *cellFaces;
4563     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4564 
4565     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4566     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4567     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4568     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4569     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4570     for (cf = 0; cf < numCellFaces; ++cf) {
4571       const PetscInt *econe = PETSC_NULL;
4572       PetscInt        esize;
4573 
4574       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4575       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4576       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]);
4577       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4578         /* Correctly oriented */
4579         mesh->coneOrientations[coff+cf] = 0;
4580       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4581         /* Start at index 1, and reverse orientation */
4582         mesh->coneOrientations[coff+cf] = -(1+1);
4583       }
4584     }
4585   }
4586   *dmInt = idm;
4587   PetscFunctionReturn(0);
4588 }
4589 
4590 #undef __FUNCT__
4591 #define __FUNCT__ "DMPlexInterpolate_3D"
4592 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4593 {
4594   DM             idm, fdm;
4595   DM_Plex       *mesh;
4596   PetscInt      *off;
4597   const PetscInt numCorners = 4;
4598   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4599   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4600   PetscErrorCode ierr;
4601 
4602   PetscFunctionBegin;
4603   {
4604     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4605     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4606     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4607   }
4608   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4609   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4610   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4611   numCells    = cEnd - cStart;
4612   numVertices = vEnd - vStart;
4613   firstFace   = numCells + numVertices;
4614   numFaces    = 0;
4615   /* Count faces using algorithm from CreateNeighborCSR */
4616   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4617   if (off) {
4618     numFaces = off[numCells]/2;
4619     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4620     numFaces += 4*numCells - off[numCells];
4621   }
4622   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4623   firstEdge = firstFace + numFaces;
4624   numEdges  = numVertices + numFaces - numCells - 1;
4625   /* Create interpolated mesh */
4626   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4627   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4628   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4629   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4630   for (c = 0; c < numCells; ++c) {
4631     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4632   }
4633   for (f = firstFace; f < firstFace+numFaces; ++f) {
4634     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4635   }
4636   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4637     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4638   }
4639   ierr = DMSetUp(idm);CHKERRQ(ierr);
4640   /* Get face cones from subsets of cell vertices */
4641   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4642   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4643   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4644   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4645   for (f = firstFace; f < firstFace+numFaces; ++f) {
4646     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4647   }
4648   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4649   for (c = 0, face = firstFace; c < numCells; ++c) {
4650     const PetscInt *cellFaces;
4651     PetscInt        numCellFaces, faceSize, cf;
4652 
4653     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4654     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4655     for (cf = 0; cf < numCellFaces; ++cf) {
4656       PetscBool found = PETSC_FALSE;
4657 
4658       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4659       for (f = firstFace; f < face; ++f) {
4660         const PetscInt *cone = PETSC_NULL;
4661 
4662         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4663         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4664             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4665             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4666             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4667             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4668             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4669           found = PETSC_TRUE;
4670           break;
4671         }
4672       }
4673       if (!found) {
4674         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4675         /* Save the vertices for orientation calculation */
4676         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4677         ++face;
4678       }
4679       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4680     }
4681   }
4682   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4683   /* Get edge cones from subsets of face vertices */
4684   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4685     const PetscInt *cellFaces;
4686     PetscInt        numCellFaces, faceSize, cf;
4687 
4688     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4689     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4690     for (cf = 0; cf < numCellFaces; ++cf) {
4691       PetscBool found = PETSC_FALSE;
4692 
4693       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4694       for (e = firstEdge; e < edge; ++e) {
4695         const PetscInt *cone = PETSC_NULL;
4696 
4697         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4698         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4699             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4700           found = PETSC_TRUE;
4701           break;
4702         }
4703       }
4704       if (!found) {
4705         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4706         ++edge;
4707       }
4708       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4709     }
4710   }
4711   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4712   ierr = PetscFree(off);CHKERRQ(ierr);
4713   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4714   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4715   mesh = (DM_Plex*) (idm)->data;
4716   /* Orient edges */
4717   for (f = firstFace; f < firstFace+numFaces; ++f) {
4718     const PetscInt *cone, *cellFaces;
4719     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4720 
4721     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4722     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4723     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4724     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4725     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4726     for (cf = 0; cf < numCellFaces; ++cf) {
4727       const PetscInt *econe;
4728       PetscInt        esize;
4729 
4730       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4731       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4732       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]);
4733       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4734         /* Correctly oriented */
4735         mesh->coneOrientations[coff+cf] = 0;
4736       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4737         /* Start at index 1, and reverse orientation */
4738         mesh->coneOrientations[coff+cf] = -(1+1);
4739       }
4740     }
4741   }
4742   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4743   /* Orient faces */
4744   for (c = 0; c < numCells; ++c) {
4745     const PetscInt *cone, *cellFaces;
4746     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4747 
4748     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4749     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4750     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4751     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4752     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4753     for (cf = 0; cf < numCellFaces; ++cf) {
4754       PetscInt *origClosure = PETSC_NULL, *closure;
4755       PetscInt closureSize, i;
4756 
4757       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4758       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4759       for (i = 4; i < 7; ++i) {
4760         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);
4761       }
4762       closure = &origClosure[4*2];
4763       /* Remember that this is the orientation for edges, not vertices */
4764       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4765         /* Correctly oriented */
4766         mesh->coneOrientations[coff+cf] = 0;
4767       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4768         /* Shifted by 1 */
4769         mesh->coneOrientations[coff+cf] = 1;
4770       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4771         /* Shifted by 2 */
4772         mesh->coneOrientations[coff+cf] = 2;
4773       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4774         /* Start at edge 1, and reverse orientation */
4775         mesh->coneOrientations[coff+cf] = -(1+1);
4776       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4777         /* Start at index 0, and reverse orientation */
4778         mesh->coneOrientations[coff+cf] = -(0+1);
4779       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4780         /* Start at index 2, and reverse orientation */
4781         mesh->coneOrientations[coff+cf] = -(2+1);
4782       } 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);
4783       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4784     }
4785   }
4786   {
4787     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4788     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4789     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4790   }
4791   *dmInt = idm;
4792   PetscFunctionReturn(0);
4793 }
4794 
4795 #undef __FUNCT__
4796 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4797 /*
4798   This takes as input the common mesh generator output, a list of the vertices for each cell
4799 */
4800 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4801 {
4802   PetscInt      *cone, c, p;
4803   PetscErrorCode ierr;
4804 
4805   PetscFunctionBegin;
4806   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4807   for (c = 0; c < numCells; ++c) {
4808     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4809   }
4810   ierr = DMSetUp(dm);CHKERRQ(ierr);
4811   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4812   for (c = 0; c < numCells; ++c) {
4813     for (p = 0; p < numCorners; ++p) {
4814       cone[p] = cells[c*numCorners+p]+numCells;
4815     }
4816     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4817   }
4818   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4819   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4820   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4821   PetscFunctionReturn(0);
4822 }
4823 
4824 #undef __FUNCT__
4825 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4826 /*
4827   This takes as input the coordinates for each vertex
4828 */
4829 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4830 {
4831   PetscSection   coordSection;
4832   Vec            coordinates;
4833   PetscScalar   *coords;
4834   PetscInt       coordSize, v, d;
4835   PetscErrorCode ierr;
4836 
4837   PetscFunctionBegin;
4838   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4839   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4840   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4841   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4842   for (v = numCells; v < numCells+numVertices; ++v) {
4843     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4844     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4845   }
4846   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4847   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4848   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4849   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4850   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4851   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4852   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4853   for (v = 0; v < numVertices; ++v) {
4854     for (d = 0; d < spaceDim; ++d) {
4855       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4856     }
4857   }
4858   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4859   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4860   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4861   PetscFunctionReturn(0);
4862 }
4863 
4864 #undef __FUNCT__
4865 #define __FUNCT__ "DMPlexCreateFromCellList"
4866 /*
4867   This takes as input the common mesh generator output, a list of the vertices for each cell
4868 */
4869 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4870 {
4871   PetscErrorCode ierr;
4872 
4873   PetscFunctionBegin;
4874   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4875   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4876   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4877   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4878   if (interpolate) {
4879     DM idm;
4880 
4881     switch (dim) {
4882     case 2:
4883       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4884     case 3:
4885       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4886     default:
4887       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4888     }
4889     ierr = DMDestroy(dm);CHKERRQ(ierr);
4890     *dm  = idm;
4891   }
4892   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4893   PetscFunctionReturn(0);
4894 }
4895 
4896 #if defined(PETSC_HAVE_TRIANGLE)
4897 #include <triangle.h>
4898 
4899 #undef __FUNCT__
4900 #define __FUNCT__ "InitInput_Triangle"
4901 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4902 {
4903   PetscFunctionBegin;
4904   inputCtx->numberofpoints             = 0;
4905   inputCtx->numberofpointattributes    = 0;
4906   inputCtx->pointlist                  = PETSC_NULL;
4907   inputCtx->pointattributelist         = PETSC_NULL;
4908   inputCtx->pointmarkerlist            = PETSC_NULL;
4909   inputCtx->numberofsegments           = 0;
4910   inputCtx->segmentlist                = PETSC_NULL;
4911   inputCtx->segmentmarkerlist          = PETSC_NULL;
4912   inputCtx->numberoftriangleattributes = 0;
4913   inputCtx->trianglelist               = PETSC_NULL;
4914   inputCtx->numberofholes              = 0;
4915   inputCtx->holelist                   = PETSC_NULL;
4916   inputCtx->numberofregions            = 0;
4917   inputCtx->regionlist                 = PETSC_NULL;
4918   PetscFunctionReturn(0);
4919 }
4920 
4921 #undef __FUNCT__
4922 #define __FUNCT__ "InitOutput_Triangle"
4923 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4924 {
4925   PetscFunctionBegin;
4926   outputCtx->numberofpoints        = 0;
4927   outputCtx->pointlist             = PETSC_NULL;
4928   outputCtx->pointattributelist    = PETSC_NULL;
4929   outputCtx->pointmarkerlist       = PETSC_NULL;
4930   outputCtx->numberoftriangles     = 0;
4931   outputCtx->trianglelist          = PETSC_NULL;
4932   outputCtx->triangleattributelist = PETSC_NULL;
4933   outputCtx->neighborlist          = PETSC_NULL;
4934   outputCtx->segmentlist           = PETSC_NULL;
4935   outputCtx->segmentmarkerlist     = PETSC_NULL;
4936   outputCtx->numberofedges         = 0;
4937   outputCtx->edgelist              = PETSC_NULL;
4938   outputCtx->edgemarkerlist        = PETSC_NULL;
4939   PetscFunctionReturn(0);
4940 }
4941 
4942 #undef __FUNCT__
4943 #define __FUNCT__ "FiniOutput_Triangle"
4944 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4945 {
4946   PetscFunctionBegin;
4947   free(outputCtx->pointmarkerlist);
4948   free(outputCtx->edgelist);
4949   free(outputCtx->edgemarkerlist);
4950   free(outputCtx->trianglelist);
4951   free(outputCtx->neighborlist);
4952   PetscFunctionReturn(0);
4953 }
4954 
4955 #undef __FUNCT__
4956 #define __FUNCT__ "DMPlexGenerate_Triangle"
4957 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4958 {
4959   MPI_Comm             comm             = ((PetscObject) boundary)->comm;
4960   PetscInt             dim              = 2;
4961   const PetscBool      createConvexHull = PETSC_FALSE;
4962   const PetscBool      constrained      = PETSC_FALSE;
4963   struct triangulateio in;
4964   struct triangulateio out;
4965   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4966   PetscMPIInt          rank;
4967   PetscErrorCode       ierr;
4968 
4969   PetscFunctionBegin;
4970   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4971   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4972   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4973   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4974 
4975   in.numberofpoints = vEnd - vStart;
4976   if (in.numberofpoints > 0) {
4977     PetscSection coordSection;
4978     Vec          coordinates;
4979     PetscScalar *array;
4980 
4981     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4982     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4983     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4984     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4985     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4986     for (v = vStart; v < vEnd; ++v) {
4987       const PetscInt idx = v - vStart;
4988       PetscInt       off, d;
4989 
4990       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4991       for (d = 0; d < dim; ++d) {
4992         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4993       }
4994       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4995     }
4996     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4997   }
4998   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4999   in.numberofsegments = eEnd - eStart;
5000   if (in.numberofsegments > 0) {
5001     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
5002     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
5003     for (e = eStart; e < eEnd; ++e) {
5004       const PetscInt  idx = e - eStart;
5005       const PetscInt *cone;
5006 
5007       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
5008 
5009       in.segmentlist[idx*2+0] = cone[0] - vStart;
5010       in.segmentlist[idx*2+1] = cone[1] - vStart;
5011 
5012       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5013     }
5014   }
5015 #if 0 /* Do not currently support holes */
5016   PetscReal *holeCoords;
5017   PetscInt   h, d;
5018 
5019   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5020   if (in.numberofholes > 0) {
5021     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5022     for (h = 0; h < in.numberofholes; ++h) {
5023       for (d = 0; d < dim; ++d) {
5024         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5025       }
5026     }
5027   }
5028 #endif
5029   if (!rank) {
5030     char args[32];
5031 
5032     /* Take away 'Q' for verbose output */
5033     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5034     if (createConvexHull) {
5035       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5036     }
5037     if (constrained) {
5038       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5039     }
5040     triangulate(args, &in, &out, PETSC_NULL);
5041   }
5042   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5043   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5044   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5045   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5046   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5047 
5048   {
5049     const PetscInt numCorners  = 3;
5050     const PetscInt numCells    = out.numberoftriangles;
5051     const PetscInt numVertices = out.numberofpoints;
5052     const int     *cells      = out.trianglelist;
5053     const double  *meshCoords = out.pointlist;
5054 
5055     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5056     /* Set labels */
5057     for (v = 0; v < numVertices; ++v) {
5058       if (out.pointmarkerlist[v]) {
5059         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5060       }
5061     }
5062     if (interpolate) {
5063       for (e = 0; e < out.numberofedges; e++) {
5064         if (out.edgemarkerlist[e]) {
5065           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5066           const PetscInt *edges;
5067           PetscInt        numEdges;
5068 
5069           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5070           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5071           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5072           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5073         }
5074       }
5075     }
5076     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5077   }
5078 #if 0 /* Do not currently support holes */
5079   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5080 #endif
5081   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5082   PetscFunctionReturn(0);
5083 }
5084 
5085 #undef __FUNCT__
5086 #define __FUNCT__ "DMPlexRefine_Triangle"
5087 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5088 {
5089   MPI_Comm             comm = ((PetscObject) dm)->comm;
5090   PetscInt             dim  = 2;
5091   struct triangulateio in;
5092   struct triangulateio out;
5093   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5094   PetscMPIInt          rank;
5095   PetscErrorCode       ierr;
5096 
5097   PetscFunctionBegin;
5098   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5099   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5100   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5101   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5102   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5103   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5104 
5105   in.numberofpoints = vEnd - vStart;
5106   if (in.numberofpoints > 0) {
5107     PetscSection coordSection;
5108     Vec          coordinates;
5109     PetscScalar *array;
5110 
5111     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5112     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5113     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5114     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5115     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5116     for (v = vStart; v < vEnd; ++v) {
5117       const PetscInt idx = v - vStart;
5118       PetscInt       off, d;
5119 
5120       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5121       for (d = 0; d < dim; ++d) {
5122         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5123       }
5124       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5125     }
5126     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5127   }
5128   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5129 
5130   in.numberofcorners   = 3;
5131   in.numberoftriangles = cEnd - cStart;
5132 
5133   in.trianglearealist  = (double*) maxVolumes;
5134   if (in.numberoftriangles > 0) {
5135     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5136     for (c = cStart; c < cEnd; ++c) {
5137       const PetscInt idx      = c - cStart;
5138       PetscInt      *closure = PETSC_NULL;
5139       PetscInt       closureSize;
5140 
5141       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5142       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5143       for (v = 0; v < 3; ++v) {
5144         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5145       }
5146       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5147     }
5148   }
5149   /* TODO: Segment markers are missing on input */
5150 #if 0 /* Do not currently support holes */
5151   PetscReal *holeCoords;
5152   PetscInt   h, d;
5153 
5154   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5155   if (in.numberofholes > 0) {
5156     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5157     for (h = 0; h < in.numberofholes; ++h) {
5158       for (d = 0; d < dim; ++d) {
5159         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5160       }
5161     }
5162   }
5163 #endif
5164   if (!rank) {
5165     char args[32];
5166 
5167     /* Take away 'Q' for verbose output */
5168     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5169     triangulate(args, &in, &out, PETSC_NULL);
5170   }
5171   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5172   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5173   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5174   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5175   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5176 
5177   {
5178     const PetscInt numCorners  = 3;
5179     const PetscInt numCells    = out.numberoftriangles;
5180     const PetscInt numVertices = out.numberofpoints;
5181     const int     *cells      = out.trianglelist;
5182     const double  *meshCoords = out.pointlist;
5183     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5184 
5185     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5186     /* Set labels */
5187     for (v = 0; v < numVertices; ++v) {
5188       if (out.pointmarkerlist[v]) {
5189         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5190       }
5191     }
5192     if (interpolate) {
5193       PetscInt e;
5194 
5195       for (e = 0; e < out.numberofedges; e++) {
5196         if (out.edgemarkerlist[e]) {
5197           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5198           const PetscInt *edges;
5199           PetscInt        numEdges;
5200 
5201           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5202           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5203           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5204           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5205         }
5206       }
5207     }
5208     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5209   }
5210 #if 0 /* Do not currently support holes */
5211   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5212 #endif
5213   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5214   PetscFunctionReturn(0);
5215 }
5216 #endif
5217 
5218 #if defined(PETSC_HAVE_TETGEN)
5219 #include <tetgen.h>
5220 #undef __FUNCT__
5221 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5222 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5223 {
5224   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5225   const PetscInt dim  = 3;
5226   ::tetgenio     in;
5227   ::tetgenio     out;
5228   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5229   PetscMPIInt    rank;
5230   PetscErrorCode ierr;
5231 
5232   PetscFunctionBegin;
5233   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5234   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5235   in.numberofpoints = vEnd - vStart;
5236   if (in.numberofpoints > 0) {
5237     PetscSection coordSection;
5238     Vec          coordinates;
5239     PetscScalar *array;
5240 
5241     in.pointlist       = new double[in.numberofpoints*dim];
5242     in.pointmarkerlist = new int[in.numberofpoints];
5243 
5244     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5245     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5246     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5247     for (v = vStart; v < vEnd; ++v) {
5248       const PetscInt idx = v - vStart;
5249       PetscInt       off, d;
5250 
5251       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5252       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5253       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5254     }
5255     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5256   }
5257   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5258 
5259   in.numberoffacets = fEnd - fStart;
5260   if (in.numberoffacets > 0) {
5261     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5262     in.facetmarkerlist = new int[in.numberoffacets];
5263     for (f = fStart; f < fEnd; ++f) {
5264       const PetscInt idx     = f - fStart;
5265       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5266 
5267       in.facetlist[idx].numberofpolygons = 1;
5268       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5269       in.facetlist[idx].numberofholes    = 0;
5270       in.facetlist[idx].holelist         = NULL;
5271 
5272       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5273       for (p = 0; p < numPoints*2; p += 2) {
5274         const PetscInt point = points[p];
5275         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5276       }
5277 
5278       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5279       poly->numberofvertices = numVertices;
5280       poly->vertexlist       = new int[poly->numberofvertices];
5281       for (v = 0; v < numVertices; ++v) {
5282         const PetscInt vIdx = points[v] - vStart;
5283         poly->vertexlist[v] = vIdx;
5284       }
5285       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5286       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5287     }
5288   }
5289   if (!rank) {
5290     char args[32];
5291 
5292     /* Take away 'Q' for verbose output */
5293     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5294     ::tetrahedralize(args, &in, &out);
5295   }
5296   {
5297     const PetscInt numCorners  = 4;
5298     const PetscInt numCells    = out.numberoftetrahedra;
5299     const PetscInt numVertices = out.numberofpoints;
5300     const int     *cells      = out.tetrahedronlist;
5301     const double  *meshCoords = out.pointlist;
5302 
5303     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5304     /* Set labels */
5305     for (v = 0; v < numVertices; ++v) {
5306       if (out.pointmarkerlist[v]) {
5307         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5308       }
5309     }
5310     if (interpolate) {
5311       PetscInt e;
5312 
5313       for (e = 0; e < out.numberofedges; e++) {
5314         if (out.edgemarkerlist[e]) {
5315           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5316           const PetscInt *edges;
5317           PetscInt        numEdges;
5318 
5319           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5320           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5321           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5322           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5323         }
5324       }
5325       for (f = 0; f < out.numberoftrifaces; f++) {
5326         if (out.trifacemarkerlist[f]) {
5327           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5328           const PetscInt *faces;
5329           PetscInt        numFaces;
5330 
5331           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5332           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5333           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5334           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5335         }
5336       }
5337     }
5338     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5339   }
5340   PetscFunctionReturn(0);
5341 }
5342 
5343 #undef __FUNCT__
5344 #define __FUNCT__ "DMPlexRefine_Tetgen"
5345 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5346 {
5347   MPI_Comm       comm = ((PetscObject) dm)->comm;
5348   const PetscInt dim  = 3;
5349   ::tetgenio     in;
5350   ::tetgenio     out;
5351   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5352   PetscMPIInt    rank;
5353   PetscErrorCode ierr;
5354 
5355   PetscFunctionBegin;
5356   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5357   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5358   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5359   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5360 
5361   in.numberofpoints = vEnd - vStart;
5362   if (in.numberofpoints > 0) {
5363     PetscSection coordSection;
5364     Vec          coordinates;
5365     PetscScalar *array;
5366 
5367     in.pointlist       = new double[in.numberofpoints*dim];
5368     in.pointmarkerlist = new int[in.numberofpoints];
5369 
5370     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5371     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5372     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5373     for (v = vStart; v < vEnd; ++v) {
5374       const PetscInt idx = v - vStart;
5375       PetscInt       off, d;
5376 
5377       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5378       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5379       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5380     }
5381     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5382   }
5383   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5384 
5385   in.numberofcorners       = 4;
5386   in.numberoftetrahedra    = cEnd - cStart;
5387   in.tetrahedronvolumelist = (double*) maxVolumes;
5388   if (in.numberoftetrahedra > 0) {
5389     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5390     for (c = cStart; c < cEnd; ++c) {
5391       const PetscInt idx      = c - cStart;
5392       PetscInt      *closure = PETSC_NULL;
5393       PetscInt       closureSize;
5394 
5395       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5396       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5397       for (v = 0; v < 4; ++v) {
5398         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5399       }
5400       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5401     }
5402   }
5403   /* TODO: Put in boundary faces with markers */
5404   if (!rank) {
5405     char args[32];
5406 
5407     /* Take away 'Q' for verbose output */
5408     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5409     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5410     ::tetrahedralize(args, &in, &out);
5411   }
5412   in.tetrahedronvolumelist = NULL;
5413 
5414   {
5415     const PetscInt numCorners  = 4;
5416     const PetscInt numCells    = out.numberoftetrahedra;
5417     const PetscInt numVertices = out.numberofpoints;
5418     const int     *cells      = out.tetrahedronlist;
5419     const double  *meshCoords = out.pointlist;
5420     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5421 
5422     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5423     /* Set labels */
5424     for (v = 0; v < numVertices; ++v) {
5425       if (out.pointmarkerlist[v]) {
5426         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5427       }
5428     }
5429     if (interpolate) {
5430       PetscInt e, f;
5431 
5432       for (e = 0; e < out.numberofedges; e++) {
5433         if (out.edgemarkerlist[e]) {
5434           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5435           const PetscInt *edges;
5436           PetscInt        numEdges;
5437 
5438           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5439           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5440           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5441           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5442         }
5443       }
5444       for (f = 0; f < out.numberoftrifaces; f++) {
5445         if (out.trifacemarkerlist[f]) {
5446           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5447           const PetscInt *faces;
5448           PetscInt        numFaces;
5449 
5450           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5451           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5452           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5453           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5454         }
5455       }
5456     }
5457     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5458   }
5459   PetscFunctionReturn(0);
5460 }
5461 #endif
5462 
5463 #if defined(PETSC_HAVE_CTETGEN)
5464 #include "ctetgen.h"
5465 
5466 #undef __FUNCT__
5467 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5468 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5469 {
5470   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5471   const PetscInt dim  = 3;
5472   PLC           *in, *out;
5473   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5474   PetscMPIInt    rank;
5475   PetscErrorCode ierr;
5476 
5477   PetscFunctionBegin;
5478   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5479   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5480   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5481   ierr = PLCCreate(&in);CHKERRQ(ierr);
5482   ierr = PLCCreate(&out);CHKERRQ(ierr);
5483 
5484   in->numberofpoints = vEnd - vStart;
5485   if (in->numberofpoints > 0) {
5486     PetscSection coordSection;
5487     Vec          coordinates;
5488     PetscScalar *array;
5489 
5490     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5491     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5492     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5493     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5494     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5495     for (v = vStart; v < vEnd; ++v) {
5496       const PetscInt idx = v - vStart;
5497       PetscInt       off, d, m;
5498 
5499       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5500       for (d = 0; d < dim; ++d) {
5501         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5502       }
5503       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5504 
5505       in->pointmarkerlist[idx] = (int) m;
5506     }
5507     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5508   }
5509   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5510 
5511   in->numberoffacets = fEnd - fStart;
5512   if (in->numberoffacets > 0) {
5513     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5514     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5515     for (f = fStart; f < fEnd; ++f) {
5516       const PetscInt idx     = f - fStart;
5517       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5518       polygon       *poly;
5519 
5520       in->facetlist[idx].numberofpolygons = 1;
5521 
5522       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5523 
5524       in->facetlist[idx].numberofholes    = 0;
5525       in->facetlist[idx].holelist         = PETSC_NULL;
5526 
5527       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5528       for (p = 0; p < numPoints*2; p += 2) {
5529         const PetscInt point = points[p];
5530         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5531       }
5532 
5533       poly                   = in->facetlist[idx].polygonlist;
5534       poly->numberofvertices = numVertices;
5535       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5536       for (v = 0; v < numVertices; ++v) {
5537         const PetscInt vIdx = points[v] - vStart;
5538         poly->vertexlist[v] = vIdx;
5539       }
5540       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5541       in->facetmarkerlist[idx] = (int) m;
5542       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5543     }
5544   }
5545   if (!rank) {
5546     TetGenOpts t;
5547 
5548     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5549     t.in        = boundary; /* Should go away */
5550     t.plc       = 1;
5551     t.quality   = 1;
5552     t.edgesout  = 1;
5553     t.zeroindex = 1;
5554     t.quiet     = 1;
5555     t.verbose   = verbose;
5556     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5557     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5558   }
5559   {
5560     const PetscInt numCorners  = 4;
5561     const PetscInt numCells    = out->numberoftetrahedra;
5562     const PetscInt numVertices = out->numberofpoints;
5563     const int     *cells      = out->tetrahedronlist;
5564     const double  *meshCoords = out->pointlist;
5565 
5566     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5567     /* Set labels */
5568     for (v = 0; v < numVertices; ++v) {
5569       if (out->pointmarkerlist[v]) {
5570         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5571       }
5572     }
5573     if (interpolate) {
5574       PetscInt e;
5575 
5576       for (e = 0; e < out->numberofedges; e++) {
5577         if (out->edgemarkerlist[e]) {
5578           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5579           const PetscInt *edges;
5580           PetscInt        numEdges;
5581 
5582           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5583           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5584           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5585           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5586         }
5587       }
5588       for (f = 0; f < out->numberoftrifaces; f++) {
5589         if (out->trifacemarkerlist[f]) {
5590           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5591           const PetscInt *faces;
5592           PetscInt        numFaces;
5593 
5594           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5595           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5596           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5597           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5598         }
5599       }
5600     }
5601     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5602   }
5603 
5604   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5605   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5606   PetscFunctionReturn(0);
5607 }
5608 
5609 #undef __FUNCT__
5610 #define __FUNCT__ "DMPlexRefine_CTetgen"
5611 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5612 {
5613   MPI_Comm       comm = ((PetscObject) dm)->comm;
5614   const PetscInt dim  = 3;
5615   PLC           *in, *out;
5616   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5617   PetscMPIInt    rank;
5618   PetscErrorCode ierr;
5619 
5620   PetscFunctionBegin;
5621   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5622   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5623   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5624   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5625   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5626   ierr = PLCCreate(&in);CHKERRQ(ierr);
5627   ierr = PLCCreate(&out);CHKERRQ(ierr);
5628 
5629   in->numberofpoints = vEnd - vStart;
5630   if (in->numberofpoints > 0) {
5631     PetscSection coordSection;
5632     Vec          coordinates;
5633     PetscScalar *array;
5634 
5635     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5636     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5637     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5638     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5639     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5640     for (v = vStart; v < vEnd; ++v) {
5641       const PetscInt idx = v - vStart;
5642       PetscInt       off, d, m;
5643 
5644       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5645       for (d = 0; d < dim; ++d) {
5646         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5647       }
5648       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5649 
5650       in->pointmarkerlist[idx] = (int) m;
5651     }
5652     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5653   }
5654   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5655 
5656   in->numberofcorners       = 4;
5657   in->numberoftetrahedra    = cEnd - cStart;
5658   in->tetrahedronvolumelist = maxVolumes;
5659   if (in->numberoftetrahedra > 0) {
5660     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5661     for (c = cStart; c < cEnd; ++c) {
5662       const PetscInt idx      = c - cStart;
5663       PetscInt      *closure = PETSC_NULL;
5664       PetscInt       closureSize;
5665 
5666       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5667       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5668       for (v = 0; v < 4; ++v) {
5669         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5670       }
5671       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5672     }
5673   }
5674   if (!rank) {
5675     TetGenOpts t;
5676 
5677     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5678 
5679     t.in        = dm; /* Should go away */
5680     t.refine    = 1;
5681     t.varvolume = 1;
5682     t.quality   = 1;
5683     t.edgesout  = 1;
5684     t.zeroindex = 1;
5685     t.quiet     = 1;
5686     t.verbose   = verbose; /* Change this */
5687 
5688     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5689     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5690   }
5691   {
5692     const PetscInt numCorners  = 4;
5693     const PetscInt numCells    = out->numberoftetrahedra;
5694     const PetscInt numVertices = out->numberofpoints;
5695     const int     *cells       = out->tetrahedronlist;
5696     const double  *meshCoords  = out->pointlist;
5697     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5698 
5699     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5700     /* Set labels */
5701     for (v = 0; v < numVertices; ++v) {
5702       if (out->pointmarkerlist[v]) {
5703         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5704       }
5705     }
5706     if (interpolate) {
5707       PetscInt e, f;
5708 
5709       for (e = 0; e < out->numberofedges; e++) {
5710         if (out->edgemarkerlist[e]) {
5711           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5712           const PetscInt *edges;
5713           PetscInt        numEdges;
5714 
5715           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5716           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5717           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5718           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5719         }
5720       }
5721       for (f = 0; f < out->numberoftrifaces; f++) {
5722         if (out->trifacemarkerlist[f]) {
5723           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5724           const PetscInt *faces;
5725           PetscInt        numFaces;
5726 
5727           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5728           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5729           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5730           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5731         }
5732       }
5733     }
5734     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5735   }
5736   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5737   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5738   PetscFunctionReturn(0);
5739 }
5740 #endif
5741 
5742 #undef __FUNCT__
5743 #define __FUNCT__ "DMPlexGenerate"
5744 /*@C
5745   DMPlexGenerate - Generates a mesh.
5746 
5747   Not Collective
5748 
5749   Input Parameters:
5750 + boundary - The DMPlex boundary object
5751 . name - The mesh generation package name
5752 - interpolate - Flag to create intermediate mesh elements
5753 
5754   Output Parameter:
5755 . mesh - The DMPlex object
5756 
5757   Level: intermediate
5758 
5759 .keywords: mesh, elements
5760 .seealso: DMPlexCreate(), DMRefine()
5761 @*/
5762 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5763 {
5764   PetscInt       dim;
5765   char           genname[1024];
5766   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5767   PetscErrorCode ierr;
5768 
5769   PetscFunctionBegin;
5770   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5771   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5772   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5773   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5774   if (flg) name = genname;
5775   if (name) {
5776     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5777     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5778     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5779   }
5780   switch (dim) {
5781   case 1:
5782     if (!name || isTriangle) {
5783 #if defined(PETSC_HAVE_TRIANGLE)
5784       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5785 #else
5786       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5787 #endif
5788     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5789     break;
5790   case 2:
5791     if (!name || isCTetgen) {
5792 #if defined(PETSC_HAVE_CTETGEN)
5793       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5794 #else
5795       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5796 #endif
5797     } else if (isTetgen) {
5798 #if defined(PETSC_HAVE_TETGEN)
5799       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5800 #else
5801       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5802 #endif
5803     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5804     break;
5805   default:
5806     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5807   }
5808   PetscFunctionReturn(0);
5809 }
5810 
5811 typedef PetscInt CellRefiner;
5812 
5813 #undef __FUNCT__
5814 #define __FUNCT__ "GetDepthStart_Private"
5815 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5816 {
5817   PetscFunctionBegin;
5818   if (cStart) *cStart = 0;
5819   if (vStart) *vStart = depthSize[depth];
5820   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5821   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5822   PetscFunctionReturn(0);
5823 }
5824 
5825 #undef __FUNCT__
5826 #define __FUNCT__ "GetDepthEnd_Private"
5827 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5828 {
5829   PetscFunctionBegin;
5830   if (cEnd) *cEnd = depthSize[depth];
5831   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5832   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5833   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5834   PetscFunctionReturn(0);
5835 }
5836 
5837 #undef __FUNCT__
5838 #define __FUNCT__ "CellRefinerGetSizes"
5839 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5840 {
5841   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5842   PetscErrorCode ierr;
5843 
5844   PetscFunctionBegin;
5845   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5846   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5847   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5848   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5849   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5850   switch (refiner) {
5851   case 1:
5852     /* Simplicial 2D */
5853     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5854     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5855     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5856     break;
5857   case 3:
5858     /* Hybrid 2D */
5859     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5860     cMax = PetscMin(cEnd, cMax);
5861     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5862     fMax         = PetscMin(fEnd, fMax);
5863     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5864     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 */
5865     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5866     break;
5867   case 2:
5868     /* Hex 2D */
5869     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5870     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5871     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5872     break;
5873   default:
5874     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5875   }
5876   PetscFunctionReturn(0);
5877 }
5878 
5879 #undef __FUNCT__
5880 #define __FUNCT__ "CellRefinerSetConeSizes"
5881 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5882 {
5883   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5884   PetscErrorCode ierr;
5885 
5886   PetscFunctionBegin;
5887   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5888   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5889   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5890   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5891   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5892   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5893   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5894   switch (refiner) {
5895   case 1:
5896     /* Simplicial 2D */
5897     /* All cells have 3 faces */
5898     for (c = cStart; c < cEnd; ++c) {
5899       for (r = 0; r < 4; ++r) {
5900         const PetscInt newp = (c - cStart)*4 + r;
5901 
5902         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5903       }
5904     }
5905     /* Split faces have 2 vertices and the same cells as the parent */
5906     for (f = fStart; f < fEnd; ++f) {
5907       for (r = 0; r < 2; ++r) {
5908         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5909         PetscInt       size;
5910 
5911         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5912         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5913         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5914       }
5915     }
5916     /* Interior faces have 2 vertices and 2 cells */
5917     for (c = cStart; c < cEnd; ++c) {
5918       for (r = 0; r < 3; ++r) {
5919         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5920 
5921         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5922         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5923       }
5924     }
5925     /* Old vertices have identical supports */
5926     for (v = vStart; v < vEnd; ++v) {
5927       const PetscInt newp = vStartNew + (v - vStart);
5928       PetscInt       size;
5929 
5930       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5931       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5932     }
5933     /* Face vertices have 2 + cells*2 supports */
5934     for (f = fStart; f < fEnd; ++f) {
5935       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5936       PetscInt       size;
5937 
5938       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5939       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5940     }
5941     break;
5942   case 2:
5943     /* Hex 2D */
5944     /* All cells have 4 faces */
5945     for (c = cStart; c < cEnd; ++c) {
5946       for (r = 0; r < 4; ++r) {
5947         const PetscInt newp = (c - cStart)*4 + r;
5948 
5949         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5950       }
5951     }
5952     /* Split faces have 2 vertices and the same cells as the parent */
5953     for (f = fStart; f < fEnd; ++f) {
5954       for (r = 0; r < 2; ++r) {
5955         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5956         PetscInt       size;
5957 
5958         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5959         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5960         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5961       }
5962     }
5963     /* Interior faces have 2 vertices and 2 cells */
5964     for (c = cStart; c < cEnd; ++c) {
5965       for (r = 0; r < 4; ++r) {
5966         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5967 
5968         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5969         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5970       }
5971     }
5972     /* Old vertices have identical supports */
5973     for (v = vStart; v < vEnd; ++v) {
5974       const PetscInt newp = vStartNew + (v - vStart);
5975       PetscInt       size;
5976 
5977       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5978       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5979     }
5980     /* Face vertices have 2 + cells supports */
5981     for (f = fStart; f < fEnd; ++f) {
5982       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5983       PetscInt       size;
5984 
5985       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5986       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5987     }
5988     /* Cell vertices have 4 supports */
5989     for (c = cStart; c < cEnd; ++c) {
5990       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5991 
5992       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5993     }
5994     break;
5995   case 3:
5996     /* Hybrid 2D */
5997     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5998     cMax = PetscMin(cEnd, cMax);
5999     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6000     fMax = PetscMin(fEnd, fMax);
6001     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6002     /* Interior cells have 3 faces */
6003     for (c = cStart; c < cMax; ++c) {
6004       for (r = 0; r < 4; ++r) {
6005         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
6006 
6007         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
6008       }
6009     }
6010     /* Hybrid cells have 4 faces */
6011     for (c = cMax; c < cEnd; ++c) {
6012       for (r = 0; r < 2; ++r) {
6013         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6014 
6015         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6016       }
6017     }
6018     /* Interior split faces have 2 vertices and the same cells as the parent */
6019     for (f = fStart; f < fMax; ++f) {
6020       for (r = 0; r < 2; ++r) {
6021         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6022         PetscInt       size;
6023 
6024         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6025         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6026         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6027       }
6028     }
6029     /* Interior cell faces have 2 vertices and 2 cells */
6030     for (c = cStart; c < cMax; ++c) {
6031       for (r = 0; r < 3; ++r) {
6032         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6033 
6034         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6035         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6036       }
6037     }
6038     /* Hybrid faces have 2 vertices and the same cells */
6039     for (f = fMax; f < fEnd; ++f) {
6040       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6041       PetscInt       size;
6042 
6043       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6044       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6045       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6046     }
6047     /* Hybrid cell faces have 2 vertices and 2 cells */
6048     for (c = cMax; c < cEnd; ++c) {
6049       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6050 
6051       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6052       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6053     }
6054     /* Old vertices have identical supports */
6055     for (v = vStart; v < vEnd; ++v) {
6056       const PetscInt newp = vStartNew + (v - vStart);
6057       PetscInt       size;
6058 
6059       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6060       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6061     }
6062     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6063     for (f = fStart; f < fMax; ++f) {
6064       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6065       const PetscInt *support;
6066       PetscInt       size, newSize = 2, s;
6067 
6068       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6069       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6070       for (s = 0; s < size; ++s) {
6071         if (support[s] >= cMax) newSize += 1;
6072         else newSize += 2;
6073       }
6074       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6075     }
6076     break;
6077   default:
6078     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6079   }
6080   PetscFunctionReturn(0);
6081 }
6082 
6083 #undef __FUNCT__
6084 #define __FUNCT__ "CellRefinerSetCones"
6085 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6086 {
6087   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;
6088   PetscInt       maxSupportSize, *supportRef;
6089   PetscErrorCode ierr;
6090 
6091   PetscFunctionBegin;
6092   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6093   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6094   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6095   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6096   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6097   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6098   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6099   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6100   switch (refiner) {
6101   case 1:
6102     /* Simplicial 2D */
6103     /*
6104      2
6105      |\
6106      | \
6107      |  \
6108      |   \
6109      | C  \
6110      |     \
6111      |      \
6112      2---1---1
6113      |\  D  / \
6114      | 2   0   \
6115      |A \ /  B  \
6116      0---0-------1
6117      */
6118     /* All cells have 3 faces */
6119     for (c = cStart; c < cEnd; ++c) {
6120       const PetscInt  newp = cStartNew + (c - cStart)*4;
6121       const PetscInt *cone, *ornt;
6122       PetscInt        coneNew[3], orntNew[3];
6123 
6124       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6125       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6126       /* A triangle */
6127       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6128       orntNew[0] = ornt[0];
6129       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6130       orntNew[1] = -2;
6131       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6132       orntNew[2] = ornt[2];
6133       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6134       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6135 #if 1
6136       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);
6137       for (p = 0; p < 3; ++p) {
6138         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);
6139       }
6140 #endif
6141       /* B triangle */
6142       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6143       orntNew[0] = ornt[0];
6144       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6145       orntNew[1] = ornt[1];
6146       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6147       orntNew[2] = -2;
6148       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6149       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6150 #if 1
6151       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);
6152       for (p = 0; p < 3; ++p) {
6153         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);
6154       }
6155 #endif
6156       /* C triangle */
6157       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6158       orntNew[0] = -2;
6159       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6160       orntNew[1] = ornt[1];
6161       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6162       orntNew[2] = ornt[2];
6163       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6164       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6165 #if 1
6166       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);
6167       for (p = 0; p < 3; ++p) {
6168         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);
6169       }
6170 #endif
6171       /* D triangle */
6172       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6173       orntNew[0] = 0;
6174       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6175       orntNew[1] = 0;
6176       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6177       orntNew[2] = 0;
6178       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6179       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6180 #if 1
6181       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);
6182       for (p = 0; p < 3; ++p) {
6183         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6184       }
6185 #endif
6186     }
6187     /* Split faces have 2 vertices and the same cells as the parent */
6188     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6189     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6190     for (f = fStart; f < fEnd; ++f) {
6191       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6192 
6193       for (r = 0; r < 2; ++r) {
6194         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6195         const PetscInt *cone, *support;
6196         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6197 
6198         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6199         coneNew[0]       = vStartNew + (cone[0] - vStart);
6200         coneNew[1]       = vStartNew + (cone[1] - vStart);
6201         coneNew[(r+1)%2] = newv;
6202         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6203 #if 1
6204         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6205         for (p = 0; p < 2; ++p) {
6206           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);
6207         }
6208 #endif
6209         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6210         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6211         for (s = 0; s < supportSize; ++s) {
6212           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6213           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6214           for (c = 0; c < coneSize; ++c) {
6215             if (cone[c] == f) break;
6216           }
6217           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6218         }
6219         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6220 #if 1
6221         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6222         for (p = 0; p < supportSize; ++p) {
6223           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);
6224         }
6225 #endif
6226       }
6227     }
6228     /* Interior faces have 2 vertices and 2 cells */
6229     for (c = cStart; c < cEnd; ++c) {
6230       const PetscInt *cone;
6231 
6232       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6233       for (r = 0; r < 3; ++r) {
6234         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6235         PetscInt       coneNew[2];
6236         PetscInt       supportNew[2];
6237 
6238         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6239         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6240         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6241 #if 1
6242         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6243         for (p = 0; p < 2; ++p) {
6244           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);
6245         }
6246 #endif
6247         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6248         supportNew[1] = (c - cStart)*4 + 3;
6249         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6250 #if 1
6251         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6252         for (p = 0; p < 2; ++p) {
6253           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);
6254         }
6255 #endif
6256       }
6257     }
6258     /* Old vertices have identical supports */
6259     for (v = vStart; v < vEnd; ++v) {
6260       const PetscInt  newp = vStartNew + (v - vStart);
6261       const PetscInt *support, *cone;
6262       PetscInt        size, s;
6263 
6264       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6265       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6266       for (s = 0; s < size; ++s) {
6267         PetscInt r = 0;
6268 
6269         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6270         if (cone[1] == v) r = 1;
6271         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6272       }
6273       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6274 #if 1
6275       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6276       for (p = 0; p < size; ++p) {
6277         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);
6278       }
6279 #endif
6280     }
6281     /* Face vertices have 2 + cells*2 supports */
6282     for (f = fStart; f < fEnd; ++f) {
6283       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6284       const PetscInt *cone, *support;
6285       PetscInt        size, s;
6286 
6287       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6288       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6289       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6290       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6291       for (s = 0; s < size; ++s) {
6292         PetscInt r = 0;
6293 
6294         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6295         if      (cone[1] == f) r = 1;
6296         else if (cone[2] == f) r = 2;
6297         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6298         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6299       }
6300       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6301 #if 1
6302       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6303       for (p = 0; p < 2+size*2; ++p) {
6304         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);
6305       }
6306 #endif
6307     }
6308     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6309     break;
6310   case 2:
6311     /* Hex 2D */
6312     /*
6313      3---------2---------2
6314      |         |         |
6315      |    D    2    C    |
6316      |         |         |
6317      3----3----0----1----1
6318      |         |         |
6319      |    A    0    B    |
6320      |         |         |
6321      0---------0---------1
6322      */
6323     /* All cells have 4 faces */
6324     for (c = cStart; c < cEnd; ++c) {
6325       const PetscInt  newp = (c - cStart)*4;
6326       const PetscInt *cone, *ornt;
6327       PetscInt        coneNew[4], orntNew[4];
6328 
6329       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6330       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6331       /* A quad */
6332       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6333       orntNew[0] = ornt[0];
6334       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6335       orntNew[1] = 0;
6336       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6337       orntNew[2] = -2;
6338       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6339       orntNew[3] = ornt[3];
6340       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6341       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6342 #if 1
6343       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);
6344       for (p = 0; p < 4; ++p) {
6345         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);
6346       }
6347 #endif
6348       /* B quad */
6349       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6350       orntNew[0] = ornt[0];
6351       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6352       orntNew[1] = ornt[1];
6353       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6354       orntNew[2] = 0;
6355       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6356       orntNew[3] = -2;
6357       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6358       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6359 #if 1
6360       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);
6361       for (p = 0; p < 4; ++p) {
6362         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);
6363       }
6364 #endif
6365       /* C quad */
6366       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6367       orntNew[0] = -2;
6368       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6369       orntNew[1] = ornt[1];
6370       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6371       orntNew[2] = ornt[2];
6372       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6373       orntNew[3] = 0;
6374       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6375       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6376 #if 1
6377       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);
6378       for (p = 0; p < 4; ++p) {
6379         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);
6380       }
6381 #endif
6382       /* D quad */
6383       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6384       orntNew[0] = 0;
6385       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6386       orntNew[1] = -2;
6387       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6388       orntNew[2] = ornt[2];
6389       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6390       orntNew[3] = ornt[3];
6391       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6392       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6393 #if 1
6394       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);
6395       for (p = 0; p < 4; ++p) {
6396         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6397       }
6398 #endif
6399     }
6400     /* Split faces have 2 vertices and the same cells as the parent */
6401     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6402     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6403     for (f = fStart; f < fEnd; ++f) {
6404       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6405 
6406       for (r = 0; r < 2; ++r) {
6407         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6408         const PetscInt *cone, *support;
6409         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6410 
6411         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6412         coneNew[0]       = vStartNew + (cone[0] - vStart);
6413         coneNew[1]       = vStartNew + (cone[1] - vStart);
6414         coneNew[(r+1)%2] = newv;
6415         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6416 #if 1
6417         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6418         for (p = 0; p < 2; ++p) {
6419           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);
6420         }
6421 #endif
6422         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6423         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6424         for (s = 0; s < supportSize; ++s) {
6425           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6426           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6427           for (c = 0; c < coneSize; ++c) {
6428             if (cone[c] == f) break;
6429           }
6430           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6431         }
6432         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6433 #if 1
6434         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6435         for (p = 0; p < supportSize; ++p) {
6436           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);
6437         }
6438 #endif
6439       }
6440     }
6441     /* Interior faces have 2 vertices and 2 cells */
6442     for (c = cStart; c < cEnd; ++c) {
6443       const PetscInt *cone;
6444       PetscInt        coneNew[2], supportNew[2];
6445 
6446       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6447       for (r = 0; r < 4; ++r) {
6448         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6449 
6450         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6451         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6452         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6453 #if 1
6454         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6455         for (p = 0; p < 2; ++p) {
6456           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);
6457         }
6458 #endif
6459         supportNew[0] = (c - cStart)*4 + r;
6460         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6461         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6462 #if 1
6463         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6464         for (p = 0; p < 2; ++p) {
6465           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);
6466         }
6467 #endif
6468       }
6469     }
6470     /* Old vertices have identical supports */
6471     for (v = vStart; v < vEnd; ++v) {
6472       const PetscInt  newp = vStartNew + (v - vStart);
6473       const PetscInt *support, *cone;
6474       PetscInt        size, s;
6475 
6476       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6477       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6478       for (s = 0; s < size; ++s) {
6479         PetscInt r = 0;
6480 
6481         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6482         if (cone[1] == v) r = 1;
6483         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6484       }
6485       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6486 #if 1
6487       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6488       for (p = 0; p < size; ++p) {
6489         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);
6490       }
6491 #endif
6492     }
6493     /* Face vertices have 2 + cells supports */
6494     for (f = fStart; f < fEnd; ++f) {
6495       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6496       const PetscInt *cone, *support;
6497       PetscInt        size, s;
6498 
6499       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6500       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6501       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6502       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6503       for (s = 0; s < size; ++s) {
6504         PetscInt r = 0;
6505 
6506         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6507         if      (cone[1] == f) r = 1;
6508         else if (cone[2] == f) r = 2;
6509         else if (cone[3] == f) r = 3;
6510         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6511       }
6512       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6513 #if 1
6514       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6515       for (p = 0; p < 2+size; ++p) {
6516         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);
6517       }
6518 #endif
6519     }
6520     /* Cell vertices have 4 supports */
6521     for (c = cStart; c < cEnd; ++c) {
6522       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6523       PetscInt       supportNew[4];
6524 
6525       for (r = 0; r < 4; ++r) {
6526         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6527       }
6528       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6529     }
6530     break;
6531   case 3:
6532     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6533     cMax = PetscMin(cEnd, cMax);
6534     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6535     fMax = PetscMin(fEnd, fMax);
6536     /* Interior cells have 3 faces */
6537     for (c = cStart; c < cMax; ++c) {
6538       const PetscInt  newp = cStartNew + (c - cStart)*4;
6539       const PetscInt *cone, *ornt;
6540       PetscInt        coneNew[3], orntNew[3];
6541 
6542       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6543       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6544       /* A triangle */
6545       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6546       orntNew[0] = ornt[0];
6547       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6548       orntNew[1] = -2;
6549       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6550       orntNew[2] = ornt[2];
6551       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6552       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6553 #if 1
6554       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);
6555       for (p = 0; p < 3; ++p) {
6556         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);
6557       }
6558 #endif
6559       /* B triangle */
6560       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6561       orntNew[0] = ornt[0];
6562       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6563       orntNew[1] = ornt[1];
6564       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6565       orntNew[2] = -2;
6566       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6567       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6568 #if 1
6569       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);
6570       for (p = 0; p < 3; ++p) {
6571         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);
6572       }
6573 #endif
6574       /* C triangle */
6575       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6576       orntNew[0] = -2;
6577       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6578       orntNew[1] = ornt[1];
6579       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6580       orntNew[2] = ornt[2];
6581       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6582       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6583 #if 1
6584       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);
6585       for (p = 0; p < 3; ++p) {
6586         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);
6587       }
6588 #endif
6589       /* D triangle */
6590       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6591       orntNew[0] = 0;
6592       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6593       orntNew[1] = 0;
6594       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6595       orntNew[2] = 0;
6596       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6597       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6598 #if 1
6599       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);
6600       for (p = 0; p < 3; ++p) {
6601         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);
6602       }
6603 #endif
6604     }
6605     /*
6606      2----3----3
6607      |         |
6608      |    B    |
6609      |         |
6610      0----4--- 1
6611      |         |
6612      |    A    |
6613      |         |
6614      0----2----1
6615      */
6616     /* Hybrid cells have 4 faces */
6617     for (c = cMax; c < cEnd; ++c) {
6618       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6619       const PetscInt *cone, *ornt;
6620       PetscInt        coneNew[4], orntNew[4];
6621 
6622       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6623       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6624       /* A quad */
6625       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6626       orntNew[0] = ornt[0];
6627       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6628       orntNew[1] = ornt[1];
6629       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6630       orntNew[2] = 0;
6631       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6632       orntNew[3] = 0;
6633       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6634       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6635 #if 1
6636       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);
6637       for (p = 0; p < 4; ++p) {
6638         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);
6639       }
6640 #endif
6641       /* B quad */
6642       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6643       orntNew[0] = ornt[0];
6644       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6645       orntNew[1] = ornt[1];
6646       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6647       orntNew[2] = 0;
6648       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6649       orntNew[3] = 0;
6650       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6651       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6652 #if 1
6653       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);
6654       for (p = 0; p < 4; ++p) {
6655         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);
6656       }
6657 #endif
6658     }
6659     /* Interior split faces have 2 vertices and the same cells as the parent */
6660     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6661     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6662     for (f = fStart; f < fMax; ++f) {
6663       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6664 
6665       for (r = 0; r < 2; ++r) {
6666         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6667         const PetscInt *cone, *support;
6668         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6669 
6670         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6671         coneNew[0]       = vStartNew + (cone[0] - vStart);
6672         coneNew[1]       = vStartNew + (cone[1] - vStart);
6673         coneNew[(r+1)%2] = newv;
6674         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6675 #if 1
6676         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6677         for (p = 0; p < 2; ++p) {
6678           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);
6679         }
6680 #endif
6681         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6682         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6683         for (s = 0; s < supportSize; ++s) {
6684           if (support[s] >= cMax) {
6685             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6686           } else {
6687             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6688             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6689             for (c = 0; c < coneSize; ++c) {
6690               if (cone[c] == f) break;
6691             }
6692             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6693           }
6694         }
6695         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6696 #if 1
6697         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6698         for (p = 0; p < supportSize; ++p) {
6699           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);
6700         }
6701 #endif
6702       }
6703     }
6704     /* Interior cell faces have 2 vertices and 2 cells */
6705     for (c = cStart; c < cMax; ++c) {
6706       const PetscInt *cone;
6707 
6708       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6709       for (r = 0; r < 3; ++r) {
6710         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6711         PetscInt       coneNew[2];
6712         PetscInt       supportNew[2];
6713 
6714         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6715         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6716         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6717 #if 1
6718         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6719         for (p = 0; p < 2; ++p) {
6720           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);
6721         }
6722 #endif
6723         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6724         supportNew[1] = (c - cStart)*4 + 3;
6725         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6726 #if 1
6727         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6728         for (p = 0; p < 2; ++p) {
6729           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);
6730         }
6731 #endif
6732       }
6733     }
6734     /* Interior hybrid faces have 2 vertices and the same cells */
6735     for (f = fMax; f < fEnd; ++f) {
6736       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6737       const PetscInt *cone;
6738       const PetscInt *support;
6739       PetscInt        coneNew[2];
6740       PetscInt        supportNew[2];
6741       PetscInt        size, s, r;
6742 
6743       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6744       coneNew[0] = vStartNew + (cone[0] - vStart);
6745       coneNew[1] = vStartNew + (cone[1] - vStart);
6746       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6747 #if 1
6748       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6749       for (p = 0; p < 2; ++p) {
6750         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);
6751       }
6752 #endif
6753       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6754       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6755       for (s = 0; s < size; ++s) {
6756         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6757         for (r = 0; r < 2; ++r) {
6758           if (cone[r+2] == f) break;
6759         }
6760         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6761       }
6762       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6763 #if 1
6764       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6765       for (p = 0; p < size; ++p) {
6766         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);
6767       }
6768 #endif
6769     }
6770     /* Cell hybrid faces have 2 vertices and 2 cells */
6771     for (c = cMax; c < cEnd; ++c) {
6772       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6773       const PetscInt *cone;
6774       PetscInt        coneNew[2];
6775       PetscInt        supportNew[2];
6776 
6777       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6778       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6779       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6780       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6781 #if 1
6782       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6783       for (p = 0; p < 2; ++p) {
6784         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);
6785       }
6786 #endif
6787       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6788       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6789       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6790 #if 1
6791       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6792       for (p = 0; p < 2; ++p) {
6793         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);
6794       }
6795 #endif
6796     }
6797     /* Old vertices have identical supports */
6798     for (v = vStart; v < vEnd; ++v) {
6799       const PetscInt  newp = vStartNew + (v - vStart);
6800       const PetscInt *support, *cone;
6801       PetscInt        size, s;
6802 
6803       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6804       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6805       for (s = 0; s < size; ++s) {
6806         if (support[s] >= fMax) {
6807           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6808         } else {
6809           PetscInt r = 0;
6810 
6811           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6812           if (cone[1] == v) r = 1;
6813           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6814         }
6815       }
6816       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6817 #if 1
6818       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6819       for (p = 0; p < size; ++p) {
6820         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);
6821       }
6822 #endif
6823     }
6824     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6825     for (f = fStart; f < fMax; ++f) {
6826       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6827       const PetscInt *cone, *support;
6828       PetscInt        size, newSize = 2, s;
6829 
6830       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6831       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6832       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6833       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6834       for (s = 0; s < size; ++s) {
6835         PetscInt r = 0;
6836 
6837         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6838         if (support[s] >= cMax) {
6839           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6840 
6841           newSize += 1;
6842         } else {
6843           if      (cone[1] == f) r = 1;
6844           else if (cone[2] == f) r = 2;
6845           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6846           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6847 
6848           newSize += 2;
6849         }
6850       }
6851       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6852 #if 1
6853       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6854       for (p = 0; p < newSize; ++p) {
6855         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);
6856       }
6857 #endif
6858     }
6859     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6860     break;
6861   default:
6862     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6863   }
6864   PetscFunctionReturn(0);
6865 }
6866 
6867 #undef __FUNCT__
6868 #define __FUNCT__ "CellRefinerSetCoordinates"
6869 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6870 {
6871   PetscSection   coordSection, coordSectionNew;
6872   Vec            coordinates, coordinatesNew;
6873   PetscScalar   *coords, *coordsNew;
6874   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6875   PetscErrorCode ierr;
6876 
6877   PetscFunctionBegin;
6878   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6879   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6880   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6881   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6882   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6883   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6884   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6885   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6886   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6887   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6888   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6889   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6890   if (fMax < 0) fMax = fEnd;
6891   switch (refiner) {
6892   case 1:
6893   case 2:
6894   case 3:
6895     /* Simplicial and Hex 2D */
6896     /* All vertices have the dim coordinates */
6897     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6898       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6899       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6900     }
6901     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6902     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6903     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6904     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6905     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6906     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6907     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6908     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6909     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6910     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6911     /* Old vertices have the same coordinates */
6912     for (v = vStart; v < vEnd; ++v) {
6913       const PetscInt newv = vStartNew + (v - vStart);
6914       PetscInt       off, offnew, d;
6915 
6916       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6917       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6918       for (d = 0; d < dim; ++d) {
6919         coordsNew[offnew+d] = coords[off+d];
6920       }
6921     }
6922     /* Face vertices have the average of endpoint coordinates */
6923     for (f = fStart; f < fMax; ++f) {
6924       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6925       const PetscInt *cone;
6926       PetscInt        coneSize, offA, offB, offnew, d;
6927 
6928       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6929       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6930       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6931       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6932       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6933       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6934       for (d = 0; d < dim; ++d) {
6935         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6936       }
6937     }
6938     /* Just Hex 2D */
6939     if (refiner == 2) {
6940       /* Cell vertices have the average of corner coordinates */
6941       for (c = cStart; c < cEnd; ++c) {
6942         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6943         PetscInt      *cone = PETSC_NULL;
6944         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6945 
6946         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6947         for (p = 0; p < closureSize*2; p += 2) {
6948           const PetscInt point = cone[p];
6949           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6950         }
6951         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6952         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6953         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6954         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6955         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6956         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6957         for (d = 0; d < dim; ++d) {
6958           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6959         }
6960         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6961       }
6962     }
6963     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6964     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6965     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6966     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6967     break;
6968   default:
6969     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6970   }
6971   PetscFunctionReturn(0);
6972 }
6973 
6974 #undef __FUNCT__
6975 #define __FUNCT__ "DMPlexCreateProcessSF"
6976 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6977 {
6978   PetscInt           numRoots, numLeaves, l;
6979   const PetscInt    *localPoints;
6980   const PetscSFNode *remotePoints;
6981   PetscInt          *localPointsNew;
6982   PetscSFNode       *remotePointsNew;
6983   PetscInt          *ranks, *ranksNew;
6984   PetscErrorCode     ierr;
6985 
6986   PetscFunctionBegin;
6987   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6988   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6989   for (l = 0; l < numLeaves; ++l) {
6990     ranks[l] = remotePoints[l].rank;
6991   }
6992   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6993   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6994   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6995   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6996   for (l = 0; l < numLeaves; ++l) {
6997     ranksNew[l]              = ranks[l];
6998     localPointsNew[l]        = l;
6999     remotePointsNew[l].index = 0;
7000     remotePointsNew[l].rank  = ranksNew[l];
7001   }
7002   ierr = PetscFree(ranks);CHKERRQ(ierr);
7003   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
7004   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
7005   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7006   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7007   PetscFunctionReturn(0);
7008 }
7009 
7010 #undef __FUNCT__
7011 #define __FUNCT__ "CellRefinerCreateSF"
7012 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7013 {
7014   PetscSF            sf, sfNew, sfProcess;
7015   IS                 processRanks;
7016   MPI_Datatype       depthType;
7017   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7018   const PetscInt    *localPoints, *neighbors;
7019   const PetscSFNode *remotePoints;
7020   PetscInt          *localPointsNew;
7021   PetscSFNode       *remotePointsNew;
7022   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7023   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7024   PetscErrorCode     ierr;
7025 
7026   PetscFunctionBegin;
7027   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7028   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7029   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7030   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7031   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7032   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7033   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7034   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7035   switch (refiner) {
7036   case 3:
7037     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7038     cMax = PetscMin(cEnd, cMax);
7039     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7040     fMax = PetscMin(fEnd, fMax);
7041   }
7042   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7043   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7044   /* Caculate size of new SF */
7045   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7046   if (numRoots < 0) PetscFunctionReturn(0);
7047   for (l = 0; l < numLeaves; ++l) {
7048     const PetscInt p = localPoints[l];
7049 
7050     switch (refiner) {
7051     case 1:
7052       /* Simplicial 2D */
7053       if ((p >= vStart) && (p < vEnd)) {
7054         /* Old vertices stay the same */
7055         ++numLeavesNew;
7056       } else if ((p >= fStart) && (p < fEnd)) {
7057         /* Old faces add new faces and vertex */
7058         numLeavesNew += 1 + 2;
7059       } else if ((p >= cStart) && (p < cEnd)) {
7060         /* Old cells add new cells and interior faces */
7061         numLeavesNew += 4 + 3;
7062       }
7063       break;
7064     case 2:
7065       /* Hex 2D */
7066       if ((p >= vStart) && (p < vEnd)) {
7067         /* Old vertices stay the same */
7068         ++numLeavesNew;
7069       } else if ((p >= fStart) && (p < fEnd)) {
7070         /* Old faces add new faces and vertex */
7071         numLeavesNew += 1 + 2;
7072       } else if ((p >= cStart) && (p < cEnd)) {
7073         /* Old cells add new cells and interior faces */
7074         numLeavesNew += 4 + 4;
7075       }
7076       break;
7077     default:
7078       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7079     }
7080   }
7081   /* Communicate depthSizes for each remote rank */
7082   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7083   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7084   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7085   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);
7086   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7087   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7088   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7089   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7090   for (n = 0; n < numNeighbors; ++n) {
7091     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7092   }
7093   depthSizeOld[depth]   = cMax;
7094   depthSizeOld[0]       = vMax;
7095   depthSizeOld[depth-1] = fMax;
7096   depthSizeOld[1]       = eMax;
7097 
7098   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7099   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7100 
7101   depthSizeOld[depth]   = cEnd - cStart;
7102   depthSizeOld[0]       = vEnd - vStart;
7103   depthSizeOld[depth-1] = fEnd - fStart;
7104   depthSizeOld[1]       = eEnd - eStart;
7105 
7106   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7107   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7108   for (n = 0; n < numNeighbors; ++n) {
7109     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7110   }
7111   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7112   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7113   /* Calculate new point SF */
7114   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7115   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7116   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7117   for (l = 0, m = 0; l < numLeaves; ++l) {
7118     PetscInt    p     = localPoints[l];
7119     PetscInt    rp    = remotePoints[l].index, n;
7120     PetscMPIInt rrank = remotePoints[l].rank;
7121 
7122     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7123     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7124     switch (refiner) {
7125     case 1:
7126       /* Simplicial 2D */
7127       if ((p >= vStart) && (p < vEnd)) {
7128         /* Old vertices stay the same */
7129         localPointsNew[m]        = vStartNew     + (p  - vStart);
7130         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7131         remotePointsNew[m].rank  = rrank;
7132         ++m;
7133       } else if ((p >= fStart) && (p < fEnd)) {
7134         /* Old faces add new faces and vertex */
7135         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7136         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7137         remotePointsNew[m].rank  = rrank;
7138         ++m;
7139         for (r = 0; r < 2; ++r, ++m) {
7140           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7141           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7142           remotePointsNew[m].rank  = rrank;
7143         }
7144       } else if ((p >= cStart) && (p < cEnd)) {
7145         /* Old cells add new cells and interior faces */
7146         for (r = 0; r < 4; ++r, ++m) {
7147           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7148           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7149           remotePointsNew[m].rank  = rrank;
7150         }
7151         for (r = 0; r < 3; ++r, ++m) {
7152           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7153           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7154           remotePointsNew[m].rank  = rrank;
7155         }
7156       }
7157       break;
7158     case 2:
7159       /* Hex 2D */
7160       if ((p >= vStart) && (p < vEnd)) {
7161         /* Old vertices stay the same */
7162         localPointsNew[m]        = vStartNew     + (p  - vStart);
7163         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7164         remotePointsNew[m].rank  = rrank;
7165         ++m;
7166       } else if ((p >= fStart) && (p < fEnd)) {
7167         /* Old faces add new faces and vertex */
7168         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7169         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7170         remotePointsNew[m].rank  = rrank;
7171         ++m;
7172         for (r = 0; r < 2; ++r, ++m) {
7173           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7174           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7175           remotePointsNew[m].rank  = rrank;
7176         }
7177       } else if ((p >= cStart) && (p < cEnd)) {
7178         /* Old cells add new cells and interior faces */
7179         for (r = 0; r < 4; ++r, ++m) {
7180           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7181           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7182           remotePointsNew[m].rank  = rrank;
7183         }
7184         for (r = 0; r < 4; ++r, ++m) {
7185           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7186           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7187           remotePointsNew[m].rank  = rrank;
7188         }
7189       }
7190       break;
7191     case 3:
7192       /* Hybrid simplicial 2D */
7193       if ((p >= vStart) && (p < vEnd)) {
7194         /* Old vertices stay the same */
7195         localPointsNew[m]        = vStartNew     + (p  - vStart);
7196         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7197         remotePointsNew[m].rank  = rrank;
7198         ++m;
7199       } else if ((p >= fStart) && (p < fMax)) {
7200         /* Old interior faces add new faces and vertex */
7201         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7202         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7203         remotePointsNew[m].rank  = rrank;
7204         ++m;
7205         for (r = 0; r < 2; ++r, ++m) {
7206           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7207           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7208           remotePointsNew[m].rank  = rrank;
7209         }
7210       } else if ((p >= fMax) && (p < fEnd)) {
7211         /* Old hybrid faces stay the same */
7212         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7213         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7214         remotePointsNew[m].rank  = rrank;
7215         ++m;
7216       } else if ((p >= cStart) && (p < cMax)) {
7217         /* Old interior cells add new cells and interior faces */
7218         for (r = 0; r < 4; ++r, ++m) {
7219           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7220           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7221           remotePointsNew[m].rank  = rrank;
7222         }
7223         for (r = 0; r < 3; ++r, ++m) {
7224           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7225           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7226           remotePointsNew[m].rank  = rrank;
7227         }
7228       } else if ((p >= cStart) && (p < cMax)) {
7229         /* Old hybrid cells add new cells and hybrid face */
7230         for (r = 0; r < 2; ++r, ++m) {
7231           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7232           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7233           remotePointsNew[m].rank  = rrank;
7234         }
7235         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7236         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]);
7237         remotePointsNew[m].rank  = rrank;
7238         ++m;
7239       }
7240       break;
7241     default:
7242       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7243     }
7244   }
7245   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7246   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7247   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7248   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7249   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7250   PetscFunctionReturn(0);
7251 }
7252 
7253 #undef __FUNCT__
7254 #define __FUNCT__ "CellRefinerCreateLabels"
7255 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7256 {
7257   PetscInt       numLabels, l;
7258   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7259   PetscErrorCode ierr;
7260 
7261   PetscFunctionBegin;
7262   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7263   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7264   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7265   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7266 
7267   cStartNew = 0;
7268   vStartNew = depthSize[2];
7269   fStartNew = depthSize[2] + depthSize[0];
7270 
7271   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7272   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7273   switch (refiner) {
7274   case 3:
7275     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7276     cMax = PetscMin(cEnd, cMax);
7277     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7278     fMax = PetscMin(fEnd, fMax);
7279   }
7280   for (l = 0; l < numLabels; ++l) {
7281     DMLabel         label, labelNew;
7282     const char     *lname;
7283     PetscBool       isDepth;
7284     IS              valueIS;
7285     const PetscInt *values;
7286     PetscInt        numValues, val;
7287 
7288     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7289     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7290     if (isDepth) continue;
7291     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7292     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7293     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7294     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7295     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7296     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7297     for (val = 0; val < numValues; ++val) {
7298       IS              pointIS;
7299       const PetscInt *points;
7300       PetscInt        numPoints, n;
7301 
7302       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7303       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7304       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7305       for (n = 0; n < numPoints; ++n) {
7306         const PetscInt p = points[n];
7307         switch (refiner) {
7308         case 1:
7309           /* Simplicial 2D */
7310           if ((p >= vStart) && (p < vEnd)) {
7311             /* Old vertices stay the same */
7312             newp = vStartNew + (p - vStart);
7313             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7314           } else if ((p >= fStart) && (p < fEnd)) {
7315             /* Old faces add new faces and vertex */
7316             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7317             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7318             for (r = 0; r < 2; ++r) {
7319               newp = fStartNew + (p - fStart)*2 + r;
7320               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7321             }
7322           } else if ((p >= cStart) && (p < cEnd)) {
7323             /* Old cells add new cells and interior faces */
7324             for (r = 0; r < 4; ++r) {
7325               newp = cStartNew + (p - cStart)*4 + r;
7326               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7327             }
7328             for (r = 0; r < 3; ++r) {
7329               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7330               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7331             }
7332           }
7333           break;
7334         case 2:
7335           /* Hex 2D */
7336           if ((p >= vStart) && (p < vEnd)) {
7337             /* Old vertices stay the same */
7338             newp = vStartNew + (p - vStart);
7339             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7340           } else if ((p >= fStart) && (p < fEnd)) {
7341             /* Old faces add new faces and vertex */
7342             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7343             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7344             for (r = 0; r < 2; ++r) {
7345               newp = fStartNew + (p - fStart)*2 + r;
7346               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7347             }
7348           } else if ((p >= cStart) && (p < cEnd)) {
7349             /* Old cells add new cells and interior faces and vertex */
7350             for (r = 0; r < 4; ++r) {
7351               newp = cStartNew + (p - cStart)*4 + r;
7352               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7353             }
7354             for (r = 0; r < 4; ++r) {
7355               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7356               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7357             }
7358             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7359             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7360           }
7361           break;
7362         case 3:
7363           /* Hybrid simplicial 2D */
7364           if ((p >= vStart) && (p < vEnd)) {
7365             /* Old vertices stay the same */
7366             newp = vStartNew + (p - vStart);
7367             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7368           } else if ((p >= fStart) && (p < fMax)) {
7369             /* Old interior faces add new faces and vertex */
7370             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7371             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7372             for (r = 0; r < 2; ++r) {
7373               newp = fStartNew + (p - fStart)*2 + r;
7374               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7375             }
7376           } else if ((p >= fMax) && (p < fEnd)) {
7377             /* Old hybrid faces stay the same */
7378             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7379             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7380           } else if ((p >= cStart) && (p < cMax)) {
7381             /* Old interior cells add new cells and interior faces */
7382             for (r = 0; r < 4; ++r) {
7383               newp = cStartNew + (p - cStart)*4 + r;
7384               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7385             }
7386             for (r = 0; r < 3; ++r) {
7387               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7388               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7389             }
7390           } else if ((p >= cMax) && (p < cEnd)) {
7391             /* Old hybrid cells add new cells and hybrid face */
7392             for (r = 0; r < 2; ++r) {
7393               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7394               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7395             }
7396             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7397             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7398           }
7399           break;
7400         default:
7401           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7402         }
7403       }
7404       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7405       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7406     }
7407     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7408     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7409     if (0) {
7410       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7411       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7412       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7413     }
7414   }
7415   PetscFunctionReturn(0);
7416 }
7417 
7418 #undef __FUNCT__
7419 #define __FUNCT__ "DMPlexRefine_Uniform"
7420 /* This will only work for interpolated meshes */
7421 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7422 {
7423   DM             rdm;
7424   PetscInt      *depthSize;
7425   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7426   PetscErrorCode ierr;
7427 
7428   PetscFunctionBegin;
7429   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7430   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7431   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7432   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7433   /* Calculate number of new points of each depth */
7434   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7435   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7436   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7437   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7438   /* Step 1: Set chart */
7439   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7440   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7441   /* Step 2: Set cone/support sizes */
7442   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7443   /* Step 3: Setup refined DM */
7444   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7445   /* Step 4: Set cones and supports */
7446   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7447   /* Step 5: Stratify */
7448   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7449   /* Step 6: Set coordinates for vertices */
7450   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7451   /* Step 7: Create pointSF */
7452   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7453   /* Step 8: Create labels */
7454   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7455   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7456 
7457   *dmRefined = rdm;
7458   PetscFunctionReturn(0);
7459 }
7460 
7461 #undef __FUNCT__
7462 #define __FUNCT__ "DMPlexSetRefinementUniform"
7463 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7464 {
7465   DM_Plex *mesh = (DM_Plex*) dm->data;
7466 
7467   PetscFunctionBegin;
7468   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7469   mesh->refinementUniform = refinementUniform;
7470   PetscFunctionReturn(0);
7471 }
7472 
7473 #undef __FUNCT__
7474 #define __FUNCT__ "DMPlexGetRefinementUniform"
7475 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7476 {
7477   DM_Plex *mesh = (DM_Plex*) dm->data;
7478 
7479   PetscFunctionBegin;
7480   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7481   PetscValidPointer(refinementUniform,  2);
7482   *refinementUniform = mesh->refinementUniform;
7483   PetscFunctionReturn(0);
7484 }
7485 
7486 #undef __FUNCT__
7487 #define __FUNCT__ "DMPlexSetRefinementLimit"
7488 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7489 {
7490   DM_Plex *mesh = (DM_Plex*) dm->data;
7491 
7492   PetscFunctionBegin;
7493   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7494   mesh->refinementLimit = refinementLimit;
7495   PetscFunctionReturn(0);
7496 }
7497 
7498 #undef __FUNCT__
7499 #define __FUNCT__ "DMPlexGetRefinementLimit"
7500 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7501 {
7502   DM_Plex *mesh = (DM_Plex*) dm->data;
7503 
7504   PetscFunctionBegin;
7505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7506   PetscValidPointer(refinementLimit,  2);
7507   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7508   *refinementLimit = mesh->refinementLimit;
7509   PetscFunctionReturn(0);
7510 }
7511 
7512 #undef __FUNCT__
7513 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7514 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7515 {
7516   PetscInt       dim, cStart, coneSize, cMax;
7517   PetscErrorCode ierr;
7518 
7519   PetscFunctionBegin;
7520   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7521   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7522   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7523   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7524   switch (dim) {
7525   case 2:
7526     switch (coneSize) {
7527     case 3:
7528       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7529       else *cellRefiner = 1; /* Triangular */
7530       break;
7531     case 4:
7532       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7533       else *cellRefiner = 2; /* Quadrilateral */
7534       break;
7535     default:
7536       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7537     }
7538     break;
7539   default:
7540     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7541   }
7542   PetscFunctionReturn(0);
7543 }
7544 
7545 #undef __FUNCT__
7546 #define __FUNCT__ "DMRefine_Plex"
7547 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7548 {
7549   PetscReal      refinementLimit;
7550   PetscInt       dim, cStart, cEnd;
7551   char           genname[1024], *name = PETSC_NULL;
7552   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7553   PetscErrorCode ierr;
7554 
7555   PetscFunctionBegin;
7556   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7557   if (isUniform) {
7558     CellRefiner cellRefiner;
7559 
7560     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7561     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7562     PetscFunctionReturn(0);
7563   }
7564   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7565   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7566   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7567   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7568   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7569   if (flg) name = genname;
7570   if (name) {
7571     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7572     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7573     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7574   }
7575   switch (dim) {
7576   case 2:
7577     if (!name || isTriangle) {
7578 #if defined(PETSC_HAVE_TRIANGLE)
7579       double  *maxVolumes;
7580       PetscInt c;
7581 
7582       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7583       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7584       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7585 #else
7586       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7587 #endif
7588     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7589     break;
7590   case 3:
7591     if (!name || isCTetgen) {
7592 #if defined(PETSC_HAVE_CTETGEN)
7593       PetscReal *maxVolumes;
7594       PetscInt   c;
7595 
7596       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7597       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7598       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7599 #else
7600       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7601 #endif
7602     } else if (isTetgen) {
7603 #if defined(PETSC_HAVE_TETGEN)
7604       double  *maxVolumes;
7605       PetscInt c;
7606 
7607       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7608       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7609       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7610 #else
7611       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7612 #endif
7613     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7614     break;
7615   default:
7616     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7617   }
7618   PetscFunctionReturn(0);
7619 }
7620 
7621 #undef __FUNCT__
7622 #define __FUNCT__ "DMPlexGetDepth"
7623 /*@
7624   DMPlexGetDepth - get the number of strata
7625 
7626   Not Collective
7627 
7628   Input Parameters:
7629 . dm           - The DMPlex object
7630 
7631   Output Parameters:
7632 . depth - number of strata
7633 
7634   Level: developer
7635 
7636   Notes:
7637   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7638 
7639 .keywords: mesh, points
7640 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7641 @*/
7642 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7643 {
7644   PetscInt       d;
7645   PetscErrorCode ierr;
7646 
7647   PetscFunctionBegin;
7648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7649   PetscValidPointer(depth, 2);
7650   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7651   *depth = d-1;
7652   PetscFunctionReturn(0);
7653 }
7654 
7655 #undef __FUNCT__
7656 #define __FUNCT__ "DMPlexGetDepthStratum"
7657 /*@
7658   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7659 
7660   Not Collective
7661 
7662   Input Parameters:
7663 + dm           - The DMPlex object
7664 - stratumValue - The requested depth
7665 
7666   Output Parameters:
7667 + start - The first point at this depth
7668 - end   - One beyond the last point at this depth
7669 
7670   Level: developer
7671 
7672 .keywords: mesh, points
7673 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7674 @*/
7675 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7676 {
7677   DM_Plex       *mesh = (DM_Plex*) dm->data;
7678   DMLabel        next  = mesh->labels;
7679   PetscBool      flg   = PETSC_FALSE;
7680   PetscInt       depth;
7681   PetscErrorCode ierr;
7682 
7683   PetscFunctionBegin;
7684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7685   if (stratumValue < 0) {
7686     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7687     PetscFunctionReturn(0);
7688   } else {
7689     PetscInt pStart, pEnd;
7690 
7691     if (start) *start = 0;
7692     if (end)   *end   = 0;
7693     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7694     if (pStart == pEnd) PetscFunctionReturn(0);
7695   }
7696   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7697   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7698   /* We should have a generic GetLabel() and a Label class */
7699   while (next) {
7700     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7701     if (flg) break;
7702     next = next->next;
7703   }
7704   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7705   depth = stratumValue;
7706   if ((depth < 0) || (depth >= next->numStrata)) {
7707     if (start) *start = 0;
7708     if (end)   *end   = 0;
7709   } else {
7710     if (start) *start = next->points[next->stratumOffsets[depth]];
7711     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7712   }
7713   PetscFunctionReturn(0);
7714 }
7715 
7716 #undef __FUNCT__
7717 #define __FUNCT__ "DMPlexGetHeightStratum"
7718 /*@
7719   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7720 
7721   Not Collective
7722 
7723   Input Parameters:
7724 + dm           - The DMPlex object
7725 - stratumValue - The requested height
7726 
7727   Output Parameters:
7728 + start - The first point at this height
7729 - end   - One beyond the last point at this height
7730 
7731   Level: developer
7732 
7733 .keywords: mesh, points
7734 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7735 @*/
7736 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7737 {
7738   DM_Plex       *mesh = (DM_Plex*) dm->data;
7739   DMLabel        next  = mesh->labels;
7740   PetscBool      flg   = PETSC_FALSE;
7741   PetscInt       depth;
7742   PetscErrorCode ierr;
7743 
7744   PetscFunctionBegin;
7745   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7746   if (stratumValue < 0) {
7747     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7748   } else {
7749     PetscInt pStart, pEnd;
7750 
7751     if (start) *start = 0;
7752     if (end)   *end   = 0;
7753     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7754     if (pStart == pEnd) PetscFunctionReturn(0);
7755   }
7756   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7757   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7758   /* We should have a generic GetLabel() and a Label class */
7759   while (next) {
7760     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7761     if (flg) break;
7762     next = next->next;
7763   }
7764   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7765   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7766   if ((depth < 0) || (depth >= next->numStrata)) {
7767     if (start) *start = 0;
7768     if (end)   *end   = 0;
7769   } else {
7770     if (start) *start = next->points[next->stratumOffsets[depth]];
7771     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7772   }
7773   PetscFunctionReturn(0);
7774 }
7775 
7776 #undef __FUNCT__
7777 #define __FUNCT__ "DMPlexCreateSectionInitial"
7778 /* Set the number of dof on each point and separate by fields */
7779 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7780 {
7781   PetscInt      *numDofTot;
7782   PetscInt       pStart = 0, pEnd = 0;
7783   PetscInt       p, d, f;
7784   PetscErrorCode ierr;
7785 
7786   PetscFunctionBegin;
7787   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7788   for (d = 0; d <= dim; ++d) {
7789     numDofTot[d] = 0;
7790     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7791   }
7792   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7793   if (numFields > 0) {
7794     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7795     if (numComp) {
7796       for (f = 0; f < numFields; ++f) {
7797         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7798       }
7799     }
7800   }
7801   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7802   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7803   for (d = 0; d <= dim; ++d) {
7804     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7805     for (p = pStart; p < pEnd; ++p) {
7806       for (f = 0; f < numFields; ++f) {
7807         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7808       }
7809       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7810     }
7811   }
7812   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7813   PetscFunctionReturn(0);
7814 }
7815 
7816 #undef __FUNCT__
7817 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7818 /* Set the number of dof on each point and separate by fields
7819    If constDof is PETSC_DETERMINE, constrain every dof on the point
7820 */
7821 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7822 {
7823   PetscInt       numFields;
7824   PetscInt       bc;
7825   PetscErrorCode ierr;
7826 
7827   PetscFunctionBegin;
7828   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7829   for (bc = 0; bc < numBC; ++bc) {
7830     PetscInt        field = 0;
7831     const PetscInt *idx;
7832     PetscInt        n, i;
7833 
7834     if (numFields) field = bcField[bc];
7835     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7836     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7837     for (i = 0; i < n; ++i) {
7838       const PetscInt p        = idx[i];
7839       PetscInt       numConst = constDof;
7840 
7841       /* Constrain every dof on the point */
7842       if (numConst < 0) {
7843         if (numFields) {
7844           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7845         } else {
7846           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7847         }
7848       }
7849       if (numFields) {
7850         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7851       }
7852       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7853     }
7854     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7855   }
7856   PetscFunctionReturn(0);
7857 }
7858 
7859 #undef __FUNCT__
7860 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7861 /* Set the constrained indices on each point and separate by fields */
7862 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7863 {
7864   PetscInt      *maxConstraints;
7865   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7866   PetscErrorCode ierr;
7867 
7868   PetscFunctionBegin;
7869   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7870   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7871   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7872   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7873   for (p = pStart; p < pEnd; ++p) {
7874     PetscInt cdof;
7875 
7876     if (numFields) {
7877       for (f = 0; f < numFields; ++f) {
7878         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7879         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7880       }
7881     } else {
7882       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7883       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7884     }
7885   }
7886   for (f = 0; f < numFields; ++f) {
7887     maxConstraints[numFields] += maxConstraints[f];
7888   }
7889   if (maxConstraints[numFields]) {
7890     PetscInt *indices;
7891 
7892     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7893     for (p = pStart; p < pEnd; ++p) {
7894       PetscInt cdof, d;
7895 
7896       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7897       if (cdof) {
7898         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7899         if (numFields) {
7900           PetscInt numConst = 0, foff = 0;
7901 
7902           for (f = 0; f < numFields; ++f) {
7903             PetscInt cfdof, fdof;
7904 
7905             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7906             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7907             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7908             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7909             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7910             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7911             numConst += cfdof;
7912             foff     += fdof;
7913           }
7914           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7915         } else {
7916           for (d = 0; d < cdof; ++d) indices[d] = d;
7917         }
7918         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7919       }
7920     }
7921     ierr = PetscFree(indices);CHKERRQ(ierr);
7922   }
7923   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7924   PetscFunctionReturn(0);
7925 }
7926 
7927 #undef __FUNCT__
7928 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7929 /* Set the constrained field indices on each point */
7930 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7931 {
7932   const PetscInt *points, *indices;
7933   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7934   PetscErrorCode  ierr;
7935 
7936   PetscFunctionBegin;
7937   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7938   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7939 
7940   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7941   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7942   if (!constraintIndices) {
7943     PetscInt *idx, i;
7944 
7945     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7946     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7947     for (i = 0; i < maxDof; ++i) idx[i] = i;
7948     for (p = 0; p < numPoints; ++p) {
7949       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7950     }
7951     ierr = PetscFree(idx);CHKERRQ(ierr);
7952   } else {
7953     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7954     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7955     for (p = 0; p < numPoints; ++p) {
7956       PetscInt fcdof;
7957 
7958       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7959       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);
7960       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7961     }
7962     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7963   }
7964   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7965   PetscFunctionReturn(0);
7966 }
7967 
7968 #undef __FUNCT__
7969 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7970 /* Set the constrained indices on each point and separate by fields */
7971 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7972 {
7973   PetscInt      *indices;
7974   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7975   PetscErrorCode ierr;
7976 
7977   PetscFunctionBegin;
7978   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7979   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7980   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7981   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7982   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7983   for (p = pStart; p < pEnd; ++p) {
7984     PetscInt cdof, d;
7985 
7986     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7987     if (cdof) {
7988       PetscInt numConst = 0, foff = 0;
7989 
7990       for (f = 0; f < numFields; ++f) {
7991         const PetscInt *fcind;
7992         PetscInt        fdof, fcdof;
7993 
7994         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7995         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7996         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7997         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7998         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
7999         foff     += fdof;
8000         numConst += fcdof;
8001       }
8002       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8003       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8004     }
8005   }
8006   ierr = PetscFree(indices);CHKERRQ(ierr);
8007   PetscFunctionReturn(0);
8008 }
8009 
8010 #undef __FUNCT__
8011 #define __FUNCT__ "DMPlexCreateSection"
8012 /*@C
8013   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8014 
8015   Not Collective
8016 
8017   Input Parameters:
8018 + dm        - The DMPlex object
8019 . dim       - The spatial dimension of the problem
8020 . numFields - The number of fields in the problem
8021 . numComp   - An array of size numFields that holds the number of components for each field
8022 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8023 . numBC     - The number of boundary conditions
8024 . bcField   - An array of size numBC giving the field number for each boundry condition
8025 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8026 
8027   Output Parameter:
8028 . section - The PetscSection object
8029 
8030   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
8031   nubmer of dof for field 0 on each edge.
8032 
8033   Level: developer
8034 
8035 .keywords: mesh, elements
8036 .seealso: DMPlexCreate(), PetscSectionCreate()
8037 @*/
8038 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8039 {
8040   PetscErrorCode ierr;
8041 
8042   PetscFunctionBegin;
8043   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8044   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8045   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8046   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8047   {
8048     PetscBool view = PETSC_FALSE;
8049 
8050     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8051     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8052   }
8053   PetscFunctionReturn(0);
8054 }
8055 
8056 #undef __FUNCT__
8057 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8058 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8059 {
8060   PetscSection   section;
8061   PetscErrorCode ierr;
8062 
8063   PetscFunctionBegin;
8064   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8065   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8066   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8067   PetscFunctionReturn(0);
8068 }
8069 
8070 #undef __FUNCT__
8071 #define __FUNCT__ "DMPlexGetCoordinateSection"
8072 /*@
8073   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8074 
8075   Not Collective
8076 
8077   Input Parameter:
8078 . dm - The DMPlex object
8079 
8080   Output Parameter:
8081 . section - The PetscSection object
8082 
8083   Level: intermediate
8084 
8085 .keywords: mesh, coordinates
8086 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8087 @*/
8088 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8089 {
8090   DM             cdm;
8091   PetscErrorCode ierr;
8092 
8093   PetscFunctionBegin;
8094   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8095   PetscValidPointer(section, 2);
8096   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8097   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8098   PetscFunctionReturn(0);
8099 }
8100 
8101 #undef __FUNCT__
8102 #define __FUNCT__ "DMPlexSetCoordinateSection"
8103 /*@
8104   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8105 
8106   Not Collective
8107 
8108   Input Parameters:
8109 + dm      - The DMPlex object
8110 - section - The PetscSection object
8111 
8112   Level: intermediate
8113 
8114 .keywords: mesh, coordinates
8115 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8116 @*/
8117 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8118 {
8119   DM             cdm;
8120   PetscErrorCode ierr;
8121 
8122   PetscFunctionBegin;
8123   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8124   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8125   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8126   PetscFunctionReturn(0);
8127 }
8128 
8129 #undef __FUNCT__
8130 #define __FUNCT__ "DMPlexGetConeSection"
8131 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8132 {
8133   DM_Plex *mesh = (DM_Plex*) dm->data;
8134 
8135   PetscFunctionBegin;
8136   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8137   if (section) *section = mesh->coneSection;
8138   PetscFunctionReturn(0);
8139 }
8140 
8141 #undef __FUNCT__
8142 #define __FUNCT__ "DMPlexGetCones"
8143 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8144 {
8145   DM_Plex *mesh = (DM_Plex*) dm->data;
8146 
8147   PetscFunctionBegin;
8148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8149   if (cones) *cones = mesh->cones;
8150   PetscFunctionReturn(0);
8151 }
8152 
8153 #undef __FUNCT__
8154 #define __FUNCT__ "DMPlexGetConeOrientations"
8155 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8156 {
8157   DM_Plex *mesh = (DM_Plex*) dm->data;
8158 
8159   PetscFunctionBegin;
8160   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8161   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8162   PetscFunctionReturn(0);
8163 }
8164 
8165 #undef __FUNCT__
8166 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8167 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8168 {
8169   const PetscInt embedDim = 2;
8170   PetscReal      x        = PetscRealPart(point[0]);
8171   PetscReal      y        = PetscRealPart(point[1]);
8172   PetscReal      v0[2], J[4], invJ[4], detJ;
8173   PetscReal      xi, eta;
8174   PetscErrorCode ierr;
8175 
8176   PetscFunctionBegin;
8177   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8178   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8179   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8180 
8181   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8182   else *cell = -1;
8183   PetscFunctionReturn(0);
8184 }
8185 
8186 #undef __FUNCT__
8187 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8188 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8189 {
8190   PetscSection       coordSection;
8191   Vec                coordsLocal;
8192   const PetscScalar *coords;
8193   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8194   PetscReal          x         = PetscRealPart(point[0]);
8195   PetscReal          y         = PetscRealPart(point[1]);
8196   PetscInt           crossings = 0, f;
8197   PetscErrorCode     ierr;
8198 
8199   PetscFunctionBegin;
8200   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8201   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8202   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8203   for (f = 0; f < 4; ++f) {
8204     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8205     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8206     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8207     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8208     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8209     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8210     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8211     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8212     if ((cond1 || cond2)  && above) ++crossings;
8213   }
8214   if (crossings % 2) *cell = c;
8215   else *cell = -1;
8216   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8217   PetscFunctionReturn(0);
8218 }
8219 
8220 #undef __FUNCT__
8221 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8222 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8223 {
8224   const PetscInt embedDim = 3;
8225   PetscReal      v0[3], J[9], invJ[9], detJ;
8226   PetscReal      x = PetscRealPart(point[0]);
8227   PetscReal      y = PetscRealPart(point[1]);
8228   PetscReal      z = PetscRealPart(point[2]);
8229   PetscReal      xi, eta, zeta;
8230   PetscErrorCode ierr;
8231 
8232   PetscFunctionBegin;
8233   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8234   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8235   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8236   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8237 
8238   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8239   else *cell = -1;
8240   PetscFunctionReturn(0);
8241 }
8242 
8243 #undef __FUNCT__
8244 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8245 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8246 {
8247   PetscSection       coordSection;
8248   Vec                coordsLocal;
8249   const PetscScalar *coords;
8250   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8251                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8252   PetscBool          found = PETSC_TRUE;
8253   PetscInt           f;
8254   PetscErrorCode     ierr;
8255 
8256   PetscFunctionBegin;
8257   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8258   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8259   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8260   for (f = 0; f < 6; ++f) {
8261     /* Check the point is under plane */
8262     /*   Get face normal */
8263     PetscReal v_i[3];
8264     PetscReal v_j[3];
8265     PetscReal normal[3];
8266     PetscReal pp[3];
8267     PetscReal dot;
8268 
8269     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8270     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8271     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8272     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8273     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8274     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8275     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8276     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8277     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8278     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8279     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8280     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8281     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8282 
8283     /* Check that projected point is in face (2D location problem) */
8284     if (dot < 0.0) {
8285       found = PETSC_FALSE;
8286       break;
8287     }
8288   }
8289   if (found) *cell = c;
8290   else *cell = -1;
8291   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8292   PetscFunctionReturn(0);
8293 }
8294 
8295 #undef __FUNCT__
8296 #define __FUNCT__ "DMLocatePoints_Plex"
8297 /*
8298  Need to implement using the guess
8299 */
8300 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8301 {
8302   PetscInt       cell = -1 /*, guess = -1*/;
8303   PetscInt       bs, numPoints, p;
8304   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8305   PetscInt      *cells;
8306   PetscScalar   *a;
8307   PetscErrorCode ierr;
8308 
8309   PetscFunctionBegin;
8310   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8311   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8312   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8313   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8314   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8315   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8316   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8317   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);
8318   numPoints /= bs;
8319   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8320   for (p = 0; p < numPoints; ++p) {
8321     const PetscScalar *point = &a[p*bs];
8322 
8323     switch (dim) {
8324     case 2:
8325       for (c = cStart; c < cEnd; ++c) {
8326         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8327         switch (coneSize) {
8328         case 3:
8329           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8330           break;
8331         case 4:
8332           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8333           break;
8334         default:
8335           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8336         }
8337         if (cell >= 0) break;
8338       }
8339       break;
8340     case 3:
8341       for (c = cStart; c < cEnd; ++c) {
8342         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8343         switch (coneSize) {
8344         case 4:
8345           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8346           break;
8347         case 8:
8348           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8349           break;
8350         default:
8351           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8352         }
8353         if (cell >= 0) break;
8354       }
8355       break;
8356     default:
8357       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8358     }
8359     cells[p] = cell;
8360   }
8361   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8362   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8363   PetscFunctionReturn(0);
8364 }
8365 
8366 /******************************** FEM Support **********************************/
8367 
8368 #undef __FUNCT__
8369 #define __FUNCT__ "DMPlexVecGetClosure"
8370 /*@C
8371   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8372 
8373   Not collective
8374 
8375   Input Parameters:
8376 + dm - The DM
8377 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8378 . v - The local vector
8379 - point - The sieve point in the DM
8380 
8381   Output Parameters:
8382 + csize - The number of values in the closure, or PETSC_NULL
8383 - values - The array of values, which is a borrowed array and should not be freed
8384 
8385   Level: intermediate
8386 
8387 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8388 @*/
8389 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8390 {
8391   PetscScalar   *array, *vArray;
8392   PetscInt      *points = PETSC_NULL;
8393   PetscInt       offsets[32];
8394   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8395   PetscErrorCode ierr;
8396 
8397   PetscFunctionBegin;
8398   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8399   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8400   if (!section) {
8401     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8402   }
8403   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8404   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8405   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8406   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8407   /* Compress out points not in the section */
8408   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8409   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8410     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8411       points[q*2]   = points[p];
8412       points[q*2+1] = points[p+1];
8413       ++q;
8414     }
8415   }
8416   numPoints = q;
8417   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8418     PetscInt dof, fdof;
8419 
8420     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8421     for (f = 0; f < numFields; ++f) {
8422       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8423       offsets[f+1] += fdof;
8424     }
8425     size += dof;
8426   }
8427   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8428   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8429   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8430   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8431   for (p = 0; p < numPoints*2; p += 2) {
8432     PetscInt     o = points[p+1];
8433     PetscInt     dof, off, d;
8434     PetscScalar *varr;
8435 
8436     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8437     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8438     varr = &vArray[off];
8439     if (numFields) {
8440       PetscInt fdof, foff, fcomp, f, c;
8441 
8442       for (f = 0, foff = 0; f < numFields; ++f) {
8443         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8444         if (o >= 0) {
8445           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8446             array[offsets[f]] = varr[foff+d];
8447           }
8448         } else {
8449           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8450           for (d = fdof/fcomp-1; d >= 0; --d) {
8451             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8452               array[offsets[f]] = varr[foff+d*fcomp+c];
8453             }
8454           }
8455         }
8456         foff += fdof;
8457       }
8458     } else {
8459       if (o >= 0) {
8460         for (d = 0; d < dof; ++d, ++offsets[0]) {
8461           array[offsets[0]] = varr[d];
8462         }
8463       } else {
8464         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8465           array[offsets[0]] = varr[d];
8466         }
8467       }
8468     }
8469   }
8470   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8471   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8472   if (csize) *csize = size;
8473   *values = array;
8474   PetscFunctionReturn(0);
8475 }
8476 
8477 #undef __FUNCT__
8478 #define __FUNCT__ "DMPlexVecRestoreClosure"
8479 /*@C
8480   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8481 
8482   Not collective
8483 
8484   Input Parameters:
8485 + dm - The DM
8486 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8487 . v - The local vector
8488 . point - The sieve point in the DM
8489 . csize - The number of values in the closure, or PETSC_NULL
8490 - values - The array of values, which is a borrowed array and should not be freed
8491 
8492   Level: intermediate
8493 
8494 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8495 @*/
8496 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8497 {
8498   PetscInt       size = 0;
8499   PetscErrorCode ierr;
8500 
8501   PetscFunctionBegin;
8502   /* Should work without recalculating size */
8503   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8504   PetscFunctionReturn(0);
8505 }
8506 
8507 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8508 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8509 
8510 #undef __FUNCT__
8511 #define __FUNCT__ "updatePoint_private"
8512 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8513 {
8514   PetscInt        cdof;   /* The number of constraints on this point */
8515   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8516   PetscScalar    *a;
8517   PetscInt        off, cind = 0, k;
8518   PetscErrorCode  ierr;
8519 
8520   PetscFunctionBegin;
8521   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8522   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8523   a    = &array[off];
8524   if (!cdof || setBC) {
8525     if (orientation >= 0) {
8526       for (k = 0; k < dof; ++k) {
8527         fuse(&a[k], values[k]);
8528       }
8529     } else {
8530       for (k = 0; k < dof; ++k) {
8531         fuse(&a[k], values[dof-k-1]);
8532       }
8533     }
8534   } else {
8535     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8536     if (orientation >= 0) {
8537       for (k = 0; k < dof; ++k) {
8538         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8539         fuse(&a[k], values[k]);
8540       }
8541     } else {
8542       for (k = 0; k < dof; ++k) {
8543         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8544         fuse(&a[k], values[dof-k-1]);
8545       }
8546     }
8547   }
8548   PetscFunctionReturn(0);
8549 }
8550 
8551 #undef __FUNCT__
8552 #define __FUNCT__ "updatePointFields_private"
8553 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8554 {
8555   PetscScalar   *a;
8556   PetscInt       numFields, off, foff, f;
8557   PetscErrorCode ierr;
8558 
8559   PetscFunctionBegin;
8560   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8561   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8562   a    = &array[off];
8563   for (f = 0, foff = 0; f < numFields; ++f) {
8564     PetscInt        fdof, fcomp, fcdof;
8565     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8566     PetscInt        cind = 0, k, c;
8567 
8568     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8569     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8570     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8571     if (!fcdof || setBC) {
8572       if (orientation >= 0) {
8573         for (k = 0; k < fdof; ++k) {
8574           fuse(&a[foff+k], values[foffs[f]+k]);
8575         }
8576       } else {
8577         for (k = fdof/fcomp-1; k >= 0; --k) {
8578           for (c = 0; c < fcomp; ++c) {
8579             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8580           }
8581         }
8582       }
8583     } else {
8584       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8585       if (orientation >= 0) {
8586         for (k = 0; k < fdof; ++k) {
8587           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8588           fuse(&a[foff+k], values[foffs[f]+k]);
8589         }
8590       } else {
8591         for (k = fdof/fcomp-1; k >= 0; --k) {
8592           for (c = 0; c < fcomp; ++c) {
8593             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8594             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8595           }
8596         }
8597       }
8598     }
8599     foff     += fdof;
8600     foffs[f] += fdof;
8601   }
8602   PetscFunctionReturn(0);
8603 }
8604 
8605 #undef __FUNCT__
8606 #define __FUNCT__ "DMPlexVecSetClosure"
8607 /*@C
8608   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8609 
8610   Not collective
8611 
8612   Input Parameters:
8613 + dm - The DM
8614 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8615 . v - The local vector
8616 . point - The sieve point in the DM
8617 . values - The array of values, which is a borrowed array and should not be freed
8618 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8619 
8620   Level: intermediate
8621 
8622 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8623 @*/
8624 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8625 {
8626   PetscScalar   *array;
8627   PetscInt      *points = PETSC_NULL;
8628   PetscInt       offsets[32];
8629   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8630   PetscErrorCode ierr;
8631 
8632   PetscFunctionBegin;
8633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8634   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8635   if (!section) {
8636     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8637   }
8638   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8639   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8640   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8641   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8642   /* Compress out points not in the section */
8643   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8644   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8645     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8646       points[q*2]   = points[p];
8647       points[q*2+1] = points[p+1];
8648       ++q;
8649     }
8650   }
8651   numPoints = q;
8652   for (p = 0; p < numPoints*2; p += 2) {
8653     PetscInt fdof;
8654 
8655     for (f = 0; f < numFields; ++f) {
8656       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8657       offsets[f+1] += fdof;
8658     }
8659   }
8660   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8661   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8662   if (numFields) {
8663     switch (mode) {
8664     case INSERT_VALUES:
8665       for (p = 0; p < numPoints*2; p += 2) {
8666         PetscInt o = points[p+1];
8667         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8668       } break;
8669     case INSERT_ALL_VALUES:
8670       for (p = 0; p < numPoints*2; p += 2) {
8671         PetscInt o = points[p+1];
8672         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8673       } break;
8674     case ADD_VALUES:
8675       for (p = 0; p < numPoints*2; p += 2) {
8676         PetscInt o = points[p+1];
8677         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8678       } break;
8679     case ADD_ALL_VALUES:
8680       for (p = 0; p < numPoints*2; p += 2) {
8681         PetscInt o = points[p+1];
8682         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8683       } break;
8684     default:
8685       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8686     }
8687   } else {
8688     switch (mode) {
8689     case INSERT_VALUES:
8690       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8691         PetscInt o = points[p+1];
8692         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8693         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8694       } break;
8695     case INSERT_ALL_VALUES:
8696       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8697         PetscInt o = points[p+1];
8698         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8699         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8700       } break;
8701     case ADD_VALUES:
8702       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8703         PetscInt o = points[p+1];
8704         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8705         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8706       } break;
8707     case ADD_ALL_VALUES:
8708       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8709         PetscInt o = points[p+1];
8710         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8711         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8712       } break;
8713     default:
8714       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8715     }
8716   }
8717   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8718   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8719   PetscFunctionReturn(0);
8720 }
8721 
8722 #undef __FUNCT__
8723 #define __FUNCT__ "DMPlexPrintMatSetValues"
8724 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8725 {
8726   PetscMPIInt    rank;
8727   PetscInt       i, j;
8728   PetscErrorCode ierr;
8729 
8730   PetscFunctionBegin;
8731   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8732   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8733   for (i = 0; i < numIndices; i++) {
8734     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8735   }
8736   for (i = 0; i < numIndices; i++) {
8737     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8738     for (j = 0; j < numIndices; j++) {
8739 #if defined(PETSC_USE_COMPLEX)
8740       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8741 #else
8742       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8743 #endif
8744     }
8745     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8746   }
8747   PetscFunctionReturn(0);
8748 }
8749 
8750 #undef __FUNCT__
8751 #define __FUNCT__ "indicesPoint_private"
8752 /* . off - The global offset of this point */
8753 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8754 {
8755   PetscInt        cdof;   /* The number of constraints on this point */
8756   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8757   PetscInt        cind = 0, k;
8758   PetscErrorCode  ierr;
8759 
8760   PetscFunctionBegin;
8761   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8762   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8763   if (!cdof || setBC) {
8764     if (orientation >= 0) {
8765       for (k = 0; k < dof; ++k) indices[k] = off+k;
8766     } else {
8767       for (k = 0; k < dof; ++k) indices[dof-k-1] = off+k;
8768     }
8769   } else {
8770     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8771     if (orientation >= 0) {
8772       for (k = 0; k < dof; ++k) {
8773         if ((cind < cdof) && (k == cdofs[cind])) {
8774           /* Insert check for returning constrained indices */
8775           indices[k] = -(off+k+1);
8776           ++cind;
8777         } else {
8778           indices[k] = off+k-cind;
8779         }
8780       }
8781     } else {
8782       for (k = 0; k < dof; ++k) {
8783         if ((cind < cdof) && (k == cdofs[cind])) {
8784           /* Insert check for returning constrained indices */
8785           indices[dof-k-1] = -(off+k+1);
8786           ++cind;
8787         } else {
8788           indices[dof-k-1] = off+k-cind;
8789         }
8790       }
8791     }
8792   }
8793   PetscFunctionReturn(0);
8794 }
8795 
8796 #undef __FUNCT__
8797 #define __FUNCT__ "indicesPointFields_private"
8798 /* . off - The global offset of this point */
8799 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8800 {
8801   PetscInt       numFields, foff, f;
8802   PetscErrorCode ierr;
8803 
8804   PetscFunctionBegin;
8805   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8806   for (f = 0, foff = 0; f < numFields; ++f) {
8807     PetscInt        fdof, fcomp, cfdof;
8808     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8809     PetscInt        cind = 0, k, c;
8810 
8811     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8812     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8813     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8814     if (!cfdof || setBC) {
8815       if (orientation >= 0) {
8816         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8817       } else {
8818         for (k = fdof/fcomp-1; k >= 0; --k) {
8819           for (c = 0; c < fcomp; ++c) {
8820             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8821           }
8822         }
8823       }
8824     } else {
8825       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8826       if (orientation >= 0) {
8827         for (k = 0; k < fdof; ++k) {
8828           if ((cind < cfdof) && (k == fcdofs[cind])) {
8829             indices[foffs[f]+k] = -(off+foff+k+1);
8830             ++cind;
8831           } else {
8832             indices[foffs[f]+k] = off+foff+k-cind;
8833           }
8834         }
8835       } else {
8836         for (k = fdof/fcomp-1; k >= 0; --k) {
8837           for (c = 0; c < fcomp; ++c) {
8838             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8839               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8840               ++cind;
8841             } else {
8842               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8843             }
8844           }
8845         }
8846       }
8847     }
8848     foff     += fdof - cfdof;
8849     foffs[f] += fdof;
8850   }
8851   PetscFunctionReturn(0);
8852 }
8853 
8854 #undef __FUNCT__
8855 #define __FUNCT__ "DMPlexMatSetClosure"
8856 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8857 {
8858   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8859   PetscInt      *points = PETSC_NULL;
8860   PetscInt      *indices;
8861   PetscInt       offsets[32];
8862   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8863   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8864   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8865   PetscErrorCode ierr;
8866 
8867   PetscFunctionBegin;
8868   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8869   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8870   if (useDefault) {
8871     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8872   }
8873   if (useGlobalDefault) {
8874     if (useDefault) {
8875       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8876     } else {
8877       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8878     }
8879   }
8880   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8881   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8882   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8883   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8884   /* Compress out points not in the section */
8885   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8886   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8887     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8888       points[q*2]   = points[p];
8889       points[q*2+1] = points[p+1];
8890       ++q;
8891     }
8892   }
8893   numPoints = q;
8894   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8895     PetscInt fdof;
8896 
8897     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8898     for (f = 0; f < numFields; ++f) {
8899       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8900       offsets[f+1] += fdof;
8901     }
8902     numIndices += dof;
8903   }
8904   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8905 
8906   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8907   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8908   if (numFields) {
8909     for (p = 0; p < numPoints*2; p += 2) {
8910       PetscInt o = points[p+1];
8911       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8912       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8913     }
8914   } else {
8915     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8916       PetscInt o = points[p+1];
8917       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8918       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8919     }
8920   }
8921   if (useGlobalDefault && !useDefault) {
8922     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8923   }
8924   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8925   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8926   if (ierr) {
8927     PetscMPIInt    rank;
8928     PetscErrorCode ierr2;
8929 
8930     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8931     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8932     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8933     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8934     CHKERRQ(ierr);
8935   }
8936   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8937   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8938   PetscFunctionReturn(0);
8939 }
8940 
8941 #undef __FUNCT__
8942 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8943 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8944 {
8945   PetscSection       coordSection;
8946   Vec                coordinates;
8947   const PetscScalar *coords;
8948   const PetscInt     dim = 2;
8949   PetscInt           d, f;
8950   PetscErrorCode     ierr;
8951 
8952   PetscFunctionBegin;
8953   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8954   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8955   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8956   if (v0) {
8957     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8958   }
8959   if (J) {
8960     for (d = 0; d < dim; d++) {
8961       for (f = 0; f < dim; f++) {
8962         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8963       }
8964     }
8965     *detJ = J[0]*J[3] - J[1]*J[2];
8966 #if 0
8967     if (detJ < 0.0) {
8968       const PetscReal xLength = mesh->periodicity[0];
8969 
8970       if (xLength != 0.0) {
8971         PetscReal v0x = coords[0*dim+0];
8972 
8973         if (v0x == 0.0) v0x = v0[0] = xLength;
8974         for (f = 0; f < dim; f++) {
8975           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8976 
8977           J[0*dim+f] = 0.5*(px - v0x);
8978         }
8979       }
8980       detJ = J[0]*J[3] - J[1]*J[2];
8981     }
8982 #endif
8983     PetscLogFlops(8.0 + 3.0);
8984   }
8985   if (invJ) {
8986     const PetscReal invDet = 1.0/(*detJ);
8987 
8988     invJ[0] =  invDet*J[3];
8989     invJ[1] = -invDet*J[1];
8990     invJ[2] = -invDet*J[2];
8991     invJ[3] =  invDet*J[0];
8992     PetscLogFlops(5.0);
8993   }
8994   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8995   PetscFunctionReturn(0);
8996 }
8997 
8998 #undef __FUNCT__
8999 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9000 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9001 {
9002   PetscSection       coordSection;
9003   Vec                coordinates;
9004   const PetscScalar *coords;
9005   const PetscInt     dim = 2;
9006   PetscInt           d, f;
9007   PetscErrorCode     ierr;
9008 
9009   PetscFunctionBegin;
9010   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9011   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9012   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9013   if (v0) {
9014     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9015   }
9016   if (J) {
9017     for (d = 0; d < dim; d++) {
9018       for (f = 0; f < dim; f++) {
9019         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9020       }
9021     }
9022     *detJ = J[0]*J[3] - J[1]*J[2];
9023     PetscLogFlops(8.0 + 3.0);
9024   }
9025   if (invJ) {
9026     const PetscReal invDet = 1.0/(*detJ);
9027 
9028     invJ[0] =  invDet*J[3];
9029     invJ[1] = -invDet*J[1];
9030     invJ[2] = -invDet*J[2];
9031     invJ[3] =  invDet*J[0];
9032     PetscLogFlops(5.0);
9033   }
9034   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9035   PetscFunctionReturn(0);
9036 }
9037 
9038 #undef __FUNCT__
9039 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9040 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9041 {
9042   PetscSection       coordSection;
9043   Vec                coordinates;
9044   const PetscScalar *coords;
9045   const PetscInt     dim = 3;
9046   PetscInt           d, f;
9047   PetscErrorCode     ierr;
9048 
9049   PetscFunctionBegin;
9050   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9051   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9052   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9053   if (v0) {
9054     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9055   }
9056   if (J) {
9057     for (d = 0; d < dim; d++) {
9058       for (f = 0; f < dim; f++) {
9059         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9060       }
9061     }
9062     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9063     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9064              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9065              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9066     PetscLogFlops(18.0 + 12.0);
9067   }
9068   if (invJ) {
9069     const PetscReal invDet = 1.0/(*detJ);
9070 
9071     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9072     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9073     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9074     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9075     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9076     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9077     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9078     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9079     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9080     PetscLogFlops(37.0);
9081   }
9082   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9083   PetscFunctionReturn(0);
9084 }
9085 
9086 #undef __FUNCT__
9087 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9088 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9089 {
9090   PetscSection       coordSection;
9091   Vec                coordinates;
9092   const PetscScalar *coords;
9093   const PetscInt     dim = 3;
9094   PetscInt           d;
9095   PetscErrorCode     ierr;
9096 
9097   PetscFunctionBegin;
9098   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9099   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9100   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9101   if (v0) {
9102     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9103   }
9104   if (J) {
9105     for (d = 0; d < dim; d++) {
9106       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9107       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9108       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9109     }
9110     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9111              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9112              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9113     PetscLogFlops(18.0 + 12.0);
9114   }
9115   if (invJ) {
9116     const PetscReal invDet = -1.0/(*detJ);
9117 
9118     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9119     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9120     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9121     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9122     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9123     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9124     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9125     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9126     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9127     PetscLogFlops(37.0);
9128   }
9129   *detJ *= 8.0;
9130   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9131   PetscFunctionReturn(0);
9132 }
9133 
9134 #undef __FUNCT__
9135 #define __FUNCT__ "DMPlexComputeCellGeometry"
9136 /*@C
9137   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9138 
9139   Collective on DM
9140 
9141   Input Arguments:
9142 + dm   - the DM
9143 - cell - the cell
9144 
9145   Output Arguments:
9146 + v0   - the translation part of this affine transform
9147 . J    - the Jacobian of the transform to the reference element
9148 . invJ - the inverse of the Jacobian
9149 - detJ - the Jacobian determinant
9150 
9151   Level: advanced
9152 
9153 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9154 @*/
9155 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9156 {
9157   PetscInt       dim, coneSize;
9158   PetscErrorCode ierr;
9159 
9160   PetscFunctionBegin;
9161   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9162   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9163   switch (dim) {
9164   case 2:
9165     switch (coneSize) {
9166     case 3:
9167       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9168       break;
9169     case 4:
9170       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9171       break;
9172     default:
9173       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9174     }
9175     break;
9176   case 3:
9177     switch (coneSize) {
9178     case 4:
9179       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9180       break;
9181     case 8:
9182       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9183       break;
9184     default:
9185       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9186     }
9187     break;
9188   default:
9189     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9190   }
9191   PetscFunctionReturn(0);
9192 }
9193 
9194 #undef __FUNCT__
9195 #define __FUNCT__ "DMPlexGetFaceOrientation"
9196 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9197 {
9198   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9199   PetscBool      posOrient = PETSC_FALSE;
9200   const PetscInt debug     = 0;
9201   PetscInt       cellDim, faceSize, f;
9202   PetscErrorCode ierr;
9203 
9204   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9205   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9206 
9207   if (cellDim == numCorners-1) {
9208     /* Simplices */
9209     faceSize  = numCorners-1;
9210     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9211   } else if (cellDim == 1 && numCorners == 3) {
9212     /* Quadratic line */
9213     faceSize  = 1;
9214     posOrient = PETSC_TRUE;
9215   } else if (cellDim == 2 && numCorners == 4) {
9216     /* Quads */
9217     faceSize = 2;
9218     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9219       posOrient = PETSC_TRUE;
9220     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9221       posOrient = PETSC_TRUE;
9222     } else {
9223       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9224         posOrient = PETSC_FALSE;
9225       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9226     }
9227   } else if (cellDim == 2 && numCorners == 6) {
9228     /* Quadratic triangle (I hate this) */
9229     /* Edges are determined by the first 2 vertices (corners of edges) */
9230     const PetscInt faceSizeTri = 3;
9231     PetscInt       sortedIndices[3], i, iFace;
9232     PetscBool      found                    = PETSC_FALSE;
9233     PetscInt       faceVerticesTriSorted[9] = {
9234       0, 3,  4, /* bottom */
9235       1, 4,  5, /* right */
9236       2, 3,  5, /* left */
9237     };
9238     PetscInt       faceVerticesTri[9] = {
9239       0, 3,  4, /* bottom */
9240       1, 4,  5, /* right */
9241       2, 5,  3, /* left */
9242     };
9243 
9244     faceSize = faceSizeTri;
9245     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9246     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9247     for (iFace = 0; iFace < 3; ++iFace) {
9248       const PetscInt ii = iFace*faceSizeTri;
9249       PetscInt       fVertex, cVertex;
9250 
9251       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9252           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9253         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9254           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9255             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9256               faceVertices[fVertex] = origVertices[cVertex];
9257               break;
9258             }
9259           }
9260         }
9261         found = PETSC_TRUE;
9262         break;
9263       }
9264     }
9265     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9266     if (posOriented) *posOriented = PETSC_TRUE;
9267     PetscFunctionReturn(0);
9268   } else if (cellDim == 2 && numCorners == 9) {
9269     /* Quadratic quad (I hate this) */
9270     /* Edges are determined by the first 2 vertices (corners of edges) */
9271     const PetscInt faceSizeQuad = 3;
9272     PetscInt       sortedIndices[3], i, iFace;
9273     PetscBool      found                      = PETSC_FALSE;
9274     PetscInt       faceVerticesQuadSorted[12] = {
9275       0, 1,  4, /* bottom */
9276       1, 2,  5, /* right */
9277       2, 3,  6, /* top */
9278       0, 3,  7, /* left */
9279     };
9280     PetscInt       faceVerticesQuad[12] = {
9281       0, 1,  4, /* bottom */
9282       1, 2,  5, /* right */
9283       2, 3,  6, /* top */
9284       3, 0,  7, /* left */
9285     };
9286 
9287     faceSize = faceSizeQuad;
9288     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9289     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9290     for (iFace = 0; iFace < 4; ++iFace) {
9291       const PetscInt ii = iFace*faceSizeQuad;
9292       PetscInt       fVertex, cVertex;
9293 
9294       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9295           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9296         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9297           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9298             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9299               faceVertices[fVertex] = origVertices[cVertex];
9300               break;
9301             }
9302           }
9303         }
9304         found = PETSC_TRUE;
9305         break;
9306       }
9307     }
9308     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9309     if (posOriented) *posOriented = PETSC_TRUE;
9310     PetscFunctionReturn(0);
9311   } else if (cellDim == 3 && numCorners == 8) {
9312     /* Hexes
9313        A hex is two oriented quads with the normal of the first
9314        pointing up at the second.
9315 
9316           7---6
9317          /|  /|
9318         4---5 |
9319         | 3-|-2
9320         |/  |/
9321         0---1
9322 
9323         Faces are determined by the first 4 vertices (corners of faces) */
9324     const PetscInt faceSizeHex = 4;
9325     PetscInt       sortedIndices[4], i, iFace;
9326     PetscBool      found                     = PETSC_FALSE;
9327     PetscInt       faceVerticesHexSorted[24] = {
9328       0, 1, 2, 3,  /* bottom */
9329       4, 5, 6, 7,  /* top */
9330       0, 1, 4, 5,  /* front */
9331       1, 2, 5, 6,  /* right */
9332       2, 3, 6, 7,  /* back */
9333       0, 3, 4, 7,  /* left */
9334     };
9335     PetscInt       faceVerticesHex[24] = {
9336       3, 2, 1, 0,  /* bottom */
9337       4, 5, 6, 7,  /* top */
9338       0, 1, 5, 4,  /* front */
9339       1, 2, 6, 5,  /* right */
9340       2, 3, 7, 6,  /* back */
9341       3, 0, 4, 7,  /* left */
9342     };
9343 
9344     faceSize = faceSizeHex;
9345     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9346     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9347     for (iFace = 0; iFace < 6; ++iFace) {
9348       const PetscInt ii = iFace*faceSizeHex;
9349       PetscInt       fVertex, cVertex;
9350 
9351       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9352           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9353           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9354           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9355         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9356           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9357             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9358               faceVertices[fVertex] = origVertices[cVertex];
9359               break;
9360             }
9361           }
9362         }
9363         found = PETSC_TRUE;
9364         break;
9365       }
9366     }
9367     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9368     if (posOriented) *posOriented = PETSC_TRUE;
9369     PetscFunctionReturn(0);
9370   } else if (cellDim == 3 && numCorners == 10) {
9371     /* Quadratic tet */
9372     /* Faces are determined by the first 3 vertices (corners of faces) */
9373     const PetscInt faceSizeTet = 6;
9374     PetscInt       sortedIndices[6], i, iFace;
9375     PetscBool      found                     = PETSC_FALSE;
9376     PetscInt       faceVerticesTetSorted[24] = {
9377       0, 1, 2,  6, 7, 8, /* bottom */
9378       0, 3, 4,  6, 7, 9,  /* front */
9379       1, 4, 5,  7, 8, 9,  /* right */
9380       2, 3, 5,  6, 8, 9,  /* left */
9381     };
9382     PetscInt       faceVerticesTet[24] = {
9383       0, 1, 2,  6, 7, 8, /* bottom */
9384       0, 4, 3,  6, 7, 9,  /* front */
9385       1, 5, 4,  7, 8, 9,  /* right */
9386       2, 3, 5,  8, 6, 9,  /* left */
9387     };
9388 
9389     faceSize = faceSizeTet;
9390     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9391     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9392     for (iFace=0; iFace < 4; ++iFace) {
9393       const PetscInt ii = iFace*faceSizeTet;
9394       PetscInt       fVertex, cVertex;
9395 
9396       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9397           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9398           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9399           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9400         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9401           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9402             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9403               faceVertices[fVertex] = origVertices[cVertex];
9404               break;
9405             }
9406           }
9407         }
9408         found = PETSC_TRUE;
9409         break;
9410       }
9411     }
9412     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9413     if (posOriented) *posOriented = PETSC_TRUE;
9414     PetscFunctionReturn(0);
9415   } else if (cellDim == 3 && numCorners == 27) {
9416     /* Quadratic hexes (I hate this)
9417        A hex is two oriented quads with the normal of the first
9418        pointing up at the second.
9419 
9420          7---6
9421         /|  /|
9422        4---5 |
9423        | 3-|-2
9424        |/  |/
9425        0---1
9426 
9427        Faces are determined by the first 4 vertices (corners of faces) */
9428     const PetscInt faceSizeQuadHex = 9;
9429     PetscInt       sortedIndices[9], i, iFace;
9430     PetscBool      found                         = PETSC_FALSE;
9431     PetscInt       faceVerticesQuadHexSorted[54] = {
9432       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9433       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9434       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9435       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9436       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9437       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9438     };
9439     PetscInt       faceVerticesQuadHex[54] = {
9440       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9441       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9442       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9443       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9444       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9445       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9446     };
9447 
9448     faceSize = faceSizeQuadHex;
9449     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9450     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9451     for (iFace = 0; iFace < 6; ++iFace) {
9452       const PetscInt ii = iFace*faceSizeQuadHex;
9453       PetscInt       fVertex, cVertex;
9454 
9455       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9456           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9457           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9458           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9459         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9460           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9461             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9462               faceVertices[fVertex] = origVertices[cVertex];
9463               break;
9464             }
9465           }
9466         }
9467         found = PETSC_TRUE;
9468         break;
9469       }
9470     }
9471     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9472     if (posOriented) *posOriented = PETSC_TRUE;
9473     PetscFunctionReturn(0);
9474   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9475   if (!posOrient) {
9476     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9477     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize-1 - f];
9478   } else {
9479     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9480     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f];
9481   }
9482   if (posOriented) *posOriented = posOrient;
9483   PetscFunctionReturn(0);
9484 }
9485 
9486 #undef __FUNCT__
9487 #define __FUNCT__ "DMPlexGetOrientedFace"
9488 /*
9489     Given a cell and a face, as a set of vertices,
9490       return the oriented face, as a set of vertices, in faceVertices
9491     The orientation is such that the face normal points out of the cell
9492 */
9493 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9494 {
9495   const PetscInt *cone = PETSC_NULL;
9496   PetscInt        coneSize, v, f, v2;
9497   PetscInt        oppositeVertex = -1;
9498   PetscErrorCode  ierr;
9499 
9500   PetscFunctionBegin;
9501   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9502   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9503   for (v = 0, v2 = 0; v < coneSize; ++v) {
9504     PetscBool found = PETSC_FALSE;
9505 
9506     for (f = 0; f < faceSize; ++f) {
9507       if (face[f] == cone[v]) {
9508         found = PETSC_TRUE; break;
9509       }
9510     }
9511     if (found) {
9512       indices[v2]      = v;
9513       origVertices[v2] = cone[v];
9514       ++v2;
9515     } else {
9516       oppositeVertex = v;
9517     }
9518   }
9519   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9520   PetscFunctionReturn(0);
9521 }
9522 
9523 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9524 {
9525   switch (i) {
9526   case 0:
9527     switch (j) {
9528     case 0: return 0;
9529     case 1:
9530       switch (k) {
9531       case 0: return 0;
9532       case 1: return 0;
9533       case 2: return 1;
9534       }
9535     case 2:
9536       switch (k) {
9537       case 0: return 0;
9538       case 1: return -1;
9539       case 2: return 0;
9540       }
9541     }
9542   case 1:
9543     switch (j) {
9544     case 0:
9545       switch (k) {
9546       case 0: return 0;
9547       case 1: return 0;
9548       case 2: return -1;
9549       }
9550     case 1: return 0;
9551     case 2:
9552       switch (k) {
9553       case 0: return 1;
9554       case 1: return 0;
9555       case 2: return 0;
9556       }
9557     }
9558   case 2:
9559     switch (j) {
9560     case 0:
9561       switch (k) {
9562       case 0: return 0;
9563       case 1: return 1;
9564       case 2: return 0;
9565       }
9566     case 1:
9567       switch (k) {
9568       case 0: return -1;
9569       case 1: return 0;
9570       case 2: return 0;
9571       }
9572     case 2: return 0;
9573     }
9574   }
9575   return 0;
9576 }
9577 
9578 #undef __FUNCT__
9579 #define __FUNCT__ "DMPlexCreateRigidBody"
9580 /*@C
9581   DMPlexCreateRigidBody - create rigid body modes from coordinates
9582 
9583   Collective on DM
9584 
9585   Input Arguments:
9586 + dm - the DM
9587 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9588 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9589 
9590   Output Argument:
9591 . sp - the null space
9592 
9593   Note: This is necessary to take account of Dirichlet conditions on the displacements
9594 
9595   Level: advanced
9596 
9597 .seealso: MatNullSpaceCreate()
9598 @*/
9599 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9600 {
9601   MPI_Comm       comm = ((PetscObject) dm)->comm;
9602   Vec            coordinates, localMode, mode[6];
9603   PetscSection   coordSection;
9604   PetscScalar   *coords;
9605   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9606   PetscErrorCode ierr;
9607 
9608   PetscFunctionBegin;
9609   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9610   if (dim == 1) {
9611     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9612     PetscFunctionReturn(0);
9613   }
9614   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9615   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9616   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9617   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9618   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9619   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9620   m    = (dim*(dim+1))/2;
9621   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9622   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9623   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9624   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9625   /* Assume P1 */
9626   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9627   for (d = 0; d < dim; ++d) {
9628     PetscScalar values[3] = {0.0, 0.0, 0.0};
9629 
9630     values[d] = 1.0;
9631     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9632     for (v = vStart; v < vEnd; ++v) {
9633       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9634     }
9635     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9636     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9637   }
9638   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9639   for (d = dim; d < dim*(dim+1)/2; ++d) {
9640     PetscInt i, j, k = dim > 2 ? d - dim : d;
9641 
9642     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9643     for (v = vStart; v < vEnd; ++v) {
9644       PetscScalar values[3] = {0.0, 0.0, 0.0};
9645       PetscInt    off;
9646 
9647       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9648       for (i = 0; i < dim; ++i) {
9649         for (j = 0; j < dim; ++j) {
9650           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9651         }
9652       }
9653       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9654     }
9655     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9656     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9657   }
9658   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9659   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9660   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9661   /* Orthonormalize system */
9662   for (i = dim; i < m; ++i) {
9663     PetscScalar dots[6];
9664 
9665     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9666     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9667     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9668     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9669   }
9670   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9671   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9672   PetscFunctionReturn(0);
9673 }
9674 
9675 #undef __FUNCT__
9676 #define __FUNCT__ "DMPlexGetHybridBounds"
9677 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9678 {
9679   DM_Plex       *mesh = (DM_Plex*) dm->data;
9680   PetscInt       dim;
9681   PetscErrorCode ierr;
9682 
9683   PetscFunctionBegin;
9684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9685   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9686   if (cMax) *cMax = mesh->hybridPointMax[dim];
9687   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9688   if (eMax) *eMax = mesh->hybridPointMax[1];
9689   if (vMax) *vMax = mesh->hybridPointMax[0];
9690   PetscFunctionReturn(0);
9691 }
9692 
9693 #undef __FUNCT__
9694 #define __FUNCT__ "DMPlexSetHybridBounds"
9695 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9696 {
9697   DM_Plex       *mesh = (DM_Plex*) dm->data;
9698   PetscInt       dim;
9699   PetscErrorCode ierr;
9700 
9701   PetscFunctionBegin;
9702   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9703   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9704   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9705   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9706   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9707   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9708   PetscFunctionReturn(0);
9709 }
9710 
9711 #undef __FUNCT__
9712 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9713 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9714 {
9715   DM_Plex *mesh = (DM_Plex*) dm->data;
9716 
9717   PetscFunctionBegin;
9718   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9719   PetscValidPointer(cellHeight, 2);
9720   *cellHeight = mesh->vtkCellHeight;
9721   PetscFunctionReturn(0);
9722 }
9723 
9724 #undef __FUNCT__
9725 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9726 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9727 {
9728   DM_Plex *mesh = (DM_Plex*) dm->data;
9729 
9730   PetscFunctionBegin;
9731   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9732   mesh->vtkCellHeight = cellHeight;
9733   PetscFunctionReturn(0);
9734 }
9735 
9736 #undef __FUNCT__
9737 #define __FUNCT__ "DMPlexInsertFace_Private"
9738 /*
9739   DMPlexInsertFace_Private - Puts a face into the mesh
9740 
9741   Not collective
9742 
9743   Input Parameters:
9744   + dm              - The DMPlex
9745   . numFaceVertex   - The number of vertices in the face
9746   . faceVertices    - The vertices in the face for dm
9747   . subfaceVertices - The vertices in the face for subdm
9748   . numCorners      - The number of vertices in the cell
9749   . cell            - A cell in dm containing the face
9750   . subcell         - A cell in subdm containing the face
9751   . firstFace       - First face in the mesh
9752   - newFacePoint    - Next face in the mesh
9753 
9754   Output Parameters:
9755   . newFacePoint - Contains next face point number on input, updated on output
9756 
9757   Level: developer
9758 */
9759 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)
9760 {
9761   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9762   DM_Plex        *submesh = (DM_Plex*) subdm->data;
9763   const PetscInt *faces;
9764   PetscInt        numFaces, coneSize;
9765   PetscErrorCode  ierr;
9766 
9767   PetscFunctionBegin;
9768   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9769   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9770 #if 0
9771   /* Cannot use this because support() has not been constructed yet */
9772   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9773 #else
9774   {
9775     PetscInt f;
9776 
9777     numFaces = 0;
9778     ierr     = DMGetWorkArray(subdm, 1, PETSC_INT, (void**) &faces);CHKERRQ(ierr);
9779     for (f = firstFace; f < *newFacePoint; ++f) {
9780       PetscInt dof, off, d;
9781 
9782       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9783       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9784       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9785       for (d = 0; d < dof; ++d) {
9786         const PetscInt p = submesh->cones[off+d];
9787         PetscInt       v;
9788 
9789         for (v = 0; v < numFaceVertices; ++v) {
9790           if (subfaceVertices[v] == p) break;
9791         }
9792         if (v == numFaceVertices) break;
9793       }
9794       if (d == dof) {
9795         numFaces               = 1;
9796         ((PetscInt*) faces)[0] = f;
9797       }
9798     }
9799   }
9800 #endif
9801   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
9802   else if (numFaces == 1) {
9803     /* Add the other cell neighbor for this face */
9804     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
9805   } else {
9806     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
9807     PetscBool posOriented;
9808 
9809     ierr                = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9810     origVertices        = &orientedVertices[numFaceVertices];
9811     indices             = &orientedVertices[numFaceVertices*2];
9812     orientedSubVertices = &orientedVertices[numFaceVertices*3];
9813     ierr                = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
9814     /* TODO: I know that routine should return a permutation, not the indices */
9815     for (v = 0; v < numFaceVertices; ++v) {
9816       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
9817       for (ov = 0; ov < numFaceVertices; ++ov) {
9818         if (orientedVertices[ov] == vertex) {
9819           orientedSubVertices[ov] = subvertex;
9820           break;
9821         }
9822       }
9823       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
9824     }
9825     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
9826     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
9827     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9828     ++(*newFacePoint);
9829   }
9830   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9831   PetscFunctionReturn(0);
9832 }
9833 
9834 #undef __FUNCT__
9835 #define __FUNCT__ "DMPlexCreateSubmesh_Uninterpolated"
9836 static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, const char label[], DM subdm)
9837 {
9838   MPI_Comm        comm = ((PetscObject) dm)->comm;
9839   PetscBool       boundaryFaces = PETSC_FALSE;
9840   PetscSection    coordSection, subCoordSection;
9841   Vec             coordinates, subCoordinates;
9842   PetscScalar    *coords, *subCoords;
9843   DMLabel         subpointMap;
9844   IS              labelIS;
9845   const PetscInt *subVertices;
9846   PetscInt       *subVerticesActive;
9847   PetscInt       *subCells = PETSC_NULL;
9848   PetscInt        numSubVertices = 0, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
9849   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
9850   PetscInt        dim;  /* Right now, do not specify dimension */
9851   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
9852   PetscErrorCode  ierr;
9853 
9854   PetscFunctionBegin;
9855   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9856   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9857   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9858   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
9859   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9860   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9861   if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9862   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9863   subface = &face[maxConeSize];
9864   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
9865   if (labelIS) {
9866     ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
9867     ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
9868   }
9869   maxSubCells = numSubVertices;
9870   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
9871   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
9872   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
9873   for (v = 0; v < numSubVertices; ++v) {
9874     const PetscInt vertex = subVertices[v];
9875     PetscInt      *star   = PETSC_NULL;
9876     PetscInt       starSize, numCells = 0;
9877 
9878     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9879     for (p = 0; p < starSize*2; p += 2) {
9880       const PetscInt point = star[p];
9881       if ((point >= cStart) && (point < cEnd)) star[numCells++] = point;
9882     }
9883     numOldSubCells = numSubCells;
9884     for (c = 0; c < numCells; ++c) {
9885       const PetscInt cell    = star[c];
9886       PetscInt      *closure = PETSC_NULL;
9887       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9888       PetscInt       cellLoc;
9889 
9890       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9891       if (cellLoc >= 0) continue;
9892       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9893       for (p = 0; p < closureSize*2; p += 2) {
9894         const PetscInt point = closure[p];
9895         if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
9896       }
9897       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9898       for (corner = 0; corner < numCorners; ++corner) {
9899         const PetscInt cellVertex = closure[corner];
9900         PetscInt       subVertex;
9901 
9902         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9903         if (subVertex >= 0) { /* contains submesh vertex */
9904           for (i = 0; i < faceSize; ++i) {
9905             if (cellVertex == face[i]) break;
9906           }
9907           if (i == faceSize) {
9908             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9909             face[faceSize]    = cellVertex;
9910             subface[faceSize] = subVertex;
9911             ++faceSize;
9912           }
9913         }
9914       }
9915       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9916       if (faceSize >= nFV) {
9917         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9918         if (numSubCells >= maxSubCells) {
9919           PetscInt *tmpCells;
9920           maxSubCells *= 2;
9921           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9922           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9923           ierr = PetscFree(subCells);CHKERRQ(ierr);
9924 
9925           subCells = tmpCells;
9926         }
9927         /* TOOD: Maybe overestimate then squeeze out empty faces */
9928         if (faceSize > nFV) {
9929           /* TODO: This is tricky. Maybe just add all faces */
9930           numSubFaces++;
9931         } else {
9932           numSubFaces++;
9933         }
9934         for (f = 0; f < faceSize; ++f) subVerticesActive[subface[f]] = 1;
9935         subCells[numSubCells++] = cell;
9936       }
9937     }
9938     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9939     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9940   }
9941   /* Pick out active subvertices */
9942   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9943     if (subVerticesActive[v]) {
9944       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9945     }
9946   }
9947   ierr = DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9948   /* Set cone sizes */
9949   firstSubVertex = numSubCells;
9950   firstSubFace   = numSubCells+numSubVerticesActive;
9951   newFacePoint   = firstSubFace;
9952   for (c = 0; c < numSubCells; ++c) {
9953     ierr = DMPlexSetConeSize(subdm, c, 1);CHKERRQ(ierr);
9954   }
9955   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9956     ierr = DMPlexSetConeSize(subdm, f, nFV);CHKERRQ(ierr);
9957   }
9958   ierr = DMSetUp(subdm);CHKERRQ(ierr);
9959   /* Create face cones */
9960   for (c = 0; c < numSubCells; ++c) {
9961     const PetscInt cell    = subCells[c];
9962     PetscInt      *closure = PETSC_NULL;
9963     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9964 
9965     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9966     for (p = 0; p < closureSize*2; p += 2) {
9967       const PetscInt point = closure[p];
9968       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
9969     }
9970     for (corner = 0; corner < numCorners; ++corner) {
9971       const PetscInt cellVertex = closure[corner];
9972       PetscInt       subVertex;
9973 
9974       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9975       if (subVertex >= 0) { /* contains submesh vertex */
9976         for (i = 0; i < faceSize; ++i) {
9977           if (cellVertex == face[i]) break;
9978         }
9979         if (i == faceSize) {
9980           face[faceSize]    = cellVertex;
9981           subface[faceSize] = numSubCells+subVertex;
9982           ++faceSize;
9983         }
9984       }
9985     }
9986     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9987     if (faceSize >= nFV) {
9988       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9989       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
9990       /*   We have to take all the faces, and discard those in the interior */
9991       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
9992 #if 0
9993       /* This object just calls insert on each face that comes from subsets() */
9994       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
9995       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9996       PointArray                          faceVec(face->begin(), face->end());
9997 
9998       subsets(faceVec, nFV, inserter);
9999 #endif
10000       ierr = DMPlexInsertFace_Private(dm, subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10001     }
10002   }
10003   ierr = DMPlexSymmetrize(subdm);CHKERRQ(ierr);
10004   ierr = DMPlexStratify(subdm);CHKERRQ(ierr);
10005   /* Build coordinates */
10006   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10007   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10008   ierr = DMPlexGetCoordinateSection(subdm, &subCoordSection);CHKERRQ(ierr);
10009   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10010   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10011     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10012   }
10013   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10014   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10015   ierr = VecCreate(comm, &subCoordinates);CHKERRQ(ierr);
10016   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10017   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10018   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10019   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10020   for (v = 0; v < numSubVerticesActive; ++v) {
10021     const PetscInt vertex    = subVerticesActive[v];
10022     const PetscInt subVertex = firstSubVertex+v;
10023     PetscInt       dof, off, sdof, soff;
10024 
10025     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10026     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10027     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10028     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10029     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10030     for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
10031   }
10032   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10033   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10034   ierr = DMSetCoordinatesLocal(subdm, subCoordinates);CHKERRQ(ierr);
10035   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10036 
10037   ierr = DMPlexSetVTKCellHeight(subdm, 1);CHKERRQ(ierr);
10038   /* Create map from submesh points to original mesh points */
10039   ierr = DMLabelCreate("subpoint_map", &subpointMap);CHKERRQ(ierr);
10040   for (c = 0; c < numSubCells; ++c) {ierr = DMLabelSetValue(subpointMap, subCells[c], 1);CHKERRQ(ierr);}
10041   for (v = 0; v < numSubVerticesActive; ++v) {ierr = DMLabelSetValue(subpointMap, subVerticesActive[v], 0);CHKERRQ(ierr);}
10042   ierr = DMPlexSetSubpointMap(subdm, subpointMap);CHKERRQ(ierr);
10043   ierr = DMLabelDestroy(&subpointMap);CHKERRQ(ierr);
10044 
10045   ierr = PetscFree(subCells);CHKERRQ(ierr);
10046   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10047   if (labelIS) {
10048     ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10049     ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10050   }
10051   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10052   PetscFunctionReturn(0);
10053 }
10054 
10055 #undef __FUNCT__
10056 #define __FUNCT__ "DMPlexCreateSubmesh_Interpolated"
10057 static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, const char vertexLabelName[], DM subdm)
10058 {
10059   MPI_Comm         comm = ((PetscObject) dm)->comm;
10060   DMLabel          subpointMap, vertexLabel;
10061   IS              *subpointIS, subvertexIS;
10062   const PetscInt **subpoints, *subvertices;
10063   PetscInt        *pStart, *pEnd, *numSubPoints, *firstSubPoint, *coneNew;
10064   PetscInt         numSubVerticesInitial, totSubPoints = 0, maxConeSize, dim, p, d, v;
10065   PetscErrorCode   ierr;
10066 
10067   PetscFunctionBegin;
10068   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10069   ierr = PetscMalloc6(dim+1,PetscInt,&pStart,dim+1,PetscInt,&pEnd,dim+1,PetscInt,&numSubPoints,dim+1,PetscInt,&firstSubPoint,dim+1,IS,&subpointIS,dim+1,const PetscInt *,&subpoints);CHKERRQ(ierr);
10070   for (d = 0; d <= dim; ++d) {
10071     ierr = DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);CHKERRQ(ierr);
10072   }
10073   ierr = DMLabelCreate("subpoint_map", &subpointMap);CHKERRQ(ierr);
10074   ierr = DMPlexGetLabel(dm, vertexLabelName, &vertexLabel);CHKERRQ(ierr);
10075   ierr = DMLabelGetStratumIS(vertexLabel, 1, &subvertexIS);CHKERRQ(ierr);
10076   ierr = ISGetSize(subvertexIS, &numSubVerticesInitial);CHKERRQ(ierr);
10077   ierr = ISGetIndices(subvertexIS, &subvertices);CHKERRQ(ierr);
10078   /* Loop over initial vertices and mark all faces in the collective star() */
10079   for (v = 0; v < numSubVerticesInitial; ++v) {
10080     const PetscInt vertex = subvertices[v];
10081     PetscInt      *star   = PETSC_NULL;
10082     PetscInt       starSize, s, numFaces = 0, f;
10083 
10084     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10085     for (s = 0; s < starSize*2; s += 2) {
10086       const PetscInt point = star[s];
10087       if ((point >= pStart[dim-1]) && (point < pEnd[dim-1])) {
10088         star[numFaces++] = point;
10089       }
10090     }
10091     for (f = 0; f < numFaces; ++f) {
10092       const PetscInt face    = star[f];
10093       PetscInt      *closure = PETSC_NULL;
10094       PetscInt       closureSize, c;
10095       PetscInt       faceLoc;
10096 
10097       ierr = DMLabelGetValue(subpointMap, face, &faceLoc);CHKERRQ(ierr);
10098       if (faceLoc == dim-1) continue;
10099       if (faceLoc >= 0) SETERRQ2(comm, PETSC_ERR_PLIB, "Face %d has dimension %d in the surface label", face, faceLoc);
10100       ierr = DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10101       for (c = 0; c < closureSize*2; c += 2) {
10102         const PetscInt point = closure[c];
10103         PetscInt       vertexLoc;
10104 
10105         if ((point >= pStart[0]) && (point < pEnd[0])) {
10106           ierr = DMLabelGetValue(vertexLabel, point, &vertexLoc);CHKERRQ(ierr);
10107           if (vertexLoc < 0) break;
10108         }
10109       }
10110       if (c == closureSize*2) {
10111         const PetscInt *support;
10112         PetscInt        supportSize, s;
10113 
10114         for (c = 0; c < closureSize*2; c += 2) {
10115           const PetscInt point = closure[c];
10116 
10117           for (d = 0; d < dim; ++d) {
10118             if ((point >= pStart[d]) && (point < pEnd[d])) {
10119               ierr = DMLabelSetValue(subpointMap, point, d);CHKERRQ(ierr);
10120               break;
10121             }
10122           }
10123         }
10124         ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10125         ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10126         for (s = 0; s < supportSize; ++s) {
10127           ierr = DMLabelSetValue(subpointMap, support[s], dim);CHKERRQ(ierr);
10128         }
10129       }
10130       ierr = DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10131     }
10132     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10133   }
10134   ierr = ISRestoreIndices(subvertexIS, &subvertices);CHKERRQ(ierr);
10135   ierr = ISDestroy(&subvertexIS);CHKERRQ(ierr);
10136   for (d = 0; d <= dim; ++d) {
10137     ierr = DMLabelGetStratumSize(subpointMap, d, &numSubPoints[d]);CHKERRQ(ierr);
10138     totSubPoints += numSubPoints[d];
10139   }
10140   ierr = DMPlexSetChart(subdm, 0, totSubPoints);CHKERRQ(ierr);
10141   ierr = DMPlexSetVTKCellHeight(subdm, 1);CHKERRQ(ierr);
10142   /* Set cone sizes */
10143   firstSubPoint[dim] = 0;
10144   firstSubPoint[0]   = firstSubPoint[dim] + numSubPoints[dim];
10145   if (dim > 1) {firstSubPoint[dim-1] = firstSubPoint[0]     + numSubPoints[0];}
10146   if (dim > 2) {firstSubPoint[dim-2] = firstSubPoint[dim-1] + numSubPoints[dim-1];}
10147   for (d = 0; d <= dim; ++d) {
10148     ierr = DMLabelGetStratumIS(subpointMap, d, &subpointIS[d]);CHKERRQ(ierr);
10149     ierr = ISGetIndices(subpointIS[d], &subpoints[d]);CHKERRQ(ierr);
10150   }
10151   for (d = 0; d <= dim; ++d) {
10152     for (p = 0; p < numSubPoints[d]; ++p) {
10153       const PetscInt  point    = subpoints[d][p];
10154       const PetscInt  subpoint = firstSubPoint[d] + p;
10155       const PetscInt *cone;
10156       PetscInt        coneSize, coneSizeNew, c, val;
10157 
10158       ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
10159       ierr = DMPlexSetConeSize(subdm, subpoint, coneSize);CHKERRQ(ierr);
10160       if (d == dim) {
10161         ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
10162         for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
10163           ierr = DMLabelGetValue(subpointMap, cone[c], &val);CHKERRQ(ierr);
10164           if (val >= 0) coneSizeNew++;
10165         }
10166         ierr = DMPlexSetConeSize(subdm, subpoint, coneSizeNew);CHKERRQ(ierr);
10167       }
10168     }
10169   }
10170   ierr = DMSetUp(subdm);CHKERRQ(ierr);
10171   /* Set cones */
10172   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
10173   ierr = PetscMalloc(maxConeSize * sizeof(PetscInt), &coneNew);CHKERRQ(ierr);
10174   for (d = 0; d <= dim; ++d) {
10175     for (p = 0; p < numSubPoints[d]; ++p) {
10176       const PetscInt  point    = subpoints[d][p];
10177       const PetscInt  subpoint = firstSubPoint[d] + p;
10178       const PetscInt *cone;
10179       PetscInt        coneSize, subconeSize, coneSizeNew, c, subc;
10180 
10181       ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
10182       ierr = DMPlexGetConeSize(subdm, subpoint, &subconeSize);CHKERRQ(ierr);
10183       ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
10184       for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
10185         ierr = PetscFindInt(cone[c], numSubPoints[d-1], subpoints[d-1], &subc);CHKERRQ(ierr);
10186         if (subc >= 0) coneNew[coneSizeNew++] = firstSubPoint[d-1] + subc;
10187       }
10188       if (coneSizeNew != subconeSize) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of cone points located %d does not match subcone size %d", coneSizeNew, subconeSize);
10189       ierr = DMPlexSetCone(subdm, subpoint, coneNew);CHKERRQ(ierr);
10190     }
10191   }
10192   ierr = PetscFree(coneNew);CHKERRQ(ierr);
10193   ierr = DMPlexSymmetrize(subdm);CHKERRQ(ierr);
10194   ierr = DMPlexStratify(subdm);CHKERRQ(ierr);
10195   /* Build coordinates */
10196   {
10197     PetscSection    coordSection, subCoordSection;
10198     Vec             coordinates, subCoordinates;
10199     PetscScalar    *coords, *subCoords;
10200     PetscInt        coordSize;
10201 
10202     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10203     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10204     ierr = DMPlexGetCoordinateSection(subdm, &subCoordSection);CHKERRQ(ierr);
10205     ierr = PetscSectionSetChart(subCoordSection, firstSubPoint[0], firstSubPoint[0]+numSubPoints[0]);CHKERRQ(ierr);
10206     for (v = 0; v < numSubPoints[0]; ++v) {
10207       const PetscInt vertex    = subpoints[0][v];
10208       const PetscInt subvertex = firstSubPoint[0]+v;
10209       PetscInt       dof;
10210 
10211       ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10212       ierr = PetscSectionSetDof(subCoordSection, subvertex, dof);CHKERRQ(ierr);
10213     }
10214     ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10215     ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10216     ierr = VecCreate(comm, &subCoordinates);CHKERRQ(ierr);
10217     ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10218     ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10219     ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10220     ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10221     for (v = 0; v < numSubPoints[0]; ++v) {
10222       const PetscInt vertex    = subpoints[0][v];
10223       const PetscInt subvertex = firstSubPoint[0]+v;
10224       PetscInt dof, off, sdof, soff, d;
10225 
10226       ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10227       ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10228       ierr = PetscSectionGetDof(subCoordSection, subvertex, &sdof);CHKERRQ(ierr);
10229       ierr = PetscSectionGetOffset(subCoordSection, subvertex, &soff);CHKERRQ(ierr);
10230       if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof);
10231       for (d = 0; d < dof; ++d) {
10232         subCoords[soff+d] = coords[off+d];
10233       }
10234     }
10235     ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10236     ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10237     ierr = DMSetCoordinatesLocal(subdm, subCoordinates);CHKERRQ(ierr);
10238     ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10239   }
10240   for (d = 0; d <= dim; ++d) {
10241     ierr = ISRestoreIndices(subpointIS[d], &subpoints[d]);CHKERRQ(ierr);
10242     ierr = ISDestroy(&subpointIS[d]);CHKERRQ(ierr);
10243   }
10244   ierr = DMPlexSetSubpointMap(subdm, subpointMap);CHKERRQ(ierr);
10245   ierr = DMLabelDestroy(&subpointMap);CHKERRQ(ierr);
10246   PetscFunctionReturn(0);
10247 }
10248 
10249 #undef __FUNCT__
10250 #define __FUNCT__ "DMPlexCreateSubmesh"
10251 /*
10252   DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label
10253 
10254   Input Parameters:
10255 + dm           - The original mesh
10256 - vertexLabel  - The DMLabel marking vertices contained in the surface
10257 
10258   Output Parameter:
10259 . subdm - The surface mesh
10260 
10261   Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().
10262 
10263   Level: developer
10264 
10265 .seealso: DMPlexGetSubpointMap(), DMPlexGetLabel(), DMLabelSetValue()
10266 */
10267 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char vertexLabel[], DM *subdm)
10268 {
10269   PetscInt       dim, depth;
10270   PetscErrorCode ierr;
10271 
10272   PetscFunctionBegin;
10273   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10274   PetscValidCharPointer(vertexLabel, 2);
10275   PetscValidPointer(subdm, 4);
10276   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10277   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10278   ierr = DMCreate(((PetscObject) dm)->comm, subdm);CHKERRQ(ierr);
10279   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10280   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10281   /* TODO Remove the dim guard */
10282   if ((dim > 1) && (depth == dim)) {
10283     ierr = DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, *subdm);CHKERRQ(ierr);
10284   } else {
10285     ierr = DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, *subdm);CHKERRQ(ierr);
10286   }
10287   PetscFunctionReturn(0);
10288 }
10289 
10290 #undef __FUNCT__
10291 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10292 /* We can easily have a form that takes an IS instead */
10293 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10294 {
10295   PetscSection   section, globalSection;
10296   PetscInt      *numbers, p;
10297   PetscErrorCode ierr;
10298 
10299   PetscFunctionBegin;
10300   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10301   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10302   for (p = pStart; p < pEnd; ++p) {
10303     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10304   }
10305   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10306   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10307   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10308   for (p = pStart; p < pEnd; ++p) {
10309     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10310   }
10311   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10312   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10313   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10314   PetscFunctionReturn(0);
10315 }
10316 
10317 #undef __FUNCT__
10318 #define __FUNCT__ "DMPlexGetCellNumbering"
10319 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10320 {
10321   DM_Plex       *mesh = (DM_Plex*) dm->data;
10322   PetscInt       cellHeight, cStart, cEnd, cMax;
10323   PetscErrorCode ierr;
10324 
10325   PetscFunctionBegin;
10326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10327   if (!mesh->globalCellNumbers) {
10328     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10329     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10330     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10331     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
10332     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10333   }
10334   *globalCellNumbers = mesh->globalCellNumbers;
10335   PetscFunctionReturn(0);
10336 }
10337 
10338 #undef __FUNCT__
10339 #define __FUNCT__ "DMPlexGetVertexNumbering"
10340 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10341 {
10342   DM_Plex       *mesh = (DM_Plex*) dm->data;
10343   PetscInt       vStart, vEnd, vMax;
10344   PetscErrorCode ierr;
10345 
10346   PetscFunctionBegin;
10347   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10348   if (!mesh->globalVertexNumbers) {
10349     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10350     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10351     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
10352     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10353   }
10354   *globalVertexNumbers = mesh->globalVertexNumbers;
10355   PetscFunctionReturn(0);
10356 }
10357 
10358 #undef __FUNCT__
10359 #define __FUNCT__ "DMPlexGetSubpointMap"
10360 PetscErrorCode DMPlexGetSubpointMap(DM dm, DMLabel *subpointMap)
10361 {
10362   DM_Plex *mesh = (DM_Plex*) dm->data;
10363 
10364   PetscFunctionBegin;
10365   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10366   PetscValidPointer(subpointMap, 2);
10367   *subpointMap = mesh->subpointMap;
10368   PetscFunctionReturn(0);
10369 }
10370 
10371 #undef __FUNCT__
10372 #define __FUNCT__ "DMPlexSetSubpointMap"
10373 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10374 PetscErrorCode DMPlexSetSubpointMap(DM dm, DMLabel subpointMap)
10375 {
10376   DM_Plex       *mesh = (DM_Plex*) dm->data;
10377   PetscErrorCode ierr;
10378 
10379   PetscFunctionBegin;
10380   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10381   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
10382   mesh->subpointMap = subpointMap;
10383   ++mesh->subpointMap->refct;CHKERRQ(ierr);
10384   PetscFunctionReturn(0);
10385 }
10386 
10387 #undef __FUNCT__
10388 #define __FUNCT__ "DMPlexGetScale"
10389 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10390 {
10391   DM_Plex *mesh = (DM_Plex*) dm->data;
10392 
10393   PetscFunctionBegin;
10394   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10395   PetscValidPointer(scale, 3);
10396   *scale = mesh->scale[unit];
10397   PetscFunctionReturn(0);
10398 }
10399 
10400 #undef __FUNCT__
10401 #define __FUNCT__ "DMPlexSetScale"
10402 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10403 {
10404   DM_Plex *mesh = (DM_Plex*) dm->data;
10405 
10406   PetscFunctionBegin;
10407   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10408   mesh->scale[unit] = scale;
10409   PetscFunctionReturn(0);
10410 }
10411 
10412 
10413 /*******************************************************************************
10414 This should be in a separate Discretization object, but I am not sure how to lay
10415 it out yet, so I am stuffing things here while I experiment.
10416 *******************************************************************************/
10417 #undef __FUNCT__
10418 #define __FUNCT__ "DMPlexSetFEMIntegration"
10419 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10420                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10421                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10422                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10423                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10424                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10425                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10426                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10427                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10428                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10429                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10430                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10431                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10432                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10433                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10434                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10435                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10436 {
10437   DM_Plex *mesh = (DM_Plex*) dm->data;
10438 
10439   PetscFunctionBegin;
10440   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10441   mesh->integrateResidualFEM       = integrateResidualFEM;
10442   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10443   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10444   PetscFunctionReturn(0);
10445 }
10446 
10447 #undef __FUNCT__
10448 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10449 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10450 {
10451   Vec            coordinates;
10452   PetscSection   section, cSection;
10453   PetscInt       dim, vStart, vEnd, v, c, d;
10454   PetscScalar   *values, *cArray;
10455   PetscReal     *coords;
10456   PetscErrorCode ierr;
10457 
10458   PetscFunctionBegin;
10459   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10460   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10461   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10462   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10463   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10464   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10465   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10466   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10467   for (v = vStart; v < vEnd; ++v) {
10468     PetscInt dof, off;
10469 
10470     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10471     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10472     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10473     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
10474     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10475     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10476   }
10477   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10478   /* Temporary, must be replaced by a projection on the finite element basis */
10479   {
10480     PetscInt eStart = 0, eEnd = 0, e, depth;
10481 
10482     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10483     --depth;
10484     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10485     for (e = eStart; e < eEnd; ++e) {
10486       const PetscInt *cone = PETSC_NULL;
10487       PetscInt        coneSize, d;
10488       PetscScalar    *coordsA, *coordsB;
10489 
10490       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10491       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10492       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10493       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10494       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10495       for (d = 0; d < dim; ++d) {
10496         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10497       }
10498       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10499       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10500     }
10501   }
10502 
10503   ierr = PetscFree(coords);CHKERRQ(ierr);
10504   ierr = PetscFree(values);CHKERRQ(ierr);
10505 #if 0
10506   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10507   PetscReal      detJ;
10508 
10509   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10510   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10511   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10512 
10513   for (PetscInt c = cStart; c < cEnd; ++c) {
10514     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10515     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10516     const int                          oSize   = pV.getSize();
10517     int                                v       = 0;
10518 
10519     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10520     for (PetscInt cl = 0; cl < oSize; ++cl) {
10521       const PetscInt fDim;
10522 
10523       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10524       if (pointDim) {
10525         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10526           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10527         }
10528       }
10529     }
10530     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10531     pV.clear();
10532   }
10533   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10534   ierr = PetscFree(values);CHKERRQ(ierr);
10535 #endif
10536   PetscFunctionReturn(0);
10537 }
10538 
10539 #undef __FUNCT__
10540 #define __FUNCT__ "DMPlexProjectFunction"
10541 /*@C
10542   DMPlexProjectFunction - This projects the given function into the function space provided.
10543 
10544   Input Parameters:
10545 + dm      - The DM
10546 . numComp - The number of components (functions)
10547 . funcs   - The coordinate functions to evaluate
10548 - mode    - The insertion mode for values
10549 
10550   Output Parameter:
10551 . X - vector
10552 
10553   Level: developer
10554 
10555   Note:
10556   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10557   We will eventually fix it.
10558 
10559 ,seealso: DMPlexComputeL2Diff()
10560 */
10561 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10562 {
10563   Vec            localX;
10564   PetscErrorCode ierr;
10565 
10566   PetscFunctionBegin;
10567   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10568   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10569   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10570   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10571   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10572   PetscFunctionReturn(0);
10573 }
10574 
10575 #undef __FUNCT__
10576 #define __FUNCT__ "DMPlexComputeL2Diff"
10577 /*@C
10578   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10579 
10580   Input Parameters:
10581 + dm    - The DM
10582 . quad  - The PetscQuadrature object for each field
10583 . funcs - The functions to evaluate for each field component
10584 - X     - The coefficient vector u_h
10585 
10586   Output Parameter:
10587 . diff - The diff ||u - u_h||_2
10588 
10589   Level: developer
10590 
10591 .seealso: DMPlexProjectFunction()
10592 */
10593 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10594 {
10595   const PetscInt debug = 0;
10596   PetscSection   section;
10597   Vec            localX;
10598   PetscReal     *coords, *v0, *J, *invJ, detJ;
10599   PetscReal      localDiff = 0.0;
10600   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10601   PetscErrorCode ierr;
10602 
10603   PetscFunctionBegin;
10604   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10605   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10606   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10607   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10608   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10609   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10610   for (field = 0; field < numFields; ++field) {
10611     numComponents += quad[field].numComponents;
10612   }
10613   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10614   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10615   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10616   for (c = cStart; c < cEnd; ++c) {
10617     const PetscScalar *x;
10618     PetscReal          elemDiff = 0.0;
10619 
10620     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10621     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10622     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10623 
10624     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10625       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10626       const PetscReal *quadPoints    = quad[field].quadPoints;
10627       const PetscReal *quadWeights   = quad[field].quadWeights;
10628       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10629       const PetscInt   numBasisComps = quad[field].numComponents;
10630       const PetscReal *basis         = quad[field].basis;
10631       PetscInt         q, d, e, fc, f;
10632 
10633       if (debug) {
10634         char title[1024];
10635         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10636         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10637       }
10638       for (q = 0; q < numQuadPoints; ++q) {
10639         for (d = 0; d < dim; d++) {
10640           coords[d] = v0[d];
10641           for (e = 0; e < dim; e++) {
10642             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10643           }
10644         }
10645         for (fc = 0; fc < numBasisComps; ++fc) {
10646           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10647           PetscReal       interpolant = 0.0;
10648           for (f = 0; f < numBasisFuncs; ++f) {
10649             const PetscInt fidx = f*numBasisComps+fc;
10650             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10651           }
10652           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10653           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10654         }
10655       }
10656       comp        += numBasisComps;
10657       fieldOffset += numBasisFuncs*numBasisComps;
10658     }
10659     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10660     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10661     localDiff += elemDiff;
10662   }
10663   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10664   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10665   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10666   *diff = PetscSqrtReal(*diff);
10667   PetscFunctionReturn(0);
10668 }
10669 
10670 #undef __FUNCT__
10671 #define __FUNCT__ "DMPlexComputeResidualFEM"
10672 /*@
10673   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10674 
10675   Input Parameters:
10676 + dm - The mesh
10677 . X  - Local input vector
10678 - user - The user context
10679 
10680   Output Parameter:
10681 . F  - Local output vector
10682 
10683   Note:
10684   The second member of the user context must be an FEMContext.
10685 
10686   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10687   like a GPU, or vectorize on a multicore machine.
10688 
10689 .seealso: DMPlexComputeJacobianActionFEM()
10690 */
10691 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10692 {
10693   DM_Plex         *mesh = (DM_Plex*) dm->data;
10694   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10695   PetscQuadrature *quad = fem->quad;
10696   PetscSection     section;
10697   PetscReal       *v0, *J, *invJ, *detJ;
10698   PetscScalar     *elemVec, *u;
10699   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10700   PetscInt         cellDof = 0, numComponents = 0;
10701   PetscErrorCode   ierr;
10702 
10703   PetscFunctionBegin;
10704   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10705   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10706   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10707   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10708   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10709   numCells = cEnd - cStart;
10710   for (field = 0; field < numFields; ++field) {
10711     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10712     numComponents += quad[field].numComponents;
10713   }
10714   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10715   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10716   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);
10717   for (c = cStart; c < cEnd; ++c) {
10718     const PetscScalar *x;
10719     PetscInt           i;
10720 
10721     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10722     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10723     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10724 
10725     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10726     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10727   }
10728   for (field = 0; field < numFields; ++field) {
10729     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10730     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10731     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10732     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10733     /* Conforming batches */
10734     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10735     PetscInt numBlocks  = 1;
10736     PetscInt batchSize  = numBlocks * blockSize;
10737     PetscInt numBatches = numBatchesTmp;
10738     PetscInt numChunks  = numCells / (numBatches*batchSize);
10739     /* Remainder */
10740     PetscInt numRemainder = numCells % (numBatches * batchSize);
10741     PetscInt offset       = numCells - numRemainder;
10742 
10743     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10744     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10745                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10746   }
10747   for (c = cStart; c < cEnd; ++c) {
10748     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10749     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10750   }
10751   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10752   if (mesh->printFEM) {
10753     PetscMPIInt rank, numProcs;
10754     PetscInt    p;
10755 
10756     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10757     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10758     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10759     for (p = 0; p < numProcs; ++p) {
10760       if (p == rank) {
10761         Vec f;
10762 
10763         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10764         ierr = VecCopy(F, f);CHKERRQ(ierr);
10765         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10766         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10767         ierr = VecDestroy(&f);CHKERRQ(ierr);
10768         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10769       }
10770       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10771     }
10772   }
10773   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10774   PetscFunctionReturn(0);
10775 }
10776 
10777 #undef __FUNCT__
10778 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10779 /*@C
10780   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10781 
10782   Input Parameters:
10783 + dm - The mesh
10784 . J  - The Jacobian shell matrix
10785 . X  - Local input vector
10786 - user - The user context
10787 
10788   Output Parameter:
10789 . F  - Local output vector
10790 
10791   Note:
10792   The second member of the user context must be an FEMContext.
10793 
10794   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10795   like a GPU, or vectorize on a multicore machine.
10796 
10797 .seealso: DMPlexComputeResidualFEM()
10798 */
10799 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10800 {
10801   DM_Plex         *mesh = (DM_Plex*) dm->data;
10802   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10803   PetscQuadrature *quad = fem->quad;
10804   PetscSection     section;
10805   JacActionCtx    *jctx;
10806   PetscReal       *v0, *J, *invJ, *detJ;
10807   PetscScalar     *elemVec, *u, *a;
10808   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10809   PetscInt         cellDof = 0;
10810   PetscErrorCode   ierr;
10811 
10812   PetscFunctionBegin;
10813   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10814   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10815   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10816   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10817   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10818   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10819   numCells = cEnd - cStart;
10820   for (field = 0; field < numFields; ++field) {
10821     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10822   }
10823   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10824   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);
10825   for (c = cStart; c < cEnd; ++c) {
10826     const PetscScalar *x;
10827     PetscInt           i;
10828 
10829     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10830     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10831     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10832     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10833     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10834     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10835     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
10836     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10837   }
10838   for (field = 0; field < numFields; ++field) {
10839     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10840     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10841     /* Conforming batches */
10842     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10843     PetscInt numBlocks  = 1;
10844     PetscInt batchSize  = numBlocks * blockSize;
10845     PetscInt numBatches = numBatchesTmp;
10846     PetscInt numChunks  = numCells / (numBatches*batchSize);
10847     /* Remainder */
10848     PetscInt numRemainder = numCells % (numBatches * batchSize);
10849     PetscInt offset       = numCells - numRemainder;
10850 
10851     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);
10852     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],
10853                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10854   }
10855   for (c = cStart; c < cEnd; ++c) {
10856     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10857     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10858   }
10859   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10860   if (mesh->printFEM) {
10861     PetscMPIInt rank, numProcs;
10862     PetscInt    p;
10863 
10864     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10865     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10866     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10867     for (p = 0; p < numProcs; ++p) {
10868       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10869       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10870     }
10871   }
10872   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10873   PetscFunctionReturn(0);
10874 }
10875 
10876 #undef __FUNCT__
10877 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10878 /*@
10879   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10880 
10881   Input Parameters:
10882 + dm - The mesh
10883 . X  - Local input vector
10884 - user - The user context
10885 
10886   Output Parameter:
10887 . Jac  - Jacobian matrix
10888 
10889   Note:
10890   The second member of the user context must be an FEMContext.
10891 
10892   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10893   like a GPU, or vectorize on a multicore machine.
10894 
10895 .seealso: FormFunctionLocal()
10896 */
10897 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10898 {
10899   DM_Plex         *mesh = (DM_Plex*) dm->data;
10900   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10901   PetscQuadrature *quad = fem->quad;
10902   PetscSection     section;
10903   PetscReal       *v0, *J, *invJ, *detJ;
10904   PetscScalar     *elemMat, *u;
10905   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10906   PetscInt         cellDof = 0, numComponents = 0;
10907   PetscBool        isShell;
10908   PetscErrorCode   ierr;
10909 
10910   PetscFunctionBegin;
10911   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10912   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10913   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10914   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10915   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10916   numCells = cEnd - cStart;
10917   for (field = 0; field < numFields; ++field) {
10918     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10919     numComponents += quad[field].numComponents;
10920   }
10921   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10922   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10923   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);
10924   for (c = cStart; c < cEnd; ++c) {
10925     const PetscScalar *x;
10926     PetscInt           i;
10927 
10928     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10929     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10930     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10931 
10932     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10933     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10934   }
10935   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10936   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10937     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10938     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10939     PetscInt       fieldJ;
10940 
10941     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10942       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10943       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10944       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10945       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10946       /* Conforming batches */
10947       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10948       PetscInt numBlocks  = 1;
10949       PetscInt batchSize  = numBlocks * blockSize;
10950       PetscInt numBatches = numBatchesTmp;
10951       PetscInt numChunks  = numCells / (numBatches*batchSize);
10952       /* Remainder */
10953       PetscInt numRemainder = numCells % (numBatches * batchSize);
10954       PetscInt offset       = numCells - numRemainder;
10955 
10956       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10957       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10958                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10959     }
10960   }
10961   for (c = cStart; c < cEnd; ++c) {
10962     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10963     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10964   }
10965   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10966 
10967   /* Assemble matrix, using the 2-step process:
10968        MatAssemblyBegin(), MatAssemblyEnd(). */
10969   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10970   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10971 
10972   if (mesh->printFEM) {
10973     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10974     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10975     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10976   }
10977   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10978   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10979   if (isShell) {
10980     JacActionCtx *jctx;
10981 
10982     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10983     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10984   }
10985   *str = SAME_NONZERO_PATTERN;
10986   PetscFunctionReturn(0);
10987 }
10988 
10989 
10990 #undef __FUNCT__
10991 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10992 /*@C
10993   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10994   the local section and an SF describing the section point overlap.
10995 
10996   Input Parameters:
10997   + s - The PetscSection for the local field layout
10998   . sf - The SF describing parallel layout of the section points
10999   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
11000   . label - The label specifying the points
11001   - labelValue - The label stratum specifying the points
11002 
11003   Output Parameter:
11004   . gsection - The PetscSection for the global field layout
11005 
11006   Note: This gives negative sizes and offsets to points not owned by this process
11007 
11008   Level: developer
11009 
11010 .seealso: PetscSectionCreate()
11011 @*/
11012 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
11013 {
11014   PetscInt      *neg;
11015   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
11016   PetscErrorCode ierr;
11017 
11018   PetscFunctionBegin;
11019   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
11020   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
11021   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
11022   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
11023   /* Mark ghost points with negative dof */
11024   for (p = pStart; p < pEnd; ++p) {
11025     PetscInt value;
11026 
11027     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11028     if (value != labelValue) continue;
11029     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11030     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11031     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11032     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11033     neg[p-pStart] = -(dof+1);
11034   }
11035   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11036   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11037   if (nroots >= 0) {
11038     if (nroots > pEnd - pStart) {
11039       PetscInt *tmpDof;
11040       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11041       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11042       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11043       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11044       for (p = pStart; p < pEnd; ++p) {
11045         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
11046       }
11047       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11048     } else {
11049       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11050       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11051     }
11052   }
11053   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11054   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11055     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11056 
11057     (*gsection)->atlasOff[p] = off;
11058 
11059     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11060   }
11061   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11062   globalOff -= off;
11063   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11064     (*gsection)->atlasOff[p] += globalOff;
11065 
11066     neg[p] = -((*gsection)->atlasOff[p]+1);
11067   }
11068   /* Put in negative offsets for ghost points */
11069   if (nroots >= 0) {
11070     if (nroots > pEnd - pStart) {
11071       PetscInt *tmpOff;
11072       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11073       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11074       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11075       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11076       for (p = pStart; p < pEnd; ++p) {
11077         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
11078       }
11079       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11080     } else {
11081       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11082       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11083     }
11084   }
11085   ierr = PetscFree(neg);CHKERRQ(ierr);
11086   PetscFunctionReturn(0);
11087 }
11088