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