xref: /petsc/src/dm/impls/plex/plex.c (revision 009bbdc485cd9ad46be9940d3549e2dde9cdc322)
1 #include <petsc-private/pleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 
4 /* Logging support */
5 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
6 
7 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
8 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "VecView_Plex_Local"
12 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
13 {
14   DM             dm;
15   PetscBool      isvtk;
16   PetscErrorCode ierr;
17 
18   PetscFunctionBegin;
19   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
20   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
21   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
22   if (isvtk) {
23     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
24     PetscSection            section;
25     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
26 
27     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
28     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
29     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, PETSC_NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, PETSC_NULL);CHKERRQ(ierr);
32     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
33     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
34     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
35     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
36     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
37     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
38       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
39     } else if (cdof && vdof) {
40       SETERRQ(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
41     } else if (cdof) {
42       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
43        * vector or just happens to have the same number of dofs as the dimension. */
44       if (cdof == dim) {
45         ft = PETSC_VTK_CELL_VECTOR_FIELD;
46       } else {
47         ft = PETSC_VTK_CELL_FIELD;
48       }
49     } else if (vdof) {
50       if (vdof == dim) {
51         ft = PETSC_VTK_POINT_VECTOR_FIELD;
52       } else {
53         ft = PETSC_VTK_POINT_FIELD;
54       }
55     } else SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
56 
57     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
58     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
59     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
60   } else {
61     PetscBool isseq;
62 
63     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
64     if (isseq) {
65       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
66     } else {
67       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "VecView_Plex"
75 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
76 {
77   DM             dm;
78   PetscBool      isvtk;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
83   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
84   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
85   if (isvtk) {
86     Vec         locv;
87     const char *name;
88 
89     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
90     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
91     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
92     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
95     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
96   } else {
97     PetscBool isseq;
98 
99     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
100     if (isseq) {
101       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
102     } else {
103       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
104     }
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "DMPlexView_Ascii"
111 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
112 {
113   DM_Plex       *mesh = (DM_Plex *) dm->data;
114   DM                cdm;
115   DMLabel           markers;
116   PetscSection      coordSection;
117   Vec               coordinates;
118   PetscViewerFormat format;
119   PetscErrorCode    ierr;
120 
121   PetscFunctionBegin;
122   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
123   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
124   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
125   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
126   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
127     const char *name;
128     PetscInt    maxConeSize, maxSupportSize;
129     PetscInt    pStart, pEnd, p;
130     PetscMPIInt rank, size;
131 
132     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
133     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
134     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
135     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
136     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
137     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
138     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
142     for (p = pStart; p < pEnd; ++p) {
143       PetscInt dof, off, s;
144 
145       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
146       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
147       for (s = off; s < off+dof; ++s) {
148         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
149       }
150     }
151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
152     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
153     for (p = pStart; p < pEnd; ++p) {
154       PetscInt dof, off, c;
155 
156       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
157       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
158       for (c = off; c < off+dof; ++c) {
159         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
160       }
161     }
162     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
163     ierr = PetscSectionGetChart(coordSection, &pStart, PETSC_NULL);CHKERRQ(ierr);
164     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
165     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
166     if (markers) {
167       ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
168     }
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors = 3;
180     PetscReal    scale = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = PETSC_NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm = ((PetscObject) dm)->comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscMPIInt size;
282 
283     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
284     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
285     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
286     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
287     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
288     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
289     if (depth == 1) {
290       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
291       pEnd = pEnd - pStart;
292       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
293       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
294       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
295       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
296       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
297       pEnd = pEnd - pStart;
298       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
299       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
300       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
301       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
302     } else {
303       for (d = 0; d <= dim; d++) {
304         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
305         pEnd = pEnd - pStart;
306         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
307         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
308         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
309         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
310       }
311     }
312     ierr = PetscFree(sizes);CHKERRQ(ierr);
313   }
314   PetscFunctionReturn(0);
315 }
316 
317 #undef __FUNCT__
318 #define __FUNCT__ "DMView_Plex"
319 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
320 {
321   PetscBool      iascii, isbinary;
322   PetscErrorCode ierr;
323 
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
326   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
327   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
329   if (iascii) {
330     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
331 #if 0
332   } else if (isbinary) {
333     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
334 #endif
335   }
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "DMDestroy_Plex"
341 PetscErrorCode DMDestroy_Plex(DM dm)
342 {
343   DM_Plex    *mesh = (DM_Plex *) dm->data;
344   DMLabel        next = mesh->labels;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   if (--mesh->refct > 0) {PetscFunctionReturn(0);}
349   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
350   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
352   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
353   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
355   while (next) {
356     DMLabel tmp = next->next;
357 
358     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
359     next = tmp;
360   }
361   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
362   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
364   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
365   ierr = PetscFree(mesh);CHKERRQ(ierr);
366   PetscFunctionReturn(0);
367 }
368 
369 #undef __FUNCT__
370 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
371 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
372 {
373   const PetscInt *support = PETSC_NULL;
374   PetscInt        numAdj  = 0, maxAdjSize = *adjSize, supportSize, s;
375   PetscErrorCode  ierr;
376 
377   PetscFunctionBegin;
378   if (useClosure) {
379     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
380     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
381     for (s = 0; s < supportSize; ++s) {
382       const PetscInt *cone = PETSC_NULL;
383       PetscInt        coneSize, c, q;
384 
385       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
386       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
387       for (c = 0; c < coneSize; ++c) {
388         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
389           if (cone[c] == adj[q]) break;
390         }
391         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
392       }
393     }
394   } else {
395     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
396     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
397     for (s = 0; s < supportSize; ++s) {
398       const PetscInt *cone = PETSC_NULL;
399       PetscInt        coneSize, c, q;
400 
401       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
402       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
403       for (c = 0; c < coneSize; ++c) {
404         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
405           if (cone[c] == adj[q]) break;
406         }
407         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
408       }
409     }
410   }
411   *adjSize = numAdj;
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "DMPlexGetAdjacency_Private"
417 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
418 {
419   const PetscInt *star   = tmpClosure;
420   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
421   PetscErrorCode  ierr;
422 
423   PetscFunctionBegin;
424   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt **) &star);CHKERRQ(ierr);
425   for (s = 2; s < starSize*2; s += 2) {
426     const PetscInt *closure = PETSC_NULL;
427     PetscInt        closureSize, c, q;
428 
429     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
430     for (c = 0; c < closureSize*2; c += 2) {
431       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
432         if (closure[c] == adj[q]) break;
433       }
434       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
435     }
436     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
437   }
438   *adjSize = numAdj;
439   PetscFunctionReturn(0);
440 }
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
444 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
445 {
446   DM_Plex *mesh = (DM_Plex *) dm->data;
447 
448   PetscFunctionBegin;
449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
450   mesh->preallocCenterDim = preallocCenterDim;
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "DMPlexPreallocateOperator"
456 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
457 {
458   DM_Plex        *mesh = (DM_Plex *) dm->data;
459   MPI_Comm           comm = ((PetscObject) dm)->comm;
460   PetscSF            sf, sfDof, sfAdj;
461   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
462   PetscInt           nleaves, l, p;
463   const PetscInt    *leaves;
464   const PetscSFNode *remotes;
465   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
466   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
467   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
468   PetscLayout        rLayout;
469   PetscInt           locRows, rStart, rEnd, r;
470   PetscMPIInt        size;
471   PetscBool          useClosure, debug = PETSC_FALSE;
472   PetscErrorCode     ierr;
473 
474   PetscFunctionBegin;
475   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
476   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
477   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
478   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
479   /* Create dof SF based on point SF */
480   if (debug) {
481     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
487   }
488   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
489   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
490   if (debug) {
491     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
492     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
493   }
494   /* Create section for dof adjacency (dof ==> # adj dof) */
495   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
496   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
497   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
498   if (mesh->preallocCenterDim == dim) {
499     useClosure = PETSC_FALSE;
500   } else if (mesh->preallocCenterDim == 0) {
501     useClosure = PETSC_TRUE;
502   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
503 
504   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
505   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
510   /*   Fill in the ghost dofs on the interface */
511   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
512   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
513   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
514   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
515   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
516   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
517 
518   /*
519    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
520     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
521        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
522     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
523        Create sfAdj connecting rootSectionAdj and leafSectionAdj
524     3. Visit unowned points on interface, write adjacencies to adj
525        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
526     4. Visit owned points on interface, write adjacencies to rootAdj
527        Remove redundancy in rootAdj
528    ** The last two traversals use transitive closure
529     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
530        Allocate memory addressed by sectionAdj (cols)
531     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
532    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
533   */
534 
535   for (l = 0; l < nleaves; ++l) {
536     PetscInt dof, off, d, q;
537     PetscInt p = leaves[l], numAdj = maxAdjSize;
538 
539     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
540     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
541     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
542     for (q = 0; q < numAdj; ++q) {
543       PetscInt ndof, ncdof;
544 
545       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
546       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
547       for (d = off; d < off+dof; ++d) {
548         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
549       }
550     }
551   }
552   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
553   if (debug) {
554     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
555     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
556   }
557   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
558   if (size > 1) {
559     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
560     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561   }
562   if (debug) {
563     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
564     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
565   }
566   /* Add in local adjacency sizes for owned dofs on interface (roots) */
567   for (p = pStart; p < pEnd; ++p) {
568     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
569 
570     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
571     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
572     if (!dof) continue;
573     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
574     if (adof <= 0) continue;
575     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
576     for (q = 0; q < numAdj; ++q) {
577       PetscInt ndof, ncdof;
578 
579       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
580       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
581       for (d = off; d < off+dof; ++d) {
582         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
583       }
584     }
585   }
586   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
587   if (debug) {
588     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
589     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
590   }
591   /* Create adj SF based on dof SF */
592   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
593   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
596     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
597   }
598   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
599   /* Create leaf adjacency */
600   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
601   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
602   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
603   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
604   for (l = 0; l < nleaves; ++l) {
605     PetscInt dof, off, d, q;
606     PetscInt p = leaves[l], numAdj = maxAdjSize;
607 
608     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
609     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
610     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
611     for (d = off; d < off+dof; ++d) {
612       PetscInt aoff, i = 0;
613 
614       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
615       for (q = 0; q < numAdj; ++q) {
616         PetscInt  ndof, ncdof, ngoff, nd;
617 
618         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
619         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
620         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
621         for (nd = 0; nd < ndof-ncdof; ++nd) {
622           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
623           ++i;
624         }
625       }
626     }
627   }
628   /* Debugging */
629   if (debug) {
630     IS tmp;
631     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
632     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
633     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
634   }
635   /* Gather adjacenct indices to root */
636   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
637   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
638   for (r = 0; r < adjSize; ++r) {
639     rootAdj[r] = -1;
640   }
641   if (size > 1) {
642     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
643     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
644   }
645   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
646   ierr = PetscFree(adj);CHKERRQ(ierr);
647   /* Debugging */
648   if (debug) {
649     IS tmp;
650     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
651     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
652     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
653   }
654   /* Add in local adjacency indices for owned dofs on interface (roots) */
655   for (p = pStart; p < pEnd; ++p) {
656     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
657 
658     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
659     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
660     if (!dof) continue;
661     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
662     if (adof <= 0) continue;
663     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
664     for (d = off; d < off+dof; ++d) {
665       PetscInt adof, aoff, i;
666 
667       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
668       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
669       i    = adof-1;
670       for (q = 0; q < numAdj; ++q) {
671         PetscInt ndof, ncdof, ngoff, nd;
672 
673         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
674         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
675         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
676         for (nd = 0; nd < ndof-ncdof; ++nd) {
677           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
678           --i;
679         }
680       }
681     }
682   }
683   /* Debugging */
684   if (debug) {
685     IS tmp;
686     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
687     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
688     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
689   }
690   /* Compress indices */
691   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
692   for (p = pStart; p < pEnd; ++p) {
693     PetscInt dof, cdof, off, d;
694     PetscInt adof, aoff;
695 
696     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
697     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
698     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
699     if (!dof) continue;
700     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
701     if (adof <= 0) continue;
702     for (d = off; d < off+dof-cdof; ++d) {
703       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
704       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
705       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
706       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
707     }
708   }
709   /* Debugging */
710   if (debug) {
711     IS tmp;
712     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
713     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
714     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
715     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
716     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
717   }
718   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
719   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
720   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
721   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
722   for (p = pStart; p < pEnd; ++p) {
723     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
724     PetscBool found  = PETSC_TRUE;
725 
726     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
727     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
728     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
729     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
730     for (d = 0; d < dof-cdof; ++d) {
731       PetscInt ldof, rdof;
732 
733       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
734       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
735       if (ldof > 0) {
736         /* We do not own this point */
737       } else if (rdof > 0) {
738         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
739       } else {
740         found = PETSC_FALSE;
741       }
742     }
743     if (found) continue;
744     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
745     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
746     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
747     for (q = 0; q < numAdj; ++q) {
748       PetscInt ndof, ncdof, noff;
749 
750       /* Adjacent points may not be in the section chart */
751       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
752       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
753       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
754       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
755       for (d = goff; d < goff+dof-cdof; ++d) {
756         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
757       }
758     }
759   }
760   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
761   if (debug) {
762     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
763     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
764   }
765   /* Get adjacent indices */
766   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
767   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
768   for (p = pStart; p < pEnd; ++p) {
769     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
770     PetscBool found  = PETSC_TRUE;
771 
772     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
773     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
774     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
775     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
776     for (d = 0; d < dof-cdof; ++d) {
777       PetscInt ldof, rdof;
778 
779       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
780       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
781       if (ldof > 0) {
782         /* We do not own this point */
783       } else if (rdof > 0) {
784         PetscInt aoff, roff;
785 
786         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
787         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
788         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
789       } else {
790         found = PETSC_FALSE;
791       }
792     }
793     if (found) continue;
794     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
795     for (d = goff; d < goff+dof-cdof; ++d) {
796       PetscInt adof, aoff, i = 0;
797 
798       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
799       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
800       for (q = 0; q < numAdj; ++q) {
801         PetscInt        ndof, ncdof, ngoff, nd;
802         const PetscInt *ncind;
803 
804         /* Adjacent points may not be in the section chart */
805         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
806         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
807         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
808         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
809         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
810         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
811           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
812         }
813       }
814       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
815     }
816   }
817   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
818   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
819   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
820   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
821   /* Debugging */
822   if (debug) {
823     IS tmp;
824     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
825     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
826     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
827   }
828   /* Create allocation vectors from adjacency graph */
829   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
830   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
831   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
832   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
833   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
834   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
835   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
836   /* Only loop over blocks of rows */
837   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
838   for (r = rStart/bs; r < rEnd/bs; ++r) {
839     const PetscInt row = r*bs;
840     PetscInt numCols, cStart, c;
841 
842     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
843     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
844     for (c = cStart; c < cStart+numCols; ++c) {
845       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
846         ++dnz[r-rStart];
847         if (cols[c] >= row) {++dnzu[r-rStart];}
848       } else {
849         ++onz[r-rStart];
850         if (cols[c] >= row) {++onzu[r-rStart];}
851       }
852     }
853   }
854   if (bs > 1) {
855     for (r = 0; r < locRows/bs; ++r) {
856       dnz[r]  /= bs;
857       onz[r]  /= bs;
858       dnzu[r] /= bs;
859       onzu[r] /= bs;
860     }
861   }
862   /* Set matrix pattern */
863   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
864   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
865   /* Fill matrix with zeros */
866   if (fillMatrix) {
867     PetscScalar *values;
868     PetscInt     maxRowLen = 0;
869 
870     for (r = rStart; r < rEnd; ++r) {
871       PetscInt len;
872 
873       ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
874       maxRowLen = PetscMax(maxRowLen, len);
875     }
876     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
877     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
878     for (r = rStart; r < rEnd; ++r) {
879       PetscInt numCols, cStart;
880 
881       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
882       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
883       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
884     }
885     ierr = PetscFree(values);CHKERRQ(ierr);
886     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
887     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
888   }
889   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
890   ierr = PetscFree(cols);CHKERRQ(ierr);
891   PetscFunctionReturn(0);
892 }
893 
894 #if 0
895 #undef __FUNCT__
896 #define __FUNCT__ "DMPlexPreallocateOperator_2"
897 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
898 {
899   PetscErrorCode ierr;
900   PetscInt c,cStart,cEnd,pStart,pEnd;
901   PetscInt *tmpClosure,*tmpAdj,*visits;
902 
903   PetscFunctionBegin;
904   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
905   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
906   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
907   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
908   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
911   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
912   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
914   for (c=cStart; c<cEnd; c++) {
915     PetscInt *support = tmpClosure;
916     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
917     for (p=0; p<supportSize; p++) {
918       lvisits[support[p]]++;
919     }
920   }
921   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
923   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
925 
926   ierr = PetscSFGetRanks();CHKERRQ(ierr);
927 
928 
929   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
930   for (c=cStart; c<cEnd; c++) {
931     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
932     /*
933      Depth-first walk of transitive closure.
934      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
935      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
936      */
937   }
938 
939   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
940   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
941   PetscFunctionReturn(0);
942 }
943 #endif
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "DMCreateMatrix_Plex"
947 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
948 {
949   PetscSection   section, sectionGlobal;
950   PetscInt       bs = -1;
951   PetscInt       localSize;
952   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
953   PetscErrorCode ierr;
954 
955   PetscFunctionBegin;
956 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
957   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
958 #endif
959   if (!mtype) mtype = MATAIJ;
960   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
961   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
962   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
963   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
964   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
965   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
966   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
967   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
975   /* Check for symmetric storage */
976   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
977   if (isSymmetric) {
978     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
979   }
980   if (!isShell) {
981     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
982     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal;
983 
984     if (bs < 0) {
985       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
986         PetscInt pStart, pEnd, p, dof;
987 
988         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
989         for (p = pStart; p < pEnd; ++p) {
990           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
991           if (dof) {
992             bs = dof;
993             break;
994           }
995         }
996       } else {
997         bs = 1;
998       }
999       /* Must have same blocksize on all procs (some might have no points) */
1000       bsLocal = bs;
1001       ierr = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1002     }
1003     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1004     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1005     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1006     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1007     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1008     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1009     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1010   }
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 #undef __FUNCT__
1015 #define __FUNCT__ "DMPlexGetDimension"
1016 /*@
1017   DMPlexGetDimension - Return the topological mesh dimension
1018 
1019   Not collective
1020 
1021   Input Parameter:
1022 . mesh - The DMPlex
1023 
1024   Output Parameter:
1025 . dim - The topological mesh dimension
1026 
1027   Level: beginner
1028 
1029 .seealso: DMPlexCreate()
1030 @*/
1031 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1032 {
1033   DM_Plex *mesh = (DM_Plex *) dm->data;
1034 
1035   PetscFunctionBegin;
1036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1037   PetscValidPointer(dim, 2);
1038   *dim = mesh->dim;
1039   PetscFunctionReturn(0);
1040 }
1041 
1042 #undef __FUNCT__
1043 #define __FUNCT__ "DMPlexSetDimension"
1044 /*@
1045   DMPlexSetDimension - Set the topological mesh dimension
1046 
1047   Collective on mesh
1048 
1049   Input Parameters:
1050 + mesh - The DMPlex
1051 - dim - The topological mesh dimension
1052 
1053   Level: beginner
1054 
1055 .seealso: DMPlexCreate()
1056 @*/
1057 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1058 {
1059   DM_Plex *mesh = (DM_Plex *) dm->data;
1060 
1061   PetscFunctionBegin;
1062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1063   PetscValidLogicalCollectiveInt(dm, dim, 2);
1064   mesh->dim = dim;
1065   mesh->preallocCenterDim = dim;
1066   PetscFunctionReturn(0);
1067 }
1068 
1069 #undef __FUNCT__
1070 #define __FUNCT__ "DMPlexGetChart"
1071 /*@
1072   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1073 
1074   Not collective
1075 
1076   Input Parameter:
1077 . mesh - The DMPlex
1078 
1079   Output Parameters:
1080 + pStart - The first mesh point
1081 - pEnd   - The upper bound for mesh points
1082 
1083   Level: beginner
1084 
1085 .seealso: DMPlexCreate(), DMPlexSetChart()
1086 @*/
1087 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1088 {
1089   DM_Plex    *mesh = (DM_Plex *) dm->data;
1090   PetscErrorCode ierr;
1091 
1092   PetscFunctionBegin;
1093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1094   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1095   PetscFunctionReturn(0);
1096 }
1097 
1098 #undef __FUNCT__
1099 #define __FUNCT__ "DMPlexSetChart"
1100 /*@
1101   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1102 
1103   Not collective
1104 
1105   Input Parameters:
1106 + mesh - The DMPlex
1107 . pStart - The first mesh point
1108 - pEnd   - The upper bound for mesh points
1109 
1110   Output Parameters:
1111 
1112   Level: beginner
1113 
1114 .seealso: DMPlexCreate(), DMPlexGetChart()
1115 @*/
1116 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1117 {
1118   DM_Plex    *mesh = (DM_Plex *) dm->data;
1119   PetscErrorCode ierr;
1120 
1121   PetscFunctionBegin;
1122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1123   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1124   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 #undef __FUNCT__
1129 #define __FUNCT__ "DMPlexGetConeSize"
1130 /*@
1131   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1132 
1133   Not collective
1134 
1135   Input Parameters:
1136 + mesh - The DMPlex
1137 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1138 
1139   Output Parameter:
1140 . size - The cone size for point p
1141 
1142   Level: beginner
1143 
1144 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1145 @*/
1146 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1147 {
1148   DM_Plex    *mesh = (DM_Plex *) dm->data;
1149   PetscErrorCode ierr;
1150 
1151   PetscFunctionBegin;
1152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1153   PetscValidPointer(size, 3);
1154   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1155   PetscFunctionReturn(0);
1156 }
1157 
1158 #undef __FUNCT__
1159 #define __FUNCT__ "DMPlexSetConeSize"
1160 /*@
1161   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1162 
1163   Not collective
1164 
1165   Input Parameters:
1166 + mesh - The DMPlex
1167 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1168 - size - The cone size for point p
1169 
1170   Output Parameter:
1171 
1172   Note:
1173   This should be called after DMPlexSetChart().
1174 
1175   Level: beginner
1176 
1177 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1178 @*/
1179 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1180 {
1181   DM_Plex    *mesh = (DM_Plex *) dm->data;
1182   PetscErrorCode ierr;
1183 
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1186   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1187   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1188   PetscFunctionReturn(0);
1189 }
1190 
1191 #undef __FUNCT__
1192 #define __FUNCT__ "DMPlexGetCone"
1193 /*@C
1194   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1195 
1196   Not collective
1197 
1198   Input Parameters:
1199 + mesh - The DMPlex
1200 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1201 
1202   Output Parameter:
1203 . cone - An array of points which are on the in-edges for point p
1204 
1205   Level: beginner
1206 
1207   Note:
1208   This routine is not available in Fortran.
1209 
1210 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1211 @*/
1212 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1213 {
1214   DM_Plex    *mesh = (DM_Plex *) dm->data;
1215   PetscInt       off;
1216   PetscErrorCode ierr;
1217 
1218   PetscFunctionBegin;
1219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1220   PetscValidPointer(cone, 3);
1221   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1222   *cone = &mesh->cones[off];
1223   PetscFunctionReturn(0);
1224 }
1225 
1226 #undef __FUNCT__
1227 #define __FUNCT__ "DMPlexSetCone"
1228 /*@
1229   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1230 
1231   Not collective
1232 
1233   Input Parameters:
1234 + mesh - The DMPlex
1235 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1236 - cone - An array of points which are on the in-edges for point p
1237 
1238   Output Parameter:
1239 
1240   Note:
1241   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1242 
1243   Level: beginner
1244 
1245 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1246 @*/
1247 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1248 {
1249   DM_Plex    *mesh = (DM_Plex *) dm->data;
1250   PetscInt       pStart, pEnd;
1251   PetscInt       dof, off, c;
1252   PetscErrorCode ierr;
1253 
1254   PetscFunctionBegin;
1255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1256   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1257   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1258   if (dof) PetscValidPointer(cone, 3);
1259   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1260   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1261   for (c = 0; c < dof; ++c) {
1262     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1263     mesh->cones[off+c] = cone[c];
1264   }
1265   PetscFunctionReturn(0);
1266 }
1267 
1268 #undef __FUNCT__
1269 #define __FUNCT__ "DMPlexGetConeOrientation"
1270 /*@C
1271   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1272 
1273   Not collective
1274 
1275   Input Parameters:
1276 + mesh - The DMPlex
1277 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1278 
1279   Output Parameter:
1280 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1281                     integer giving the prescription for cone traversal. If it is negative, the cone is
1282                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1283                     the index of the cone point on which to start.
1284 
1285   Level: beginner
1286 
1287   Note:
1288   This routine is not available in Fortran.
1289 
1290 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1291 @*/
1292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1293 {
1294   DM_Plex    *mesh = (DM_Plex *) dm->data;
1295   PetscInt       off;
1296   PetscErrorCode ierr;
1297 
1298   PetscFunctionBegin;
1299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1300 #if defined(PETSC_USE_DEBUG)
1301   {
1302     PetscInt dof;
1303     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1304     if (dof) PetscValidPointer(coneOrientation, 3);
1305   }
1306 #endif
1307   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1308   *coneOrientation = &mesh->coneOrientations[off];
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 #undef __FUNCT__
1313 #define __FUNCT__ "DMPlexSetConeOrientation"
1314 /*@
1315   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1316 
1317   Not collective
1318 
1319   Input Parameters:
1320 + mesh - The DMPlex
1321 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1322 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1323                     integer giving the prescription for cone traversal. If it is negative, the cone is
1324                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1325                     the index of the cone point on which to start.
1326 
1327   Output Parameter:
1328 
1329   Note:
1330   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1331 
1332   Level: beginner
1333 
1334 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1335 @*/
1336 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1337 {
1338   DM_Plex    *mesh = (DM_Plex *) dm->data;
1339   PetscInt       pStart, pEnd;
1340   PetscInt       dof, off, c;
1341   PetscErrorCode ierr;
1342 
1343   PetscFunctionBegin;
1344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1345   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1346   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1347   if (dof) PetscValidPointer(coneOrientation, 3);
1348   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1349   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1350   for (c = 0; c < dof; ++c) {
1351     PetscInt cdof, o = coneOrientation[c];
1352 
1353     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1354     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1355     mesh->coneOrientations[off+c] = o;
1356   }
1357   PetscFunctionReturn(0);
1358 }
1359 
1360 #undef __FUNCT__
1361 #define __FUNCT__ "DMPlexInsertCone"
1362 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1363 {
1364   DM_Plex    *mesh = (DM_Plex *) dm->data;
1365   PetscInt       pStart, pEnd;
1366   PetscInt       dof, off;
1367   PetscErrorCode ierr;
1368 
1369   PetscFunctionBegin;
1370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1371   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1372   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1373   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1374   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1375   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1376   if (conePos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1377   mesh->cones[off+conePos] = conePoint;
1378   PetscFunctionReturn(0);
1379 }
1380 
1381 #undef __FUNCT__
1382 #define __FUNCT__ "DMPlexGetSupportSize"
1383 /*@
1384   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1385 
1386   Not collective
1387 
1388   Input Parameters:
1389 + mesh - The DMPlex
1390 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1391 
1392   Output Parameter:
1393 . size - The support size for point p
1394 
1395   Level: beginner
1396 
1397 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1398 @*/
1399 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1400 {
1401   DM_Plex    *mesh = (DM_Plex *) dm->data;
1402   PetscErrorCode ierr;
1403 
1404   PetscFunctionBegin;
1405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1406   PetscValidPointer(size, 3);
1407   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1408   PetscFunctionReturn(0);
1409 }
1410 
1411 #undef __FUNCT__
1412 #define __FUNCT__ "DMPlexSetSupportSize"
1413 /*@
1414   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1415 
1416   Not collective
1417 
1418   Input Parameters:
1419 + mesh - The DMPlex
1420 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1421 - size - The support size for point p
1422 
1423   Output Parameter:
1424 
1425   Note:
1426   This should be called after DMPlexSetChart().
1427 
1428   Level: beginner
1429 
1430 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1431 @*/
1432 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1433 {
1434   DM_Plex    *mesh = (DM_Plex *) dm->data;
1435   PetscErrorCode ierr;
1436 
1437   PetscFunctionBegin;
1438   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1439   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1440   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1441   PetscFunctionReturn(0);
1442 }
1443 
1444 #undef __FUNCT__
1445 #define __FUNCT__ "DMPlexGetSupport"
1446 /*@C
1447   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1448 
1449   Not collective
1450 
1451   Input Parameters:
1452 + mesh - The DMPlex
1453 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1454 
1455   Output Parameter:
1456 . support - An array of points which are on the out-edges for point p
1457 
1458   Level: beginner
1459 
1460 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1461 @*/
1462 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1463 {
1464   DM_Plex    *mesh = (DM_Plex *) dm->data;
1465   PetscInt       off;
1466   PetscErrorCode ierr;
1467 
1468   PetscFunctionBegin;
1469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1470   PetscValidPointer(support, 3);
1471   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1472   *support = &mesh->supports[off];
1473   PetscFunctionReturn(0);
1474 }
1475 
1476 #undef __FUNCT__
1477 #define __FUNCT__ "DMPlexSetSupport"
1478 /*@
1479   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1480 
1481   Not collective
1482 
1483   Input Parameters:
1484 + mesh - The DMPlex
1485 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1486 - support - An array of points which are on the in-edges for point p
1487 
1488   Output Parameter:
1489 
1490   Note:
1491   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1492 
1493   Level: beginner
1494 
1495 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1496 @*/
1497 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1498 {
1499   DM_Plex    *mesh = (DM_Plex *) dm->data;
1500   PetscInt       pStart, pEnd;
1501   PetscInt       dof, off, c;
1502   PetscErrorCode ierr;
1503 
1504   PetscFunctionBegin;
1505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1506   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1507   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1508   if (dof) PetscValidPointer(support, 3);
1509   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1510   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1511   for (c = 0; c < dof; ++c) {
1512     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1513     mesh->supports[off+c] = support[c];
1514   }
1515   PetscFunctionReturn(0);
1516 }
1517 
1518 #undef __FUNCT__
1519 #define __FUNCT__ "DMPlexInsertSupport"
1520 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1521 {
1522   DM_Plex    *mesh = (DM_Plex *) dm->data;
1523   PetscInt       pStart, pEnd;
1524   PetscInt       dof, off;
1525   PetscErrorCode ierr;
1526 
1527   PetscFunctionBegin;
1528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1529   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1530   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1531   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1532   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1533   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1534   if (supportPos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1535   mesh->supports[off+supportPos] = supportPoint;
1536   PetscFunctionReturn(0);
1537 }
1538 
1539 #undef __FUNCT__
1540 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1541 /*@C
1542   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1543 
1544   Not collective
1545 
1546   Input Parameters:
1547 + mesh - The DMPlex
1548 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1549 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1550 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1551 
1552   Output Parameters:
1553 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1554 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1555 
1556   Note:
1557   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1558 
1559   Level: beginner
1560 
1561 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1562 @*/
1563 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1564 {
1565   DM_Plex     *mesh = (DM_Plex *) dm->data;
1566   PetscInt       *closure, *fifo;
1567   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1568   PetscInt        tmpSize, t;
1569   PetscInt        depth = 0, maxSize;
1570   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1571   PetscErrorCode  ierr;
1572 
1573   PetscFunctionBegin;
1574   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1575   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1576   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1577   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1578   if (*points) {
1579     closure = *points;
1580   } else {
1581     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1582   }
1583   closure[0] = p; closure[1] = 0;
1584   /* This is only 1-level */
1585   if (useCone) {
1586     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1587     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1588     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1589   } else {
1590     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1591     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1592   }
1593   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1594     const PetscInt cp = tmp[t];
1595     const PetscInt co = tmpO ? tmpO[t] : 0;
1596 
1597     closure[closureSize]   = cp;
1598     closure[closureSize+1] = co;
1599     fifo[fifoSize]         = cp;
1600     fifo[fifoSize+1]       = co;
1601   }
1602   while (fifoSize - fifoStart) {
1603     const PetscInt q   = fifo[fifoStart];
1604     const PetscInt o   = fifo[fifoStart+1];
1605     const PetscInt rev = o >= 0 ? 0 : 1;
1606     const PetscInt off = rev ? -(o+1) : o;
1607 
1608     if (useCone) {
1609       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1610       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1611       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1612     } else {
1613       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1614       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1615       tmpO = PETSC_NULL;
1616     }
1617     for (t = 0; t < tmpSize; ++t) {
1618       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1619       const PetscInt cp = tmp[i];
1620       /* Must propogate orientation */
1621       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1622       PetscInt       c;
1623 
1624       /* Check for duplicate */
1625       for (c = 0; c < closureSize; c += 2) {
1626         if (closure[c] == cp) break;
1627       }
1628       if (c == closureSize) {
1629         closure[closureSize]   = cp;
1630         closure[closureSize+1] = co;
1631         fifo[fifoSize]         = cp;
1632         fifo[fifoSize+1]       = co;
1633         closureSize += 2;
1634         fifoSize    += 2;
1635       }
1636     }
1637     fifoStart += 2;
1638   }
1639   if (numPoints) *numPoints = closureSize/2;
1640   if (points)    *points    = closure;
1641   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1642   PetscFunctionReturn(0);
1643 }
1644 
1645 #undef __FUNCT__
1646 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1647 /*@C
1648   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1649 
1650   Not collective
1651 
1652   Input Parameters:
1653 + mesh - The DMPlex
1654 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1655 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1656 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1657 
1658   Output Parameters:
1659 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1660 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1661 
1662   Note:
1663   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1664 
1665   Level: beginner
1666 
1667 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1668 @*/
1669 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1670 {
1671   PetscErrorCode  ierr;
1672 
1673   PetscFunctionBegin;
1674   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1675   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1676   PetscFunctionReturn(0);
1677 }
1678 
1679 #undef __FUNCT__
1680 #define __FUNCT__ "DMPlexGetFaces"
1681 /*
1682   DMPlexGetFaces -
1683 
1684   Note: This will only work for cell-vertex meshes.
1685 */
1686 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1687 {
1688   DM_Plex     *mesh  = (DM_Plex *) dm->data;
1689   const PetscInt *cone  = PETSC_NULL;
1690   PetscInt        depth = 0, dim, coneSize;
1691   PetscErrorCode  ierr;
1692 
1693   PetscFunctionBegin;
1694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1695   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1696   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1697   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1698   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1699   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1700   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1701   switch (dim) {
1702   case 2:
1703     switch (coneSize) {
1704     case 3:
1705       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1706       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1707       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1708       *numFaces = 3;
1709       *faceSize = 2;
1710       *faces    = mesh->facesTmp;
1711       break;
1712     case 4:
1713       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1714       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1715       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1716       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1717       *numFaces = 4;
1718       *faceSize = 2;
1719       *faces    = mesh->facesTmp;
1720       break;
1721     default:
1722       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1723     }
1724     break;
1725   case 3:
1726     switch (coneSize) {
1727     case 3:
1728       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1729       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1730       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1731       *numFaces = 3;
1732       *faceSize = 2;
1733       *faces    = mesh->facesTmp;
1734       break;
1735     case 4:
1736       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1737       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1738       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1739       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1740       *numFaces = 4;
1741       *faceSize = 3;
1742       *faces    = mesh->facesTmp;
1743       break;
1744     default:
1745       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1746     }
1747     break;
1748   default:
1749     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1750   }
1751   PetscFunctionReturn(0);
1752 }
1753 
1754 #undef __FUNCT__
1755 #define __FUNCT__ "DMPlexGetMaxSizes"
1756 /*@
1757   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1758 
1759   Not collective
1760 
1761   Input Parameter:
1762 . mesh - The DMPlex
1763 
1764   Output Parameters:
1765 + maxConeSize - The maximum number of in-edges
1766 - maxSupportSize - The maximum number of out-edges
1767 
1768   Level: beginner
1769 
1770 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1771 @*/
1772 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1773 {
1774   DM_Plex *mesh = (DM_Plex *) dm->data;
1775 
1776   PetscFunctionBegin;
1777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1778   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1779   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1780   PetscFunctionReturn(0);
1781 }
1782 
1783 #undef __FUNCT__
1784 #define __FUNCT__ "DMSetUp_Plex"
1785 PetscErrorCode DMSetUp_Plex(DM dm)
1786 {
1787   DM_Plex    *mesh = (DM_Plex *) dm->data;
1788   PetscInt       size;
1789   PetscErrorCode ierr;
1790 
1791   PetscFunctionBegin;
1792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1793   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1794   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1795   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1796   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1797   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1798   if (mesh->maxSupportSize) {
1799     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1800     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1801     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1802   }
1803   PetscFunctionReturn(0);
1804 }
1805 
1806 #undef __FUNCT__
1807 #define __FUNCT__ "DMCreateSubDM_Plex"
1808 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1809 {
1810   PetscSection   section, sectionGlobal;
1811   PetscInt      *subIndices;
1812   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1813   PetscErrorCode ierr;
1814 
1815   PetscFunctionBegin;
1816   if (!numFields) PetscFunctionReturn(0);
1817   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1818   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1819   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1820   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1821   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1822   if (numFields > nF) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1823   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1824   for (p = pStart; p < pEnd; ++p) {
1825     PetscInt gdof;
1826 
1827     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1828     if (gdof > 0) {
1829       for (f = 0; f < numFields; ++f) {
1830         PetscInt fdof, fcdof;
1831 
1832         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1833         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1834         subSize += fdof-fcdof;
1835       }
1836     }
1837   }
1838   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1839   for (p = pStart; p < pEnd; ++p) {
1840     PetscInt gdof, goff;
1841 
1842     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1843     if (gdof > 0) {
1844       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1845       for (f = 0; f < numFields; ++f) {
1846         PetscInt fdof, fcdof, fc, f2, poff = 0;
1847 
1848         /* Can get rid of this loop by storing field information in the global section */
1849         for (f2 = 0; f2 < fields[f]; ++f2) {
1850           ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1851           ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1852           poff += fdof-fcdof;
1853         }
1854         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1855         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1856         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1857           subIndices[subOff] = goff+poff+fc;
1858         }
1859       }
1860     }
1861   }
1862   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1863   if (subdm) {
1864     PetscSection subsection;
1865     PetscBool    haveNull = PETSC_FALSE;
1866     PetscInt     f, nf = 0;
1867 
1868     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1869     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1870     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1871     for (f = 0; f < numFields; ++f) {
1872       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1873       if ((*subdm)->nullspaceConstructors[f]) {
1874         haveNull = PETSC_TRUE;
1875         nf       = f;
1876       }
1877     }
1878     if (haveNull) {
1879       MatNullSpace nullSpace;
1880 
1881       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1882       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1883       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1884     }
1885     if (dm->fields) {
1886       if (nF != dm->numFields) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1887       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1888       for (f = 0; f < numFields; ++f) {
1889         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1890       }
1891       if (numFields == 1) {
1892         MatNullSpace space;
1893         Mat          pmat;
1894 
1895         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject *) &space);CHKERRQ(ierr);
1896         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1897         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject *) &space);CHKERRQ(ierr);
1898         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1899         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject *) &pmat);CHKERRQ(ierr);
1900         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1901       }
1902     }
1903   }
1904   PetscFunctionReturn(0);
1905 }
1906 
1907 #undef __FUNCT__
1908 #define __FUNCT__ "DMPlexSymmetrize"
1909 /*@
1910   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1911 
1912   Not collective
1913 
1914   Input Parameter:
1915 . mesh - The DMPlex
1916 
1917   Output Parameter:
1918 
1919   Note:
1920   This should be called after all calls to DMPlexSetCone()
1921 
1922   Level: beginner
1923 
1924 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1925 @*/
1926 PetscErrorCode DMPlexSymmetrize(DM dm)
1927 {
1928   DM_Plex    *mesh = (DM_Plex *) dm->data;
1929   PetscInt      *offsets;
1930   PetscInt       supportSize;
1931   PetscInt       pStart, pEnd, p;
1932   PetscErrorCode ierr;
1933 
1934   PetscFunctionBegin;
1935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1936   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1937   /* Calculate support sizes */
1938   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1939   for (p = pStart; p < pEnd; ++p) {
1940     PetscInt dof, off, c;
1941 
1942     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1943     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1944     for (c = off; c < off+dof; ++c) {
1945       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1946     }
1947   }
1948   for (p = pStart; p < pEnd; ++p) {
1949     PetscInt dof;
1950 
1951     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1952     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1953   }
1954   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1955   /* Calculate supports */
1956   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1957   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1958   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1959   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1960   for (p = pStart; p < pEnd; ++p) {
1961     PetscInt dof, off, c;
1962 
1963     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1964     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1965     for (c = off; c < off+dof; ++c) {
1966       const PetscInt q = mesh->cones[c];
1967       PetscInt       offS;
1968 
1969       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1970       mesh->supports[offS+offsets[q]] = p;
1971       ++offsets[q];
1972     }
1973   }
1974   ierr = PetscFree(offsets);CHKERRQ(ierr);
1975   PetscFunctionReturn(0);
1976 }
1977 
1978 #undef __FUNCT__
1979 #define __FUNCT__ "DMPlexSetDepth_Private"
1980 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1981 {
1982   PetscInt       d;
1983   PetscErrorCode ierr;
1984 
1985   PetscFunctionBegin;
1986   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1987   if (d < 0) {
1988     /* We are guaranteed that the point has a cone since the depth was not yet set */
1989     const PetscInt *cone = PETSC_NULL;
1990     PetscInt        dCone;
1991 
1992     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1993     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1994     d    = dCone+1;
1995     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1996   }
1997   *depth = d;
1998   PetscFunctionReturn(0);
1999 }
2000 
2001 #undef __FUNCT__
2002 #define __FUNCT__ "DMPlexStratify"
2003 /*@
2004   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2005   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2006   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2007   the DAG.
2008 
2009   Not collective
2010 
2011   Input Parameter:
2012 . mesh - The DMPlex
2013 
2014   Output Parameter:
2015 
2016   Notes:
2017   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2018   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2019 
2020   This should be called after all calls to DMPlexSymmetrize()
2021 
2022   Level: beginner
2023 
2024 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2025 @*/
2026 PetscErrorCode DMPlexStratify(DM dm)
2027 {
2028   DM_Plex    *mesh = (DM_Plex *) dm->data;
2029   PetscInt       pStart, pEnd, p;
2030   PetscInt       numRoots = 0, numLeaves = 0;
2031   PetscErrorCode ierr;
2032 
2033   PetscFunctionBegin;
2034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2035   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2036   /* Calculate depth */
2037   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2038   /* Initialize roots and count leaves */
2039   for (p = pStart; p < pEnd; ++p) {
2040     PetscInt coneSize, supportSize;
2041 
2042     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2043     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2044     if (!coneSize && supportSize) {
2045       ++numRoots;
2046       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2047     } else if (!supportSize && coneSize) {
2048       ++numLeaves;
2049     } else if (!supportSize && !coneSize) {
2050       /* Isolated points */
2051       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2052     }
2053   }
2054   if (numRoots + numLeaves == (pEnd - pStart)) {
2055     for (p = pStart; p < pEnd; ++p) {
2056       PetscInt coneSize, supportSize;
2057 
2058       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2059       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2060       if (!supportSize && coneSize) {
2061         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2062       }
2063     }
2064   } else {
2065     /* This might be slow since lookup is not fast */
2066     for (p = pStart; p < pEnd; ++p) {
2067       PetscInt depth;
2068 
2069       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2070     }
2071   }
2072   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2073   PetscFunctionReturn(0);
2074 }
2075 
2076 #undef __FUNCT__
2077 #define __FUNCT__ "DMPlexGetJoin"
2078 /*@C
2079   DMPlexGetJoin - Get an array for the join of the set of points
2080 
2081   Not Collective
2082 
2083   Input Parameters:
2084 + dm - The DMPlex object
2085 . numPoints - The number of input points for the join
2086 - points - The input points
2087 
2088   Output Parameters:
2089 + numCoveredPoints - The number of points in the join
2090 - coveredPoints - The points in the join
2091 
2092   Level: intermediate
2093 
2094   Note: Currently, this is restricted to a single level join
2095 
2096 .keywords: mesh
2097 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2098 @*/
2099 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2100 {
2101   DM_Plex    *mesh = (DM_Plex *) dm->data;
2102   PetscInt      *join[2];
2103   PetscInt       joinSize, i = 0;
2104   PetscInt       dof, off, p, c, m;
2105   PetscErrorCode ierr;
2106 
2107   PetscFunctionBegin;
2108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2109   PetscValidPointer(points, 2);
2110   PetscValidPointer(numCoveredPoints, 3);
2111   PetscValidPointer(coveredPoints, 4);
2112   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2113   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2114   /* Copy in support of first point */
2115   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2116   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2117   for (joinSize = 0; joinSize < dof; ++joinSize) {
2118     join[i][joinSize] = mesh->supports[off+joinSize];
2119   }
2120   /* Check each successive support */
2121   for (p = 1; p < numPoints; ++p) {
2122     PetscInt newJoinSize = 0;
2123 
2124     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2125     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2126     for (c = 0; c < dof; ++c) {
2127       const PetscInt point = mesh->supports[off+c];
2128 
2129       for (m = 0; m < joinSize; ++m) {
2130         if (point == join[i][m]) {
2131           join[1-i][newJoinSize++] = point;
2132           break;
2133         }
2134       }
2135     }
2136     joinSize = newJoinSize;
2137     i = 1-i;
2138   }
2139   *numCoveredPoints = joinSize;
2140   *coveredPoints    = join[i];
2141   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2142   PetscFunctionReturn(0);
2143 }
2144 
2145 #undef __FUNCT__
2146 #define __FUNCT__ "DMPlexRestoreJoin"
2147 /*@C
2148   DMPlexRestoreJoin - Restore an array for the join of the set of points
2149 
2150   Not Collective
2151 
2152   Input Parameters:
2153 + dm - The DMPlex object
2154 . numPoints - The number of input points for the join
2155 - points - The input points
2156 
2157   Output Parameters:
2158 + numCoveredPoints - The number of points in the join
2159 - coveredPoints - The points in the join
2160 
2161   Level: intermediate
2162 
2163 .keywords: mesh
2164 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2165 @*/
2166 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2167 {
2168   PetscErrorCode ierr;
2169 
2170   PetscFunctionBegin;
2171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2172   PetscValidPointer(coveredPoints, 4);
2173   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2174   PetscFunctionReturn(0);
2175 }
2176 
2177 #undef __FUNCT__
2178 #define __FUNCT__ "DMPlexGetFullJoin"
2179 /*@C
2180   DMPlexGetFullJoin - Get an array for the join of the set of points
2181 
2182   Not Collective
2183 
2184   Input Parameters:
2185 + dm - The DMPlex object
2186 . numPoints - The number of input points for the join
2187 - points - The input points
2188 
2189   Output Parameters:
2190 + numCoveredPoints - The number of points in the join
2191 - coveredPoints - The points in the join
2192 
2193   Level: intermediate
2194 
2195 .keywords: mesh
2196 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2197 @*/
2198 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2199 {
2200   DM_Plex    *mesh = (DM_Plex *) dm->data;
2201   PetscInt      *offsets, **closures;
2202   PetscInt      *join[2];
2203   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2204   PetscInt       p, d, c, m;
2205   PetscErrorCode ierr;
2206 
2207   PetscFunctionBegin;
2208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2209   PetscValidPointer(points, 2);
2210   PetscValidPointer(numCoveredPoints, 3);
2211   PetscValidPointer(coveredPoints, 4);
2212 
2213   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2214   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2215   ierr = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2216   ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2217   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2218   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2219   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2220 
2221   for (p = 0; p < numPoints; ++p) {
2222     PetscInt closureSize;
2223 
2224     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2225     offsets[p*(depth+2)+0] = 0;
2226     for (d = 0; d < depth+1; ++d) {
2227       PetscInt pStart, pEnd, i;
2228 
2229       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2230       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2231         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2232           offsets[p*(depth+2)+d+1] = i;
2233           break;
2234         }
2235       }
2236       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2237     }
2238     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2239   }
2240   for (d = 0; d < depth+1; ++d) {
2241     PetscInt dof;
2242 
2243     /* Copy in support of first point */
2244     dof = offsets[d+1] - offsets[d];
2245     for (joinSize = 0; joinSize < dof; ++joinSize) {
2246       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2247     }
2248     /* Check each successive cone */
2249     for (p = 1; p < numPoints && joinSize; ++p) {
2250       PetscInt newJoinSize = 0;
2251 
2252       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2253       for (c = 0; c < dof; ++c) {
2254         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2255 
2256         for (m = 0; m < joinSize; ++m) {
2257           if (point == join[i][m]) {
2258             join[1-i][newJoinSize++] = point;
2259             break;
2260           }
2261         }
2262       }
2263       joinSize = newJoinSize;
2264       i = 1-i;
2265     }
2266     if (joinSize) break;
2267   }
2268   *numCoveredPoints = joinSize;
2269   *coveredPoints    = join[i];
2270   for (p = 0; p < numPoints; ++p) {
2271     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2272   }
2273   ierr = PetscFree(closures);CHKERRQ(ierr);
2274   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2275   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2276   PetscFunctionReturn(0);
2277 }
2278 
2279 #undef __FUNCT__
2280 #define __FUNCT__ "DMPlexGetMeet"
2281 /*@C
2282   DMPlexGetMeet - Get an array for the meet of the set of points
2283 
2284   Not Collective
2285 
2286   Input Parameters:
2287 + dm - The DMPlex object
2288 . numPoints - The number of input points for the meet
2289 - points - The input points
2290 
2291   Output Parameters:
2292 + numCoveredPoints - The number of points in the meet
2293 - coveredPoints - The points in the meet
2294 
2295   Level: intermediate
2296 
2297   Note: Currently, this is restricted to a single level meet
2298 
2299 .keywords: mesh
2300 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2301 @*/
2302 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2303 {
2304   DM_Plex    *mesh = (DM_Plex *) dm->data;
2305   PetscInt      *meet[2];
2306   PetscInt       meetSize, i = 0;
2307   PetscInt       dof, off, p, c, m;
2308   PetscErrorCode ierr;
2309 
2310   PetscFunctionBegin;
2311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2312   PetscValidPointer(points, 2);
2313   PetscValidPointer(numCoveringPoints, 3);
2314   PetscValidPointer(coveringPoints, 4);
2315   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2316   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2317   /* Copy in cone of first point */
2318   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2319   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2320   for (meetSize = 0; meetSize < dof; ++meetSize) {
2321     meet[i][meetSize] = mesh->cones[off+meetSize];
2322   }
2323   /* Check each successive cone */
2324   for (p = 1; p < numPoints; ++p) {
2325     PetscInt newMeetSize = 0;
2326 
2327     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2328     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2329     for (c = 0; c < dof; ++c) {
2330       const PetscInt point = mesh->cones[off+c];
2331 
2332       for (m = 0; m < meetSize; ++m) {
2333         if (point == meet[i][m]) {
2334           meet[1-i][newMeetSize++] = point;
2335           break;
2336         }
2337       }
2338     }
2339     meetSize = newMeetSize;
2340     i = 1-i;
2341   }
2342   *numCoveringPoints = meetSize;
2343   *coveringPoints    = meet[i];
2344   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2345   PetscFunctionReturn(0);
2346 }
2347 
2348 #undef __FUNCT__
2349 #define __FUNCT__ "DMPlexRestoreMeet"
2350 /*@C
2351   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2352 
2353   Not Collective
2354 
2355   Input Parameters:
2356 + dm - The DMPlex object
2357 . numPoints - The number of input points for the meet
2358 - points - The input points
2359 
2360   Output Parameters:
2361 + numCoveredPoints - The number of points in the meet
2362 - coveredPoints - The points in the meet
2363 
2364   Level: intermediate
2365 
2366 .keywords: mesh
2367 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2368 @*/
2369 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2370 {
2371   PetscErrorCode ierr;
2372 
2373   PetscFunctionBegin;
2374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2375   PetscValidPointer(coveredPoints, 4);
2376   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2377   PetscFunctionReturn(0);
2378 }
2379 
2380 #undef __FUNCT__
2381 #define __FUNCT__ "DMPlexGetFullMeet"
2382 /*@C
2383   DMPlexGetFullMeet - Get an array for the meet of the set of points
2384 
2385   Not Collective
2386 
2387   Input Parameters:
2388 + dm - The DMPlex object
2389 . numPoints - The number of input points for the meet
2390 - points - The input points
2391 
2392   Output Parameters:
2393 + numCoveredPoints - The number of points in the meet
2394 - coveredPoints - The points in the meet
2395 
2396   Level: intermediate
2397 
2398 .keywords: mesh
2399 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2400 @*/
2401 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2402 {
2403   DM_Plex    *mesh = (DM_Plex *) dm->data;
2404   PetscInt      *offsets, **closures;
2405   PetscInt      *meet[2];
2406   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2407   PetscInt       p, h, c, m;
2408   PetscErrorCode ierr;
2409 
2410   PetscFunctionBegin;
2411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2412   PetscValidPointer(points, 2);
2413   PetscValidPointer(numCoveredPoints, 3);
2414   PetscValidPointer(coveredPoints, 4);
2415 
2416   ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2417   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2418   ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2419   maxSize = PetscPowInt(mesh->maxConeSize,height);
2420   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2421   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2422 
2423   for (p = 0; p < numPoints; ++p) {
2424     PetscInt closureSize;
2425 
2426     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2427     offsets[p*(height+2)+0] = 0;
2428     for (h = 0; h < height+1; ++h) {
2429       PetscInt pStart, pEnd, i;
2430 
2431       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2432       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2433         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2434           offsets[p*(height+2)+h+1] = i;
2435           break;
2436         }
2437       }
2438       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2439     }
2440     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2441   }
2442   for (h = 0; h < height+1; ++h) {
2443     PetscInt dof;
2444 
2445     /* Copy in cone of first point */
2446     dof = offsets[h+1] - offsets[h];
2447     for (meetSize = 0; meetSize < dof; ++meetSize) {
2448       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2449     }
2450     /* Check each successive cone */
2451     for (p = 1; p < numPoints && meetSize; ++p) {
2452       PetscInt newMeetSize = 0;
2453 
2454       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2455       for (c = 0; c < dof; ++c) {
2456         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2457 
2458         for (m = 0; m < meetSize; ++m) {
2459           if (point == meet[i][m]) {
2460             meet[1-i][newMeetSize++] = point;
2461             break;
2462           }
2463         }
2464       }
2465       meetSize = newMeetSize;
2466       i = 1-i;
2467     }
2468     if (meetSize) break;
2469   }
2470   *numCoveredPoints = meetSize;
2471   *coveredPoints    = meet[i];
2472   for (p = 0; p < numPoints; ++p) {
2473     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2474   }
2475   ierr = PetscFree(closures);CHKERRQ(ierr);
2476   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2477   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2478   PetscFunctionReturn(0);
2479 }
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2483 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2484 {
2485   MPI_Comm       comm = ((PetscObject) dm)->comm;
2486   PetscInt       cellDim;
2487   PetscErrorCode ierr;
2488 
2489   PetscFunctionBegin;
2490   PetscValidPointer(numFaceVertices,3);
2491   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2492   switch (cellDim) {
2493   case 0:
2494     *numFaceVertices = 0;
2495     break;
2496   case 1:
2497     *numFaceVertices = 1;
2498     break;
2499   case 2:
2500     switch (numCorners) {
2501     case 3: /* triangle */
2502       *numFaceVertices = 2; /* Edge has 2 vertices */
2503       break;
2504     case 4: /* quadrilateral */
2505       *numFaceVertices = 2; /* Edge has 2 vertices */
2506       break;
2507     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2508       *numFaceVertices = 3; /* Edge has 3 vertices */
2509       break;
2510     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2511       *numFaceVertices = 3; /* Edge has 3 vertices */
2512       break;
2513     default:
2514       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2515     }
2516     break;
2517   case 3:
2518     switch (numCorners) {
2519     case 4: /* tetradehdron */
2520       *numFaceVertices = 3; /* Face has 3 vertices */
2521       break;
2522     case 6: /* tet cohesive cells */
2523       *numFaceVertices = 4; /* Face has 4 vertices */
2524       break;
2525     case 8: /* hexahedron */
2526       *numFaceVertices = 4; /* Face has 4 vertices */
2527       break;
2528     case 9: /* tet cohesive Lagrange cells */
2529       *numFaceVertices = 6; /* Face has 6 vertices */
2530       break;
2531     case 10: /* quadratic tetrahedron */
2532       *numFaceVertices = 6; /* Face has 6 vertices */
2533       break;
2534     case 12: /* hex cohesive Lagrange cells */
2535       *numFaceVertices = 6; /* Face has 6 vertices */
2536       break;
2537     case 18: /* quadratic tet cohesive Lagrange cells */
2538       *numFaceVertices = 6; /* Face has 6 vertices */
2539       break;
2540     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2541       *numFaceVertices = 9; /* Face has 9 vertices */
2542       break;
2543     default:
2544       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2545     }
2546     break;
2547   default:
2548     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2549   }
2550   PetscFunctionReturn(0);
2551 }
2552 
2553 #undef __FUNCT__
2554 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2555 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2556 {
2557   const PetscInt maxFaceCases = 30;
2558   PetscInt       numFaceCases = 0;
2559   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2560   PetscInt      *off, *adj;
2561   PetscInt      *neighborCells, *tmpClosure;
2562   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2563   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2564   PetscErrorCode ierr;
2565 
2566   PetscFunctionBegin;
2567   /* For parallel partitioning, I think you have to communicate supports */
2568   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2569   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2570   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2571   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2572   if (cEnd - cStart == 0) {
2573     if (numVertices) *numVertices = 0;
2574     if (offsets)     *offsets     = PETSC_NULL;
2575     if (adjacency)   *adjacency   = PETSC_NULL;
2576     PetscFunctionReturn(0);
2577   }
2578   numCells = cEnd - cStart;
2579   /* Setup face recognition */
2580   {
2581     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
2582 
2583     for (c = cStart; c < cEnd; ++c) {
2584       PetscInt corners;
2585 
2586       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2587       if (!cornersSeen[corners]) {
2588         PetscInt nFV;
2589 
2590         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2591         cornersSeen[corners] = 1;
2592         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2593         numFaceVertices[numFaceCases++] = nFV;
2594       }
2595     }
2596   }
2597   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2598   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2599   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2600   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2601   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2602   /* Count neighboring cells */
2603   for (cell = cStart; cell < cEnd; ++cell) {
2604     PetscInt numNeighbors = maxNeighbors, n;
2605 
2606     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2607     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2608     for (n = 0; n < numNeighbors; ++n) {
2609       PetscInt        cellPair[2];
2610       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2611       PetscInt        meetSize    = 0;
2612       const PetscInt *meet        = PETSC_NULL;
2613 
2614       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2615       if (cellPair[0] == cellPair[1]) continue;
2616       if (!found) {
2617         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2618         if (meetSize) {
2619           PetscInt f;
2620 
2621           for (f = 0; f < numFaceCases; ++f) {
2622             if (numFaceVertices[f] == meetSize) {
2623               found = PETSC_TRUE;
2624               break;
2625             }
2626           }
2627         }
2628         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2629       }
2630       if (found) {
2631         ++off[cell-cStart+1];
2632       }
2633     }
2634   }
2635   /* Prefix sum */
2636   for (cell = 1; cell <= numCells; ++cell) {
2637     off[cell] += off[cell-1];
2638   }
2639   if (adjacency) {
2640     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2641     /* Get neighboring cells */
2642     for (cell = cStart; cell < cEnd; ++cell) {
2643       PetscInt numNeighbors = maxNeighbors, n;
2644       PetscInt cellOffset   = 0;
2645 
2646       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2647       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2648       for (n = 0; n < numNeighbors; ++n) {
2649         PetscInt        cellPair[2];
2650         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2651         PetscInt        meetSize    = 0;
2652         const PetscInt *meet        = PETSC_NULL;
2653 
2654         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2655         if (cellPair[0] == cellPair[1]) continue;
2656         if (!found) {
2657           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2658           if (meetSize) {
2659             PetscInt f;
2660 
2661             for (f = 0; f < numFaceCases; ++f) {
2662               if (numFaceVertices[f] == meetSize) {
2663                 found = PETSC_TRUE;
2664                 break;
2665               }
2666             }
2667           }
2668           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2669         }
2670         if (found) {
2671           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2672           ++cellOffset;
2673         }
2674       }
2675     }
2676   }
2677   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2678   if (numVertices) *numVertices = numCells;
2679   if (offsets)     *offsets     = off;
2680   if (adjacency)   *adjacency   = adj;
2681   PetscFunctionReturn(0);
2682 }
2683 
2684 #if defined(PETSC_HAVE_CHACO)
2685 #if defined(PETSC_HAVE_UNISTD_H)
2686 #include <unistd.h>
2687 #endif
2688 /* Chaco does not have an include file */
2689 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2690                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2691                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2692                        int mesh_dims[3], double *goal, int global_method, int local_method,
2693                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2694 
2695 extern int FREE_GRAPH;
2696 
2697 #undef __FUNCT__
2698 #define __FUNCT__ "DMPlexPartition_Chaco"
2699 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2700 {
2701   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2702   MPI_Comm comm = ((PetscObject) dm)->comm;
2703   int nvtxs = numVertices;                /* number of vertices in full graph */
2704   int *vwgts = NULL;                      /* weights for all vertices */
2705   float *ewgts = NULL;                    /* weights for all edges */
2706   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2707   char *outassignname = NULL;             /*  name of assignment output file */
2708   char *outfilename = NULL;               /* output file name */
2709   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2710   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2711   int mesh_dims[3];                       /* dimensions of mesh of processors */
2712   double *goal = NULL;                    /* desired set sizes for each set */
2713   int global_method = 1;                  /* global partitioning algorithm */
2714   int local_method = 1;                   /* local partitioning algorithm */
2715   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2716   int vmax = 200;                         /* how many vertices to coarsen down to? */
2717   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2718   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2719   long seed = 123636512;                  /* for random graph mutations */
2720   short int *assignment;                  /* Output partition */
2721   int fd_stdout, fd_pipe[2];
2722   PetscInt      *points;
2723   PetscMPIInt    commSize;
2724   int            i, v, p;
2725   PetscErrorCode ierr;
2726 
2727   PetscFunctionBegin;
2728   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2729   if (!numVertices) {
2730     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2731     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2732     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2733     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2734     PetscFunctionReturn(0);
2735   }
2736   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2737   for (i = 0; i < start[numVertices]; ++i) {
2738     ++adjacency[i];
2739   }
2740   if (global_method == INERTIAL_METHOD) {
2741     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2742     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2743   }
2744   mesh_dims[0] = commSize;
2745   mesh_dims[1] = 1;
2746   mesh_dims[2] = 1;
2747   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2748   /* Chaco outputs to stdout. We redirect this to a buffer. */
2749   /* TODO: check error codes for UNIX calls */
2750 #if defined(PETSC_HAVE_UNISTD_H)
2751   {
2752     int piperet;
2753     piperet = pipe(fd_pipe);
2754     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2755     fd_stdout = dup(1);
2756     close(1);
2757     dup2(fd_pipe[1], 1);
2758   }
2759 #endif
2760   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2761                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2762                    vmax, ndims, eigtol, seed);
2763 #if defined(PETSC_HAVE_UNISTD_H)
2764   {
2765     char msgLog[10000];
2766     int  count;
2767 
2768     fflush(stdout);
2769     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2770     if (count < 0) count = 0;
2771     msgLog[count] = 0;
2772     close(1);
2773     dup2(fd_stdout, 1);
2774     close(fd_stdout);
2775     close(fd_pipe[0]);
2776     close(fd_pipe[1]);
2777     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2778   }
2779 #endif
2780   /* Convert to PetscSection+IS */
2781   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2782   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2783   for (v = 0; v < nvtxs; ++v) {
2784     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2785   }
2786   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2787   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2788   for (p = 0, i = 0; p < commSize; ++p) {
2789     for (v = 0; v < nvtxs; ++v) {
2790       if (assignment[v] == p) points[i++] = v;
2791     }
2792   }
2793   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2794   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2795   if (global_method == INERTIAL_METHOD) {
2796     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2797   }
2798   ierr = PetscFree(assignment);CHKERRQ(ierr);
2799   for (i = 0; i < start[numVertices]; ++i) {
2800     --adjacency[i];
2801   }
2802   PetscFunctionReturn(0);
2803 }
2804 #endif
2805 
2806 #if defined(PETSC_HAVE_PARMETIS)
2807 #undef __FUNCT__
2808 #define __FUNCT__ "DMPlexPartition_ParMetis"
2809 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2810 {
2811   PetscFunctionBegin;
2812   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2813   PetscFunctionReturn(0);
2814 }
2815 #endif
2816 
2817 #undef __FUNCT__
2818 #define __FUNCT__ "DMPlexEnlargePartition"
2819 /* Expand the partition by BFS on the adjacency graph */
2820 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2821 {
2822   PetscHashI      h;
2823   const PetscInt *points;
2824   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2825   PetscInt        pStart, pEnd, part, q;
2826   PetscErrorCode  ierr;
2827 
2828   PetscFunctionBegin;
2829   PetscHashICreate(h);
2830   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2831   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2832   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2833   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2834   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2835   for (part = pStart; part < pEnd; ++part) {
2836     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2837 
2838     PetscHashIClear(h);
2839     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2840     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2841     /* Add all existing points to h */
2842     for (p = 0; p < numPoints; ++p) {
2843       const PetscInt point = points[off+p];
2844       PetscHashIAdd(h, point, 1);
2845     }
2846     PetscHashISize(h, nP);
2847     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2848     /* Add all points in next BFS level */
2849     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2850     for (p = 0; p < numPoints; ++p) {
2851       const PetscInt point = points[off+p];
2852       PetscInt s = start[point], e = start[point+1], a;
2853 
2854       for (a = s; a < e; ++a) {
2855         PetscHashIAdd(h, adjacency[a], 1);
2856       }
2857     }
2858     PetscHashISize(h, numNewPoints);
2859     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2860     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2861     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2862     totPoints += numNewPoints;
2863   }
2864   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2865   PetscHashIDestroy(h);
2866   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2867   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2868   for (part = pStart, q = 0; part < pEnd; ++part) {
2869     PetscInt numPoints, p;
2870 
2871     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2872     for (p = 0; p < numPoints; ++p, ++q) {
2873       newPoints[q] = tmpPoints[part][p];
2874     }
2875     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2876   }
2877   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2878   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2879   PetscFunctionReturn(0);
2880 }
2881 
2882 #undef __FUNCT__
2883 #define __FUNCT__ "DMPlexCreatePartition"
2884 /*
2885   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2886 
2887   Collective on DM
2888 
2889   Input Parameters:
2890   + dm - The DM
2891   . height - The height for points in the partition
2892   - enlarge - Expand each partition with neighbors
2893 
2894   Output Parameters:
2895   + partSection - The PetscSection giving the division of points by partition
2896   . partition - The list of points by partition
2897   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2898   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2899 
2900   Level: developer
2901 
2902 .seealso DMPlexDistribute()
2903 */
2904 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2905 {
2906   PetscMPIInt    size;
2907   PetscErrorCode ierr;
2908 
2909   PetscFunctionBegin;
2910   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2911   *origPartSection = PETSC_NULL;
2912   *origPartition   = PETSC_NULL;
2913   if (size == 1) {
2914     PetscInt *points;
2915     PetscInt  cStart, cEnd, c;
2916 
2917     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2918     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2919     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2920     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2921     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2922     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2923     for (c = cStart; c < cEnd; ++c) {
2924       points[c] = c;
2925     }
2926     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2927     PetscFunctionReturn(0);
2928   }
2929   if (height == 0) {
2930     PetscInt  numVertices;
2931     PetscInt *start     = PETSC_NULL;
2932     PetscInt *adjacency = PETSC_NULL;
2933 
2934     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2935     if (1) {
2936 #if defined(PETSC_HAVE_CHACO)
2937       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2938 #endif
2939     } else {
2940 #if defined(PETSC_HAVE_PARMETIS)
2941       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2942 #endif
2943     }
2944     if (enlarge) {
2945       *origPartSection = *partSection;
2946       *origPartition   = *partition;
2947       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2948     }
2949     ierr = PetscFree(start);CHKERRQ(ierr);
2950     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2951 # if 0
2952   } else if (height == 1) {
2953     /* Build the dual graph for faces and partition the hypergraph */
2954     PetscInt numEdges;
2955 
2956     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2957     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2958     destroyCSR(numEdges, start, adjacency);
2959 #endif
2960   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2961   PetscFunctionReturn(0);
2962 }
2963 
2964 #undef __FUNCT__
2965 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2966 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2967 {
2968   /* const PetscInt  height = 0; */
2969   const PetscInt *partArray;
2970   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2971   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2972   PetscErrorCode  ierr;
2973 
2974   PetscFunctionBegin;
2975   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2976   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2977   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2978   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2979   for (rank = rStart; rank < rEnd; ++rank) {
2980     PetscInt partSize = 0;
2981     PetscInt numPoints, offset, p;
2982 
2983     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2984     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2985     for (p = 0; p < numPoints; ++p) {
2986       PetscInt  point   = partArray[offset+p], closureSize, c;
2987       PetscInt *closure = PETSC_NULL;
2988 
2989       /* TODO Include support for height > 0 case */
2990       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2991       /* Merge into existing points */
2992       if (partSize+closureSize > maxPartSize) {
2993         PetscInt *tmpPoints;
2994 
2995         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2996         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2997         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2998         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2999         partPoints = tmpPoints;
3000       }
3001       for (c = 0; c < closureSize; ++c) {
3002         partPoints[partSize+c] = closure[c*2];
3003       }
3004       partSize += closureSize;
3005       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3006       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3007     }
3008     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3009   }
3010   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3011   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3012   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3013 
3014   for (rank = rStart; rank < rEnd; ++rank) {
3015     PetscInt partSize = 0, newOffset;
3016     PetscInt numPoints, offset, p;
3017 
3018     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3019     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3020     for (p = 0; p < numPoints; ++p) {
3021       PetscInt  point   = partArray[offset+p], closureSize, c;
3022       PetscInt *closure = PETSC_NULL;
3023 
3024       /* TODO Include support for height > 0 case */
3025       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3026       /* Merge into existing points */
3027       for (c = 0; c < closureSize; ++c) {
3028         partPoints[partSize+c] = closure[c*2];
3029       }
3030       partSize += closureSize;
3031       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3032       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3033     }
3034     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3035     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3036   }
3037   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3038   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3039   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3040   PetscFunctionReturn(0);
3041 }
3042 
3043 #undef __FUNCT__
3044 #define __FUNCT__ "DMPlexDistributeField"
3045 /*
3046   Input Parameters:
3047 . originalSection
3048 , originalVec
3049 
3050   Output Parameters:
3051 . newSection
3052 . newVec
3053 */
3054 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3055 {
3056   PetscSF         fieldSF;
3057   PetscInt       *remoteOffsets, fieldSize;
3058   PetscScalar    *originalValues, *newValues;
3059   PetscErrorCode  ierr;
3060 
3061   PetscFunctionBegin;
3062   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3063 
3064   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3065   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3066   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3067 
3068   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3069   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3070   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3071   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3072   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3073   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3074   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3075   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3076   PetscFunctionReturn(0);
3077 }
3078 
3079 #undef __FUNCT__
3080 #define __FUNCT__ "DMPlexDistribute"
3081 /*@C
3082   DMPlexDistribute - Distributes the mesh and any associated sections.
3083 
3084   Not Collective
3085 
3086   Input Parameter:
3087 + dm  - The original DMPlex object
3088 . partitioner - The partitioning package, or NULL for the default
3089 - overlap - The overlap of partitions, 0 is the default
3090 
3091   Output Parameter:
3092 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3093 
3094   Note: If the mesh was not distributed, the return value is PETSC_NULL
3095 
3096   Level: intermediate
3097 
3098 .keywords: mesh, elements
3099 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3100 @*/
3101 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3102 {
3103   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3104   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3105   const PetscInt height = 0;
3106   PetscInt       dim, numRemoteRanks;
3107   IS             origCellPart,        cellPart,        part;
3108   PetscSection   origCellPartSection, cellPartSection, partSection;
3109   PetscSFNode   *remoteRanks;
3110   PetscSF        partSF, pointSF, coneSF;
3111   ISLocalToGlobalMapping renumbering;
3112   PetscSection   originalConeSection, newConeSection;
3113   PetscInt      *remoteOffsets;
3114   PetscInt      *cones, *newCones, newConesSize;
3115   PetscBool      flg;
3116   PetscMPIInt    rank, numProcs, p;
3117   PetscErrorCode ierr;
3118 
3119   PetscFunctionBegin;
3120   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3121   PetscValidPointer(dmParallel,4);
3122   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3123   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3124   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3125   *dmParallel = PETSC_NULL;
3126   if (numProcs == 1) PetscFunctionReturn(0);
3127 
3128   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3129   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3130   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3131   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3132   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3133   if (!rank) {
3134     numRemoteRanks = numProcs;
3135   } else {
3136     numRemoteRanks = 0;
3137   }
3138   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3139   for (p = 0; p < numRemoteRanks; ++p) {
3140     remoteRanks[p].rank  = p;
3141     remoteRanks[p].index = 0;
3142   }
3143   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3144   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3145   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3146   if (flg) {
3147     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3148     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3149     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3150     if (origCellPart) {
3151       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3152       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3153       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3154     }
3155     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3156   }
3157   /* Close the partition over the mesh */
3158   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3159   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3160   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3161   /* Create new mesh */
3162   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3163   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3164   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3165   pmesh = (DM_Plex *) (*dmParallel)->data;
3166   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3167   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3168   if (flg) {
3169     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3170     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3171     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3172     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3173     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3174     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3175   }
3176   /* Distribute cone section */
3177   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3178   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3179   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3180   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3181   {
3182     PetscInt pStart, pEnd, p;
3183 
3184     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3185     for (p = pStart; p < pEnd; ++p) {
3186       PetscInt coneSize;
3187       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3188       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3189     }
3190   }
3191   /* Communicate and renumber cones */
3192   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3193   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3194   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3195   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3196   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3197   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3198   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3199   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3200   if (flg) {
3201     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3202     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3203     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3204     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3205     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3206   }
3207   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3208   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3209   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3210   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3211   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3212   /* Create supports and stratify sieve */
3213   {
3214     PetscInt pStart, pEnd;
3215 
3216     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3217     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3218   }
3219   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3220   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3221   /* Distribute Coordinates */
3222   {
3223     PetscSection originalCoordSection, newCoordSection;
3224     Vec          originalCoordinates, newCoordinates;
3225     const char  *name;
3226 
3227     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3228     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3229     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3230     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3231     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3232     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3233 
3234     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3235     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3236     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3237   }
3238   /* Distribute labels */
3239   {
3240     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3241     PetscInt   numLabels = 0, l;
3242 
3243     /* Bcast number of labels */
3244     while (next) {++numLabels; next = next->next;}
3245     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3246     next = mesh->labels;
3247     for (l = 0; l < numLabels; ++l) {
3248       DMLabel         newLabel;
3249       const PetscInt *partArray;
3250       char           *name;
3251       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3252       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3253       PetscInt        nameSize, s, p;
3254       PetscBool       isdepth;
3255       size_t          len = 0;
3256 
3257       /* Bcast name (could filter for no points) */
3258       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3259       nameSize = len;
3260       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3261       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3262       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3263       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3264       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3265       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3266       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3267       newLabel->name = name;
3268       /* Bcast numStrata (could filter for no points in stratum) */
3269       if (!rank) {newLabel->numStrata = next->numStrata;}
3270       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3271       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3272                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3273                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3274       /* Bcast stratumValues (could filter for no points in stratum) */
3275       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3276       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3277       /* Find size on each process and Scatter */
3278       if (!rank) {
3279         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3280         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3281         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3282         for (s = 0; s < next->numStrata; ++s) {
3283           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3284             const PetscInt point = next->points[p];
3285             PetscInt       proc;
3286 
3287             for (proc = 0; proc < numProcs; ++proc) {
3288               PetscInt dof, off, pPart;
3289 
3290               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3291               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3292               for (pPart = off; pPart < off+dof; ++pPart) {
3293                 if (partArray[pPart] == point) {
3294                   ++stratumSizes[proc*next->numStrata+s];
3295                   break;
3296                 }
3297               }
3298             }
3299           }
3300         }
3301         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3302       }
3303       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3304       /* Calculate stratumOffsets */
3305       newLabel->stratumOffsets[0] = 0;
3306       for (s = 0; s < newLabel->numStrata; ++s) {
3307         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3308       }
3309       /* Pack points and Scatter */
3310       if (!rank) {
3311         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3312         displs[0] = 0;
3313         for (p = 0; p < numProcs; ++p) {
3314           sendcnts[p] = 0;
3315           for (s = 0; s < next->numStrata; ++s) {
3316             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3317           }
3318           offsets[p]  = displs[p];
3319           displs[p+1] = displs[p] + sendcnts[p];
3320         }
3321         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3322         for (s = 0; s < next->numStrata; ++s) {
3323           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3324             const PetscInt point = next->points[p];
3325             PetscInt       proc;
3326 
3327             for (proc = 0; proc < numProcs; ++proc) {
3328               PetscInt dof, off, pPart;
3329 
3330               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3331               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3332               for (pPart = off; pPart < off+dof; ++pPart) {
3333                 if (partArray[pPart] == point) {
3334                   points[offsets[proc]++] = point;
3335                   break;
3336                 }
3337               }
3338             }
3339           }
3340         }
3341       }
3342       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3343       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3344       ierr = PetscFree(points);CHKERRQ(ierr);
3345       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3346       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3347       /* Renumber points */
3348       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3349       /* Sort points */
3350       for (s = 0; s < newLabel->numStrata; ++s) {
3351         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3352       }
3353       /* Insert into list */
3354       if (newNext) {
3355         newNext->next = newLabel;
3356       } else {
3357         pmesh->labels = newLabel;
3358       }
3359       newNext = newLabel;
3360       if (!rank) {next = next->next;}
3361     }
3362   }
3363   /* Cleanup Partition */
3364   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3365   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3366   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3367   ierr = ISDestroy(&part);CHKERRQ(ierr);
3368   /* Create point SF for parallel mesh */
3369   {
3370     const PetscInt *leaves;
3371     PetscSFNode    *remotePoints, *rowners, *lowners;
3372     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3373     PetscInt        pStart, pEnd;
3374 
3375     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3376     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3377     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3378     for (p=0; p<numRoots; p++) {
3379       rowners[p].rank = -1;
3380       rowners[p].index = -1;
3381     }
3382     if (origCellPart) {
3383       /* Make sure cells in the original partition are not assigned to other procs */
3384       const PetscInt *origCells;
3385 
3386       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3387       for (p = 0; p < numProcs; ++p) {
3388         PetscInt dof, off, d;
3389 
3390         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3391         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3392         for (d = off; d < off+dof; ++d) {
3393           rowners[origCells[d]].rank = p;
3394         }
3395       }
3396       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3397     }
3398     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3399     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3400 
3401     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3402     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3403     for (p = 0; p < numLeaves; ++p) {
3404       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3405         lowners[p].rank = rank;
3406         lowners[p].index = leaves ? leaves[p] : p;
3407       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3408         lowners[p].rank = -2;
3409         lowners[p].index = -2;
3410       }
3411     }
3412     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3413       rowners[p].rank = -3;
3414       rowners[p].index = -3;
3415     }
3416     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3417     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3418     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3419     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3420     for (p = 0; p < numLeaves; ++p) {
3421       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3422       if (lowners[p].rank != rank) ++numGhostPoints;
3423     }
3424     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3425     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3426     for (p = 0, gp = 0; p < numLeaves; ++p) {
3427       if (lowners[p].rank != rank) {
3428         ghostPoints[gp]       = leaves ? leaves[p] : p;
3429         remotePoints[gp].rank  = lowners[p].rank;
3430         remotePoints[gp].index = lowners[p].index;
3431         ++gp;
3432       }
3433     }
3434     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3435     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3436     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3437   }
3438   /* Cleanup */
3439   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3440   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3441   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3442   PetscFunctionReturn(0);
3443 }
3444 
3445 #undef __FUNCT__
3446 #define __FUNCT__ "DMPlexRenumber_Private"
3447 /*
3448   Reasons to renumber:
3449 
3450   1) Permute points, e.g. bandwidth reduction (Renumber)
3451 
3452     a) Must not mix strata
3453 
3454   2) Shift numbers for point insertion (Shift)
3455 
3456     a) Want operation brken into parts so that insertion can be interleaved
3457 
3458   renumbering - An IS which provides the new numbering
3459 */
3460 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3461 {
3462   PetscFunctionBegin;
3463   PetscFunctionReturn(0);
3464 }
3465 
3466 #undef __FUNCT__
3467 #define __FUNCT__ "DMPlexShiftPoint_Private"
3468 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3469 {
3470   if (depth < 0) return p;
3471   /* Cells    */ if (p < depthEnd[depth])   return p;
3472   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3473   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3474   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3475 }
3476 
3477 #undef __FUNCT__
3478 #define __FUNCT__ "DMPlexShiftSizes_Private"
3479 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3480 {
3481   PetscInt      *depthEnd;
3482   PetscInt       depth = 0, d, pStart, pEnd, p;
3483   PetscErrorCode ierr;
3484 
3485   PetscFunctionBegin;
3486   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3487   if (depth < 0) PetscFunctionReturn(0);
3488   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3489   /* Step 1: Expand chart */
3490   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3491   for (d = 0; d <= depth; ++d) {
3492     pEnd += depthShift[d];
3493     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3494   }
3495   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3496   /* Step 2: Set cone and support sizes */
3497   for (d = 0; d <= depth; ++d) {
3498     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3499     for (p = pStart; p < pEnd; ++p) {
3500       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3501       PetscInt size;
3502 
3503       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3504       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3505       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3506       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3507     }
3508   }
3509   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3510   PetscFunctionReturn(0);
3511 }
3512 
3513 #undef __FUNCT__
3514 #define __FUNCT__ "DMPlexShiftPoints_Private"
3515 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3516 {
3517   PetscInt      *depthEnd, *newpoints;
3518   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3519   PetscErrorCode ierr;
3520 
3521   PetscFunctionBegin;
3522   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3523   if (depth < 0) PetscFunctionReturn(0);
3524   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3525   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3526   for (d = 0; d <= depth; ++d) {
3527     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3528   }
3529   /* Step 5: Set cones and supports */
3530   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3531   for (p = pStart; p < pEnd; ++p) {
3532     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3533     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3534 
3535     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3536     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3537     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3538     for (i = 0; i < size; ++i) {
3539       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3540     }
3541     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3542     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3543     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3544     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3545     for (i = 0; i < size; ++i) {
3546       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3547     }
3548     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3549   }
3550   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3551   PetscFunctionReturn(0);
3552 }
3553 
3554 #undef __FUNCT__
3555 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3556 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3557 {
3558   PetscSection   coordSection, newCoordSection;
3559   Vec            coordinates, newCoordinates;
3560   PetscScalar   *coords, *newCoords;
3561   PetscInt      *depthEnd, coordSize;
3562   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3563   PetscErrorCode ierr;
3564 
3565   PetscFunctionBegin;
3566   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3567   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3568   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3569   for (d = 0; d <= depth; ++d) {
3570     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3571   }
3572   /* Step 8: Convert coordinates */
3573   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3574   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3575   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3576   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3577   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3578   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3579   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3580   for (v = vStartNew; v < vEndNew; ++v) {
3581     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3582     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3583   }
3584   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3585   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3586   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3587   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3588   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3589   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3590   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3591   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3592   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3593   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3594   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3595   for (v = vStart; v < vEnd; ++v) {
3596     PetscInt dof, off, noff, d;
3597 
3598     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3599     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3600     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3601     for (d = 0; d < dof; ++d) {
3602       newCoords[noff+d] = coords[off+d];
3603     }
3604   }
3605   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3606   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3607   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3608   PetscFunctionReturn(0);
3609 }
3610 
3611 #undef __FUNCT__
3612 #define __FUNCT__ "DMPlexShiftSF_Private"
3613 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3614 {
3615   PetscInt          *depthEnd;
3616   PetscInt           depth = 0, d;
3617   PetscSF            sfPoint, sfPointNew;
3618   const PetscSFNode *remotePoints;
3619   PetscSFNode       *gremotePoints;
3620   const PetscInt    *localPoints;
3621   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3622   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3623   PetscMPIInt        numProcs;
3624   PetscErrorCode     ierr;
3625 
3626   PetscFunctionBegin;
3627   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3628   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3629   for (d = 0; d <= depth; ++d) {
3630     totShift += depthShift[d];
3631     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3632   }
3633   /* Step 9: Convert pointSF */
3634   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3635   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3636   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3637   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3638   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3639   if (numRoots >= 0) {
3640     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3641     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3642     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3643     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3644     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3645     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3646     for (l = 0; l < numLeaves; ++l) {
3647       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3648       gremotePoints[l].rank  = remotePoints[l].rank;
3649       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3650     }
3651     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3652     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3653   }
3654   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3655   PetscFunctionReturn(0);
3656 }
3657 
3658 #undef __FUNCT__
3659 #define __FUNCT__ "DMPlexShiftLabels_Private"
3660 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3661 {
3662   PetscSF        sfPoint;
3663   DMLabel        vtkLabel, ghostLabel;
3664   PetscInt      *depthEnd;
3665   const PetscSFNode *leafRemote;
3666   const PetscInt    *leafLocal;
3667   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3668   PetscMPIInt    rank;
3669   PetscErrorCode ierr;
3670 
3671   PetscFunctionBegin;
3672   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3673   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3674   for (d = 0; d <= depth; ++d) {
3675     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3676   }
3677   /* Step 10: Convert labels */
3678   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3679   for (l = 0; l < numLabels; ++l) {
3680     DMLabel         label, newlabel;
3681     const char     *lname;
3682     PetscBool       isDepth;
3683     IS              valueIS;
3684     const PetscInt *values;
3685     PetscInt        numValues, val;
3686 
3687     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3688     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3689     if (isDepth) continue;
3690     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3691     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3692     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3693     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3694     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3695     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3696     for (val = 0; val < numValues; ++val) {
3697       IS              pointIS;
3698       const PetscInt *points;
3699       PetscInt        numPoints, p;
3700 
3701       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3702       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3703       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3704       for (p = 0; p < numPoints; ++p) {
3705         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3706 
3707         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3708       }
3709       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3710       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3711     }
3712     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3713     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3714   }
3715   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3716   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3717   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3718   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3719   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3720   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3721   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3722   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3723   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3724   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3725   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3726     for (; c < leafLocal[l] && c < cEnd; ++c) {
3727       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3728     }
3729     if (leafLocal[l] >= cEnd) break;
3730     if (leafRemote[l].rank == rank) {
3731       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3732     } else {
3733       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3734     }
3735   }
3736   for (; c < cEnd; ++c) {
3737     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3738   }
3739   if (0) {
3740     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3741     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3742     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3743   }
3744   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3745   for (f = fStart; f < fEnd; ++f) {
3746     PetscInt numCells;
3747 
3748     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3749     if (numCells < 2) {
3750       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3751     } else {
3752       const PetscInt *cells = PETSC_NULL;
3753       PetscInt        vA, vB;
3754 
3755       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3756       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3757       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3758       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3759     }
3760   }
3761   if (0) {
3762     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3763     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3764     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3765   }
3766   PetscFunctionReturn(0);
3767 }
3768 
3769 #undef __FUNCT__
3770 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3771 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3772 {
3773   DMLabel         label;
3774   IS              valueIS;
3775   const PetscInt *values;
3776   PetscInt       *depthShift;
3777   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3778   PetscErrorCode  ierr;
3779 
3780   PetscFunctionBegin;
3781   /* Count ghost cells */
3782   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3783   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3784   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3785   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3786   *numGhostCells = 0;
3787   for (fs = 0; fs < numFS; ++fs) {
3788     PetscInt numBdFaces;
3789 
3790     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3791     *numGhostCells += numBdFaces;
3792   }
3793   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3794   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3795   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3796   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3797   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3798   /* Step 3: Set cone/support sizes for new points */
3799   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3800   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3801     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3802   }
3803   for (fs = 0; fs < numFS; ++fs) {
3804     IS              faceIS;
3805     const PetscInt *faces;
3806     PetscInt        numFaces, f;
3807 
3808     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3809     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3810     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3811     for (f = 0; f < numFaces; ++f) {
3812       PetscInt size;
3813 
3814       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3815       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3816       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3817     }
3818     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3819     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3820   }
3821   /* Step 4: Setup ghosted DM */
3822   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3823   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3824   /* Step 6: Set cones and supports for new points */
3825   ghostCell = cEnd;
3826   for (fs = 0; fs < numFS; ++fs) {
3827     IS              faceIS;
3828     const PetscInt *faces;
3829     PetscInt        numFaces, f;
3830 
3831     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3832     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3833     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3834     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3835       PetscInt newFace = faces[f] + *numGhostCells;
3836 
3837       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3838       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3839     }
3840     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3841     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3842   }
3843   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3844   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3845   /* Step 7: Stratify */
3846   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3847   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3848   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3849   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3850   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3851   PetscFunctionReturn(0);
3852 }
3853 
3854 #undef __FUNCT__
3855 #define __FUNCT__ "DMPlexConstructGhostCells"
3856 /*@C
3857   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3858 
3859   Collective on dm
3860 
3861   Input Parameters:
3862 + dm - The original DM
3863 - labelName - The label specifying the boundary faces (this could be auto-generated)
3864 
3865   Output Parameters:
3866 + numGhostCells - The number of ghost cells added to the DM
3867 - dmGhosted - The new DM
3868 
3869   Level: developer
3870 
3871 .seealso: DMCreate()
3872 */
3873 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3874 {
3875   DM             gdm;
3876   PetscInt       dim;
3877   PetscErrorCode ierr;
3878 
3879   PetscFunctionBegin;
3880   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3881   PetscValidPointer(numGhostCells, 3);
3882   PetscValidPointer(dmGhosted, 4);
3883   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3884   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3885   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3886   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3887   switch (dim) {
3888   case 2:
3889     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3890     break;
3891   default:
3892     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3893   }
3894   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3895   *dmGhosted = gdm;
3896   PetscFunctionReturn(0);
3897 }
3898 
3899 #undef __FUNCT__
3900 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3901 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, const char labelName[], DM sdm)
3902 {
3903   MPI_Comm        comm = ((PetscObject) dm)->comm;
3904   DMLabel         label;
3905   IS              valueIS, svIS = PETSC_NULL, seIS = PETSC_NULL;
3906   const PetscInt *values, *splitVertices = PETSC_NULL, *splitEdges = PETSC_NULL;
3907   PetscSection    coordSection;
3908   Vec             coordinates;
3909   PetscScalar    *coords;
3910   PetscInt       *depthShift, *depthOffset, *pMaxNew, *coneNew, *supportNew;
3911   PetscInt        shift = 100, depth = 0, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numSplitVertices = 0, v, numSplitEdges = 0, numLabels, l;
3912   PetscErrorCode  ierr;
3913 
3914   PetscFunctionBegin;
3915   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3916   /* Count split points and add cohesive cells */
3917   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3918   if (label) {
3919     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3920     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3921     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3922     ierr = DMLabelGetStratumIS(label, 0, &svIS);CHKERRQ(ierr);
3923     if (svIS) {
3924       ierr = ISGetLocalSize(svIS, &numSplitVertices);CHKERRQ(ierr);
3925       ierr = ISGetIndices(svIS, &splitVertices);CHKERRQ(ierr);
3926     }
3927     ierr = DMLabelGetStratumIS(label, 1, &seIS);CHKERRQ(ierr);
3928     if (seIS) {
3929       ierr = ISGetLocalSize(seIS, &numSplitEdges);CHKERRQ(ierr);
3930       ierr = ISGetIndices(seIS, &splitEdges);CHKERRQ(ierr);
3931     }
3932   }
3933   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3934   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3935   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3936   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3937   for(d = 0; d <= depth; ++d) {
3938     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3939   }
3940   for(sp = 0; sp < numSP; ++sp) {
3941     if ((values[sp] < 0) || (values[sp] > depth)) continue;
3942     ierr = DMLabelGetStratumSize(label, values[sp], &depthShift[values[sp]]);CHKERRQ(ierr);
3943   }
3944   if (depth >= 0) {
3945     /* Calculate number of additional points */
3946     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3947     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3948     /* Calculate hybrid bound for each dimension */
3949     pMaxNew[0]       += depthShift[depth];
3950     if (depth > 1) {pMaxNew[dim-1] += depthShift[depth] + depthShift[0];}
3951     if (depth > 2) {pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];}
3952     /* Calculate point offset for each dimension */
3953     depthOffset[depth] = 0;
3954     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3955     if (depth > 1) {depthOffset[dim-1] = depthOffset[0]     + depthShift[0];}
3956     if (depth > 2) {depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];}
3957   }
3958   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3959   /* Step 3: Set cone/support sizes for new points */
3960   for(sp = 0; sp < numSP; ++sp) {
3961     const PetscInt  dep = values[sp];
3962     const PetscInt *points;
3963     IS              dimIS;
3964     PetscInt        numPoints, p;
3965 
3966     if ((values[sp] < 0) || (values[sp] > depth)) continue;
3967     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
3968     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
3969     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
3970     for(p = 0; p < numPoints; ++p) {
3971       const PetscInt  oldp   = points[p];
3972       const PetscInt  newp   = depthOffset[dep] + oldp;
3973       const PetscInt  splitp = pMaxNew[dep] + p;
3974       const PetscInt *support;
3975       PetscInt        coneSize, supportSize, q, e;
3976 
3977       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3978       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3979       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3980       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3981       if (dep == depth-1) {
3982         const PetscInt ccell = pMaxNew[depth] + p;
3983         /* Add cohesive cells, they are prisms */
3984         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3985       } else if (dep == 0) {
3986         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3987 
3988         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3989         /* Split old vertex: Edges in old split faces and new cohesive edge */
3990         for(e = 0, q = 0; e < supportSize; ++e) {
3991           PetscInt val;
3992 
3993           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3994           if ((val == 1) || (val == (shift + 1))) ++q;
3995         }
3996         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3997         /* Split new vertex: Edges in new split faces and new cohesive edge */
3998         for(e = 0, q = 0; e < supportSize; ++e) {
3999           PetscInt val;
4000 
4001           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4002           if ((val == 1) || (val == -(shift + 1))) ++q;
4003         }
4004         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4005         /* Add cohesive edges */
4006         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4007         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4008       }
4009     }
4010     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4011     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4012   }
4013   /* Step 4: Setup split DM */
4014   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4015   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4016   /* Step 6: Set cones and supports for new points */
4017   for(sp = 0; sp < numSP; ++sp) {
4018     const PetscInt  dep = values[sp];
4019     const PetscInt *points;
4020     IS              dimIS;
4021     PetscInt        numPoints, p;
4022 
4023     if ((values[sp] < 0) || (values[sp] > depth)) continue;
4024     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
4025     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4026     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4027     for(p = 0; p < numPoints; ++p) {
4028       const PetscInt  newp   = depthOffset[dep] + points[p];
4029       const PetscInt  splitp = pMaxNew[dep] + p;
4030       const PetscInt *cone, *support;
4031       PetscInt        coneSize, supportSize, q, v, e, s;
4032 
4033       ierr = DMPlexGetConeSize(dm, points[p], &coneSize);CHKERRQ(ierr);
4034       ierr = DMPlexGetCone(dm, points[p], &cone);CHKERRQ(ierr);
4035       ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4036       ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4037       if (dep == depth-1) {
4038         const PetscInt  ccell = pMaxNew[depth] + p;
4039         const PetscInt *supportF;
4040 
4041         /* Split face:       copy in old face to new face to start */
4042         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4043         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4044         /* Split old face:   old vertices in cone so no change */
4045         /* Split new face:   new vertices in cone */
4046         for(q = 0; q < coneSize; ++q) {
4047           ierr = PetscFindInt(cone[q], numSplitVertices, splitVertices, &v);CHKERRQ(ierr);
4048           coneNew[2+q] = pMaxNew[0] + v;
4049         }
4050         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4051         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4052         coneNew[0] = newp;
4053         coneNew[1] = splitp;
4054         for(q = 0; q < coneSize; ++q) {
4055           coneNew[2+q] = (pMaxNew[1] - pMaxNew[0]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4056         }
4057         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4058         for(s = 0; s < supportSize; ++s) {
4059           PetscInt val;
4060 
4061           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4062           if (val < 0) {
4063             const PetscInt *scone;
4064             PetscInt        sconeSize, sc;
4065 
4066             /* Split old face:   Replace negative side cell with cohesive cell */
4067             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4068             /* Negative cell: replace split face */
4069             ierr = DMPlexGetConeSize(sdm, support[s], &sconeSize);CHKERRQ(ierr);
4070             ierr = DMPlexGetCone(sdm, support[s], &scone);CHKERRQ(ierr);
4071             for(sc = 0; sc < sconeSize; ++sc) {
4072               if (scone[sc] == newp) {
4073                 ierr = DMPlexInsertCone(sdm, support[s], sc, splitp);CHKERRQ(ierr);
4074                 break;
4075               }
4076             }
4077           } else {
4078             /* Split new face:   Replace positive side cell with cohesive cell */
4079             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4080           }
4081         }
4082       } else if (dep == 0) {
4083         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4084 
4085         /* Split old vertex: Edges in old split faces and new cohesive edge */
4086         for(e = 0, q = 0; e < supportSize; ++e) {
4087           PetscInt val;
4088 
4089           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4090           if ((val == 1) || (val == (shift + 1))) {
4091             supportNew[q++] = depthOffset[1] + support[e];
4092           }
4093         }
4094         supportNew[q] = cedge;
4095         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4096         /* Split new vertex: Edges in new split faces and new cohesive edge */
4097         for(e = 0, q = 0; e < supportSize; ++e) {
4098           PetscInt val, edge;
4099 
4100           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4101           if (val == 1) {
4102             ierr = PetscFindInt(support[e], numSplitEdges, splitEdges, &edge);CHKERRQ(ierr);
4103             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4104             supportNew[q++] = pMaxNew[1] + edge;
4105           } else if (val == -(shift + 1)) {
4106             const PetscInt *scone;
4107             PetscInt        sconeSize, sc;
4108 
4109             supportNew[q++] = depthOffset[1] + support[e];
4110             /* Negative edge: replace split vertex */
4111             ierr = DMPlexGetConeSize(sdm, depthOffset[1] + support[e], &sconeSize);CHKERRQ(ierr);
4112             ierr = DMPlexGetCone(sdm, depthOffset[1] + support[e], &scone);CHKERRQ(ierr);
4113             for(sc = 0; sc < sconeSize; ++sc) {
4114               if (scone[sc] == newp) {
4115                 ierr = DMPlexInsertCone(sdm, depthOffset[1] + support[e], sc, splitp);CHKERRQ(ierr);
4116                 break;
4117               }
4118             }
4119             if (sc == sconeSize) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Edge %d does not contain split vertex %d", support[e], newp);
4120           }
4121         }
4122         supportNew[q] = cedge;
4123         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4124         /* Cohesive edge:    Old and new split vertex, punting on support */
4125         coneNew[0] = newp;
4126         coneNew[1] = splitp;
4127         ierr = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4128       }
4129     }
4130     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4131     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4132   }
4133   /* Step 7: Stratify */
4134   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4135   /* Step 8: Coordinates */
4136   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4137   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4138   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4139   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4140   for(v = 0; v < numSplitVertices; ++v) {
4141     const PetscInt newp   = depthOffset[0] + splitVertices[v];
4142     const PetscInt splitp = pMaxNew[0] + v;
4143     PetscInt       dof, off, soff, d;
4144 
4145     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4146     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4147     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4148     for(d = 0; d < dof; ++d) {
4149       coords[soff+d] = coords[off+d];
4150     }
4151   }
4152   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4153   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4154   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4155   /* Step 10: Labels */
4156   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4157   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4158   for(sp = 0; sp < numSP; ++sp) {
4159     const PetscInt  dep = values[sp];
4160     const PetscInt *points;
4161     IS              dimIS;
4162     PetscInt        numPoints, p;
4163 
4164     if ((values[sp] < 0) || (values[sp] > depth)) continue;
4165     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
4166     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4167     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4168     for(p = 0; p < numPoints; ++p) {
4169       const PetscInt newp   = depthOffset[dep] + points[p];
4170       const PetscInt splitp = pMaxNew[dep] + p;
4171 
4172       for (l = 0; l < numLabels; ++l) {
4173         DMLabel     label;
4174         const char *lname;
4175         PetscInt    val;
4176 
4177         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4178         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4179         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4180         if (val >= 0) {
4181           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4182           if (dep == 0) {
4183             const PetscInt cedge  = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4184             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4185           }
4186         }
4187       }
4188     }
4189     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4190     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4191   }
4192   if (label) {
4193     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4194     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4195   }
4196   if (svIS) {ierr = ISRestoreIndices(svIS, &splitVertices);CHKERRQ(ierr);}
4197   if (seIS) {ierr = ISRestoreIndices(seIS, &splitEdges);CHKERRQ(ierr);}
4198   ierr = ISDestroy(&svIS);CHKERRQ(ierr);
4199   ierr = ISDestroy(&seIS);CHKERRQ(ierr);
4200   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4201   PetscFunctionReturn(0);
4202 }
4203 
4204 #undef __FUNCT__
4205 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4206 /*@C
4207   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4208 
4209   Collective on dm
4210 
4211   Input Parameters:
4212 + dm - The original DM
4213 - labelName - The label specifying the boundary faces (this could be auto-generated)
4214 
4215   Output Parameters:
4216 - dmSplit - The new DM
4217 
4218   Level: developer
4219 
4220 .seealso: DMCreate()
4221 */
4222 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4223 {
4224   DM             sdm;
4225   PetscInt       dim;
4226   PetscErrorCode ierr;
4227 
4228   PetscFunctionBegin;
4229   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4230   PetscValidPointer(dmSplit, 4);
4231   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4232   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4233   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4234   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4235   switch(dim) {
4236   case 2:
4237   case 3:
4238     ierr = DMPlexConstructCohesiveCells_Private(dm, labelName, sdm);CHKERRQ(ierr);
4239     break;
4240   default:
4241     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4242   }
4243   *dmSplit = sdm;
4244   PetscFunctionReturn(0);
4245 }
4246 
4247 #undef __FUNCT__
4248 #define __FUNCT__ "DMLabelCohesiveComplete"
4249 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4250 {
4251   IS              dimIS;
4252   const PetscInt *points;
4253   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4254   PetscErrorCode  ierr;
4255 
4256   PetscFunctionBegin;
4257   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4258   /* Cell orientation for face gives the side of the fault */
4259   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4260   if (!dimIS) PetscFunctionReturn(0);
4261   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4262   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4263   for(p = 0; p < numPoints; ++p) {
4264     const PetscInt *support;
4265     PetscInt        supportSize, s;
4266 
4267     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4268     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4269     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4270     for(s = 0; s < supportSize; ++s) {
4271       const PetscInt *cone, *ornt;
4272       PetscInt        coneSize, c;
4273       PetscBool       pos = PETSC_TRUE;
4274 
4275       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4276       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4277       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4278       for(c = 0; c < coneSize; ++c) {
4279         if (cone[c] == points[p]) {
4280           if (ornt[c] >= 0) {
4281             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4282           } else {
4283             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4284             pos  = PETSC_FALSE;
4285           }
4286           break;
4287         }
4288       }
4289       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]);
4290       /* Put faces touching the fault in the label */
4291       for(c = 0; c < coneSize; ++c) {
4292         const PetscInt point = cone[c];
4293 
4294         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4295         if (val == -1) {
4296           PetscInt *closure = PETSC_NULL;
4297           PetscInt  closureSize, cl;
4298 
4299           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4300           for (cl = 0; cl < closureSize*2; cl += 2) {
4301             const PetscInt clp = closure[cl];
4302 
4303             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4304             if ((val >= 0) && (val < dim-1)) {
4305               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4306               break;
4307             }
4308           }
4309           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4310         }
4311       }
4312     }
4313   }
4314   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4315   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4316   /* Search for other cells/faces/edges connected to the fault by a vertex */
4317   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4318   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4319   if (!dimIS) PetscFunctionReturn(0);
4320   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4321   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4322   for(p = 0; p < numPoints; ++p) {
4323     PetscInt *star = PETSC_NULL;
4324     PetscInt  starSize, s;
4325     PetscInt  again = 1; /* 0: Finished 1: Keep iterating after a change 2: No change */
4326 
4327     /* First mark cells connected to the fault */
4328     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4329     while (again) {
4330       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4331       again = 0;
4332       for (s = 0; s < starSize*2; s += 2) {
4333         const PetscInt  point = star[s];
4334         const PetscInt *cone;
4335         PetscInt        coneSize, c;
4336 
4337         if ((point < cStart) || (point >= cEnd)) continue;
4338         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4339         if (val != -1) continue;
4340         again = 2;
4341         ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4342         ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4343         for(c = 0; c < coneSize; ++c) {
4344           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4345           if (val != -1) {
4346             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);
4347             if (val > 0) {
4348               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4349             } else {
4350               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4351             }
4352             again = 1;
4353             break;
4354           }
4355         }
4356       }
4357     }
4358     /* Classify the rest by cell membership */
4359     for (s = 0; s < starSize*2; s += 2) {
4360       const PetscInt point = star[s];
4361 
4362       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4363       if (val == -1) {
4364         PetscInt *sstar = PETSC_NULL;
4365         PetscInt  sstarSize, ss;
4366         PetscBool marked = PETSC_FALSE;
4367 
4368         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4369         for (ss = 0; ss < sstarSize*2; ss += 2) {
4370           const PetscInt spoint = sstar[ss];
4371 
4372           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4373           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4374           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4375           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4376           if (val > 0) {
4377             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4378           } else {
4379             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4380           }
4381           marked = PETSC_TRUE;
4382           break;
4383         }
4384         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4385         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4386       }
4387     }
4388     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4389   }
4390   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4391   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4392   PetscFunctionReturn(0);
4393 }
4394 
4395 #undef __FUNCT__
4396 #define __FUNCT__ "DMPlexInterpolate_2D"
4397 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4398 {
4399   DM             idm;
4400   DM_Plex       *mesh;
4401   PetscHashIJ    edgeTable;
4402   PetscInt      *off;
4403   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4404   PetscInt       numEdges, firstEdge, edge, e;
4405   PetscErrorCode ierr;
4406 
4407   PetscFunctionBegin;
4408   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4409   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4410   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4411   numCells    = cEnd - cStart;
4412   numVertices = vEnd - vStart;
4413   firstEdge   = numCells + numVertices;
4414   numEdges    = 0 ;
4415   /* Count edges using algorithm from CreateNeighborCSR */
4416   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4417   if (off) {
4418     PetscInt numCorners = 0;
4419 
4420     numEdges = off[numCells]/2;
4421 #if 0
4422     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4423     numEdges += 3*numCells - off[numCells];
4424 #else
4425     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4426     for (c = cStart; c < cEnd; ++c) {
4427       PetscInt coneSize;
4428 
4429       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4430       numCorners += coneSize;
4431     }
4432     numEdges += numCorners - off[numCells];
4433 #endif
4434   }
4435 #if 0
4436   /* Check Euler characteristic V - E + F = 1 */
4437   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4438 #endif
4439   /* Create interpolated mesh */
4440   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4441   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4442   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4443   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4444   for (c = 0; c < numCells; ++c) {
4445     PetscInt numCorners;
4446 
4447     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4448     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4449   }
4450   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4451     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4452   }
4453   ierr = DMSetUp(idm);CHKERRQ(ierr);
4454   /* Get edge cones from subsets of cell vertices */
4455   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4456   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4457 
4458   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4459     const PetscInt *cellFaces;
4460     PetscInt        numCellFaces, faceSize, cf;
4461 
4462     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4463     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4464     for (cf = 0; cf < numCellFaces; ++cf) {
4465 #if 1
4466       PetscHashIJKey key;
4467 
4468       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4469       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4470       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4471       if (e < 0) {
4472         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4473         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4474         e    = edge++;
4475       }
4476 #else
4477       PetscBool found = PETSC_FALSE;
4478 
4479       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4480       for (e = firstEdge; e < edge; ++e) {
4481         const PetscInt *cone;
4482 
4483         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4484         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4485             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4486           found = PETSC_TRUE;
4487           break;
4488         }
4489       }
4490       if (!found) {
4491         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4492         ++edge;
4493       }
4494 #endif
4495       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4496     }
4497   }
4498   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4499   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4500   ierr = PetscFree(off);CHKERRQ(ierr);
4501   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4502   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4503   mesh = (DM_Plex *) (idm)->data;
4504   /* Orient edges */
4505   for (c = 0; c < numCells; ++c) {
4506     const PetscInt *cone = PETSC_NULL, *cellFaces;
4507     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4508 
4509     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4510     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4511     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4512     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4513     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4514     for (cf = 0; cf < numCellFaces; ++cf) {
4515       const PetscInt *econe = PETSC_NULL;
4516       PetscInt        esize;
4517 
4518       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4519       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4520       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]);
4521       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4522         /* Correctly oriented */
4523         mesh->coneOrientations[coff+cf] = 0;
4524       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4525         /* Start at index 1, and reverse orientation */
4526         mesh->coneOrientations[coff+cf] = -(1+1);
4527       }
4528     }
4529   }
4530   *dmInt  = idm;
4531   PetscFunctionReturn(0);
4532 }
4533 
4534 #undef __FUNCT__
4535 #define __FUNCT__ "DMPlexInterpolate_3D"
4536 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4537 {
4538   DM             idm, fdm;
4539   DM_Plex    *mesh;
4540   PetscInt      *off;
4541   const PetscInt numCorners = 4;
4542   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4543   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4544   PetscErrorCode ierr;
4545 
4546   PetscFunctionBegin;
4547   {
4548     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4549     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4550     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4551   }
4552   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4553   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4554   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4555   numCells    = cEnd - cStart;
4556   numVertices = vEnd - vStart;
4557   firstFace   = numCells + numVertices;
4558   numFaces    = 0 ;
4559   /* Count faces using algorithm from CreateNeighborCSR */
4560   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4561   if (off) {
4562     numFaces = off[numCells]/2;
4563     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4564     numFaces += 4*numCells - off[numCells];
4565   }
4566   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4567   firstEdge = firstFace + numFaces;
4568   numEdges  = numVertices + numFaces - numCells - 1;
4569   /* Create interpolated mesh */
4570   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4571   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4572   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4573   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4574   for (c = 0; c < numCells; ++c) {
4575     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4576   }
4577   for (f = firstFace; f < firstFace+numFaces; ++f) {
4578     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4579   }
4580   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4581     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4582   }
4583   ierr = DMSetUp(idm);CHKERRQ(ierr);
4584   /* Get face cones from subsets of cell vertices */
4585   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4586   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4587   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4588   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4589   for (f = firstFace; f < firstFace+numFaces; ++f) {
4590     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4591   }
4592   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4593   for (c = 0, face = firstFace; c < numCells; ++c) {
4594     const PetscInt *cellFaces;
4595     PetscInt        numCellFaces, faceSize, cf;
4596 
4597     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4598     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4599     for (cf = 0; cf < numCellFaces; ++cf) {
4600       PetscBool found = PETSC_FALSE;
4601 
4602       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4603       for (f = firstFace; f < face; ++f) {
4604         const PetscInt *cone = PETSC_NULL;
4605 
4606         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4607         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4608             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4609             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4610             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4611             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4612             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4613           found = PETSC_TRUE;
4614           break;
4615         }
4616       }
4617       if (!found) {
4618         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4619         /* Save the vertices for orientation calculation */
4620         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4621         ++face;
4622       }
4623       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4624     }
4625   }
4626   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4627   /* Get edge cones from subsets of face vertices */
4628   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4629     const PetscInt *cellFaces;
4630     PetscInt        numCellFaces, faceSize, cf;
4631 
4632     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4633     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4634     for (cf = 0; cf < numCellFaces; ++cf) {
4635       PetscBool found = PETSC_FALSE;
4636 
4637       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4638       for (e = firstEdge; e < edge; ++e) {
4639         const PetscInt *cone = PETSC_NULL;
4640 
4641         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4642         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4643             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4644           found = PETSC_TRUE;
4645           break;
4646         }
4647       }
4648       if (!found) {
4649         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4650         ++edge;
4651       }
4652       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4653     }
4654   }
4655   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4656   ierr = PetscFree(off);CHKERRQ(ierr);
4657   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4658   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4659   mesh = (DM_Plex *) (idm)->data;
4660   /* Orient edges */
4661   for (f = firstFace; f < firstFace+numFaces; ++f) {
4662     const PetscInt *cone, *cellFaces;
4663     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4664 
4665     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4666     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4667     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4668     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4669     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4670     for (cf = 0; cf < numCellFaces; ++cf) {
4671       const PetscInt *econe;
4672       PetscInt        esize;
4673 
4674       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4675       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4676       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]);
4677       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4678         /* Correctly oriented */
4679         mesh->coneOrientations[coff+cf] = 0;
4680       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4681         /* Start at index 1, and reverse orientation */
4682         mesh->coneOrientations[coff+cf] = -(1+1);
4683       }
4684     }
4685   }
4686   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4687   /* Orient faces */
4688   for (c = 0; c < numCells; ++c) {
4689     const PetscInt *cone, *cellFaces;
4690     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4691 
4692     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4693     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4694     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4695     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4696     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4697     for (cf = 0; cf < numCellFaces; ++cf) {
4698       PetscInt *origClosure = PETSC_NULL, *closure;
4699       PetscInt  closureSize, i;
4700 
4701       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4702       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4703       for (i = 4; i < 7; ++i) {
4704         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);
4705       }
4706       closure = &origClosure[4*2];
4707       /* Remember that this is the orientation for edges, not vertices */
4708       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4709         /* Correctly oriented */
4710         mesh->coneOrientations[coff+cf] = 0;
4711       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4712         /* Shifted by 1 */
4713         mesh->coneOrientations[coff+cf] = 1;
4714       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4715         /* Shifted by 2 */
4716         mesh->coneOrientations[coff+cf] = 2;
4717       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4718         /* Start at edge 1, and reverse orientation */
4719         mesh->coneOrientations[coff+cf] = -(1+1);
4720       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4721         /* Start at index 0, and reverse orientation */
4722         mesh->coneOrientations[coff+cf] = -(0+1);
4723       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4724         /* Start at index 2, and reverse orientation */
4725         mesh->coneOrientations[coff+cf] = -(2+1);
4726       } 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);
4727       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4728     }
4729   }
4730   {
4731     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4732     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4733     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4734   }
4735   *dmInt  = idm;
4736   PetscFunctionReturn(0);
4737 }
4738 
4739 #undef __FUNCT__
4740 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4741 /*
4742   This takes as input the common mesh generator output, a list of the vertices for each cell
4743 */
4744 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4745 {
4746   PetscInt      *cone, c, p;
4747   PetscErrorCode ierr;
4748 
4749   PetscFunctionBegin;
4750   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4751   for (c = 0; c < numCells; ++c) {
4752     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4753   }
4754   ierr = DMSetUp(dm);CHKERRQ(ierr);
4755   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4756   for (c = 0; c < numCells; ++c) {
4757     for (p = 0; p < numCorners; ++p) {
4758       cone[p] = cells[c*numCorners+p]+numCells;
4759     }
4760     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4761   }
4762   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4763   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4764   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4765   PetscFunctionReturn(0);
4766 }
4767 
4768 #undef __FUNCT__
4769 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4770 /*
4771   This takes as input the coordinates for each vertex
4772 */
4773 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4774 {
4775   PetscSection   coordSection;
4776   Vec            coordinates;
4777   PetscScalar   *coords;
4778   PetscInt       coordSize, v, d;
4779   PetscErrorCode ierr;
4780 
4781   PetscFunctionBegin;
4782   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4783   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4784   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4785   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4786   for (v = numCells; v < numCells+numVertices; ++v) {
4787     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4788     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4789   }
4790   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4791   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4792   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4793   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4794   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4795   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4796   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4797   for (v = 0; v < numVertices; ++v) {
4798     for (d = 0; d < spaceDim; ++d) {
4799       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4800     }
4801   }
4802   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4803   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4804   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4805   PetscFunctionReturn(0);
4806 }
4807 
4808 #undef __FUNCT__
4809 #define __FUNCT__ "DMPlexCreateFromCellList"
4810 /*
4811   This takes as input the common mesh generator output, a list of the vertices for each cell
4812 */
4813 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4814 {
4815   PetscErrorCode ierr;
4816 
4817   PetscFunctionBegin;
4818   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4819   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4820   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4821   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4822   if (interpolate) {
4823     DM idm;
4824 
4825     switch (dim) {
4826     case 2:
4827       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4828     case 3:
4829       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4830     default:
4831       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4832     }
4833     ierr = DMDestroy(dm);CHKERRQ(ierr);
4834     *dm  = idm;
4835   }
4836   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4837   PetscFunctionReturn(0);
4838 }
4839 
4840 #if defined(PETSC_HAVE_TRIANGLE)
4841 #include <triangle.h>
4842 
4843 #undef __FUNCT__
4844 #define __FUNCT__ "InitInput_Triangle"
4845 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4846 {
4847   PetscFunctionBegin;
4848   inputCtx->numberofpoints = 0;
4849   inputCtx->numberofpointattributes = 0;
4850   inputCtx->pointlist = PETSC_NULL;
4851   inputCtx->pointattributelist = PETSC_NULL;
4852   inputCtx->pointmarkerlist = PETSC_NULL;
4853   inputCtx->numberofsegments = 0;
4854   inputCtx->segmentlist = PETSC_NULL;
4855   inputCtx->segmentmarkerlist = PETSC_NULL;
4856   inputCtx->numberoftriangleattributes = 0;
4857   inputCtx->trianglelist = PETSC_NULL;
4858   inputCtx->numberofholes = 0;
4859   inputCtx->holelist = PETSC_NULL;
4860   inputCtx->numberofregions = 0;
4861   inputCtx->regionlist = PETSC_NULL;
4862   PetscFunctionReturn(0);
4863 }
4864 
4865 #undef __FUNCT__
4866 #define __FUNCT__ "InitOutput_Triangle"
4867 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4868 {
4869   PetscFunctionBegin;
4870   outputCtx->numberofpoints = 0;
4871   outputCtx->pointlist = PETSC_NULL;
4872   outputCtx->pointattributelist = PETSC_NULL;
4873   outputCtx->pointmarkerlist = PETSC_NULL;
4874   outputCtx->numberoftriangles = 0;
4875   outputCtx->trianglelist = PETSC_NULL;
4876   outputCtx->triangleattributelist = PETSC_NULL;
4877   outputCtx->neighborlist = PETSC_NULL;
4878   outputCtx->segmentlist = PETSC_NULL;
4879   outputCtx->segmentmarkerlist = PETSC_NULL;
4880   outputCtx->numberofedges = 0;
4881   outputCtx->edgelist = PETSC_NULL;
4882   outputCtx->edgemarkerlist = PETSC_NULL;
4883   PetscFunctionReturn(0);
4884 }
4885 
4886 #undef __FUNCT__
4887 #define __FUNCT__ "FiniOutput_Triangle"
4888 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4889 {
4890   PetscFunctionBegin;
4891   free(outputCtx->pointmarkerlist);
4892   free(outputCtx->edgelist);
4893   free(outputCtx->edgemarkerlist);
4894   free(outputCtx->trianglelist);
4895   free(outputCtx->neighborlist);
4896   PetscFunctionReturn(0);
4897 }
4898 
4899 #undef __FUNCT__
4900 #define __FUNCT__ "DMPlexGenerate_Triangle"
4901 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4902 {
4903   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4904   PetscInt             dim              = 2;
4905   const PetscBool      createConvexHull = PETSC_FALSE;
4906   const PetscBool      constrained      = PETSC_FALSE;
4907   struct triangulateio in;
4908   struct triangulateio out;
4909   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4910   PetscMPIInt          rank;
4911   PetscErrorCode       ierr;
4912 
4913   PetscFunctionBegin;
4914   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4915   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4916   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4917   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4918   in.numberofpoints = vEnd - vStart;
4919   if (in.numberofpoints > 0) {
4920     PetscSection coordSection;
4921     Vec          coordinates;
4922     PetscScalar *array;
4923 
4924     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4925     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4926     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4927     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4928     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4929     for (v = vStart; v < vEnd; ++v) {
4930       const PetscInt idx = v - vStart;
4931       PetscInt       off, d;
4932 
4933       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4934       for (d = 0; d < dim; ++d) {
4935         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4936       }
4937       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4938     }
4939     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4940   }
4941   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4942   in.numberofsegments = eEnd - eStart;
4943   if (in.numberofsegments > 0) {
4944     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4945     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4946     for (e = eStart; e < eEnd; ++e) {
4947       const PetscInt  idx = e - eStart;
4948       const PetscInt *cone;
4949 
4950       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4951       in.segmentlist[idx*2+0] = cone[0] - vStart;
4952       in.segmentlist[idx*2+1] = cone[1] - vStart;
4953       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4954     }
4955   }
4956 #if 0 /* Do not currently support holes */
4957   PetscReal *holeCoords;
4958   PetscInt   h, d;
4959 
4960   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4961   if (in.numberofholes > 0) {
4962     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4963     for (h = 0; h < in.numberofholes; ++h) {
4964       for (d = 0; d < dim; ++d) {
4965         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4966       }
4967     }
4968   }
4969 #endif
4970   if (!rank) {
4971     char args[32];
4972 
4973     /* Take away 'Q' for verbose output */
4974     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4975     if (createConvexHull) {
4976       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4977     }
4978     if (constrained) {
4979       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4980     }
4981     triangulate(args, &in, &out, PETSC_NULL);
4982   }
4983   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4984   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4985   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4986   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4987   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4988 
4989   {
4990     const PetscInt numCorners  = 3;
4991     const PetscInt numCells    = out.numberoftriangles;
4992     const PetscInt numVertices = out.numberofpoints;
4993     const int     *cells       = out.trianglelist;
4994     const double  *meshCoords  = out.pointlist;
4995 
4996     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4997     /* Set labels */
4998     for (v = 0; v < numVertices; ++v) {
4999       if (out.pointmarkerlist[v]) {
5000         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5001       }
5002     }
5003     if (interpolate) {
5004       for (e = 0; e < out.numberofedges; e++) {
5005         if (out.edgemarkerlist[e]) {
5006           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5007           const PetscInt *edges;
5008           PetscInt        numEdges;
5009 
5010           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5011           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5012           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5013           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5014         }
5015       }
5016     }
5017     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5018   }
5019 #if 0 /* Do not currently support holes */
5020   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5021 #endif
5022   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5023   PetscFunctionReturn(0);
5024 }
5025 
5026 #undef __FUNCT__
5027 #define __FUNCT__ "DMPlexRefine_Triangle"
5028 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5029 {
5030   MPI_Comm             comm = ((PetscObject) dm)->comm;
5031   PetscInt             dim  = 2;
5032   struct triangulateio in;
5033   struct triangulateio out;
5034   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5035   PetscMPIInt          rank;
5036   PetscErrorCode       ierr;
5037 
5038   PetscFunctionBegin;
5039   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5040   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5041   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5042   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5043   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5044   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5045   in.numberofpoints = vEnd - vStart;
5046   if (in.numberofpoints > 0) {
5047     PetscSection coordSection;
5048     Vec          coordinates;
5049     PetscScalar *array;
5050 
5051     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5052     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5053     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5054     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5055     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5056     for (v = vStart; v < vEnd; ++v) {
5057       const PetscInt idx = v - vStart;
5058       PetscInt       off, d;
5059 
5060       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5061       for (d = 0; d < dim; ++d) {
5062         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5063       }
5064       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5065     }
5066     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5067   }
5068   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5069   in.numberofcorners   = 3;
5070   in.numberoftriangles = cEnd - cStart;
5071   in.trianglearealist  = (double *) maxVolumes;
5072   if (in.numberoftriangles > 0) {
5073     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5074     for (c = cStart; c < cEnd; ++c) {
5075       const PetscInt idx     = c - cStart;
5076       PetscInt      *closure = PETSC_NULL;
5077       PetscInt       closureSize;
5078 
5079       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5080       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5081       for (v = 0; v < 3; ++v) {
5082         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5083       }
5084       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5085     }
5086   }
5087   /* TODO: Segment markers are missing on input */
5088 #if 0 /* Do not currently support holes */
5089   PetscReal *holeCoords;
5090   PetscInt   h, d;
5091 
5092   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5093   if (in.numberofholes > 0) {
5094     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5095     for (h = 0; h < in.numberofholes; ++h) {
5096       for (d = 0; d < dim; ++d) {
5097         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5098       }
5099     }
5100   }
5101 #endif
5102   if (!rank) {
5103     char args[32];
5104 
5105     /* Take away 'Q' for verbose output */
5106     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5107     triangulate(args, &in, &out, PETSC_NULL);
5108   }
5109   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5110   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5111   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5112   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5113   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5114 
5115   {
5116     const PetscInt numCorners  = 3;
5117     const PetscInt numCells    = out.numberoftriangles;
5118     const PetscInt numVertices = out.numberofpoints;
5119     const int     *cells       = out.trianglelist;
5120     const double  *meshCoords  = out.pointlist;
5121     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5122 
5123     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5124     /* Set labels */
5125     for (v = 0; v < numVertices; ++v) {
5126       if (out.pointmarkerlist[v]) {
5127         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5128       }
5129     }
5130     if (interpolate) {
5131       PetscInt e;
5132 
5133       for (e = 0; e < out.numberofedges; e++) {
5134         if (out.edgemarkerlist[e]) {
5135           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5136           const PetscInt *edges;
5137           PetscInt        numEdges;
5138 
5139           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5140           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5141           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5142           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5143         }
5144       }
5145     }
5146     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5147   }
5148 #if 0 /* Do not currently support holes */
5149   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5150 #endif
5151   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5152   PetscFunctionReturn(0);
5153 }
5154 #endif
5155 
5156 #if defined(PETSC_HAVE_TETGEN)
5157 #include <tetgen.h>
5158 #undef __FUNCT__
5159 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5160 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5161 {
5162   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5163   const PetscInt dim  = 3;
5164   ::tetgenio     in;
5165   ::tetgenio     out;
5166   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5167   PetscMPIInt    rank;
5168   PetscErrorCode ierr;
5169 
5170   PetscFunctionBegin;
5171   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5172   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5173   in.numberofpoints = vEnd - vStart;
5174   if (in.numberofpoints > 0) {
5175     PetscSection coordSection;
5176     Vec          coordinates;
5177     PetscScalar *array;
5178 
5179     in.pointlist       = new double[in.numberofpoints*dim];
5180     in.pointmarkerlist = new int[in.numberofpoints];
5181     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5182     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5183     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5184     for (v = vStart; v < vEnd; ++v) {
5185       const PetscInt idx = v - vStart;
5186       PetscInt       off, d;
5187 
5188       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5189       for (d = 0; d < dim; ++d) {
5190         in.pointlist[idx*dim + d] = array[off+d];
5191       }
5192       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5193     }
5194     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5195   }
5196   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5197   in.numberoffacets = fEnd - fStart;
5198   if (in.numberoffacets > 0) {
5199     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5200     in.facetmarkerlist = new int[in.numberoffacets];
5201     for (f = fStart; f < fEnd; ++f) {
5202       const PetscInt idx    = f - fStart;
5203       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5204 
5205       in.facetlist[idx].numberofpolygons = 1;
5206       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5207       in.facetlist[idx].numberofholes    = 0;
5208       in.facetlist[idx].holelist         = NULL;
5209 
5210       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5211       for (p = 0; p < numPoints*2; p += 2) {
5212         const PetscInt point = points[p];
5213         if ((point >= vStart) && (point < vEnd)) {
5214           points[numVertices++] = point;
5215         }
5216       }
5217 
5218       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5219       poly->numberofvertices = numVertices;
5220       poly->vertexlist       = new int[poly->numberofvertices];
5221       for (v = 0; v < numVertices; ++v) {
5222         const PetscInt vIdx = points[v] - vStart;
5223         poly->vertexlist[v] = vIdx;
5224       }
5225       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5226       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5227     }
5228   }
5229   if (!rank) {
5230     char args[32];
5231 
5232     /* Take away 'Q' for verbose output */
5233     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5234     ::tetrahedralize(args, &in, &out);
5235   }
5236   {
5237     const PetscInt numCorners  = 4;
5238     const PetscInt numCells    = out.numberoftetrahedra;
5239     const PetscInt numVertices = out.numberofpoints;
5240     const int     *cells       = out.tetrahedronlist;
5241     const double  *meshCoords  = out.pointlist;
5242 
5243     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5244     /* Set labels */
5245     for (v = 0; v < numVertices; ++v) {
5246       if (out.pointmarkerlist[v]) {
5247         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5248       }
5249     }
5250     if (interpolate) {
5251       PetscInt e;
5252 
5253       for (e = 0; e < out.numberofedges; e++) {
5254         if (out.edgemarkerlist[e]) {
5255           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5256           const PetscInt *edges;
5257           PetscInt        numEdges;
5258 
5259           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5260           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5261           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5262           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5263         }
5264       }
5265       for (f = 0; f < out.numberoftrifaces; f++) {
5266         if (out.trifacemarkerlist[f]) {
5267           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5268           const PetscInt *faces;
5269           PetscInt        numFaces;
5270 
5271           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5272           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5273           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5274           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5275         }
5276       }
5277     }
5278     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5279   }
5280   PetscFunctionReturn(0);
5281 }
5282 
5283 #undef __FUNCT__
5284 #define __FUNCT__ "DMPlexRefine_Tetgen"
5285 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5286 {
5287   MPI_Comm       comm = ((PetscObject) dm)->comm;
5288   const PetscInt dim  = 3;
5289   ::tetgenio     in;
5290   ::tetgenio     out;
5291   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5292   PetscMPIInt    rank;
5293   PetscErrorCode ierr;
5294 
5295   PetscFunctionBegin;
5296   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5297   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5298   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5299   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5300   in.numberofpoints = vEnd - vStart;
5301   if (in.numberofpoints > 0) {
5302     PetscSection coordSection;
5303     Vec          coordinates;
5304     PetscScalar *array;
5305 
5306     in.pointlist       = new double[in.numberofpoints*dim];
5307     in.pointmarkerlist = new int[in.numberofpoints];
5308     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5309     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5310     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5311     for (v = vStart; v < vEnd; ++v) {
5312       const PetscInt idx = v - vStart;
5313       PetscInt       off, d;
5314 
5315       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5316       for (d = 0; d < dim; ++d) {
5317         in.pointlist[idx*dim + d] = array[off+d];
5318       }
5319       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5320     }
5321     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5322   }
5323   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5324   in.numberofcorners       = 4;
5325   in.numberoftetrahedra    = cEnd - cStart;
5326   in.tetrahedronvolumelist = (double *) maxVolumes;
5327   if (in.numberoftetrahedra > 0) {
5328     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5329     for (c = cStart; c < cEnd; ++c) {
5330       const PetscInt idx     = c - cStart;
5331       PetscInt      *closure = PETSC_NULL;
5332       PetscInt       closureSize;
5333 
5334       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5335       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5336       for (v = 0; v < 4; ++v) {
5337         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5338       }
5339       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5340     }
5341   }
5342   /* TODO: Put in boundary faces with markers */
5343   if (!rank) {
5344     char args[32];
5345 
5346     /* Take away 'Q' for verbose output */
5347     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5348     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5349     ::tetrahedralize(args, &in, &out);
5350   }
5351   in.tetrahedronvolumelist = NULL;
5352 
5353   {
5354     const PetscInt numCorners  = 4;
5355     const PetscInt numCells    = out.numberoftetrahedra;
5356     const PetscInt numVertices = out.numberofpoints;
5357     const int     *cells       = out.tetrahedronlist;
5358     const double  *meshCoords  = out.pointlist;
5359     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5360 
5361     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5362     /* Set labels */
5363     for (v = 0; v < numVertices; ++v) {
5364       if (out.pointmarkerlist[v]) {
5365         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5366       }
5367     }
5368     if (interpolate) {
5369       PetscInt e, f;
5370 
5371       for (e = 0; e < out.numberofedges; e++) {
5372         if (out.edgemarkerlist[e]) {
5373           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5374           const PetscInt *edges;
5375           PetscInt        numEdges;
5376 
5377           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5378           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5379           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5380           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5381         }
5382       }
5383       for (f = 0; f < out.numberoftrifaces; f++) {
5384         if (out.trifacemarkerlist[f]) {
5385           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5386           const PetscInt *faces;
5387           PetscInt        numFaces;
5388 
5389           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5390           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5391           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5392           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5393         }
5394       }
5395     }
5396     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5397   }
5398   PetscFunctionReturn(0);
5399 }
5400 #endif
5401 
5402 #if defined(PETSC_HAVE_CTETGEN)
5403 #include "ctetgen.h"
5404 
5405 #undef __FUNCT__
5406 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5407 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5408 {
5409   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5410   const PetscInt dim  = 3;
5411   PLC           *in, *out;
5412   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5413   PetscMPIInt    rank;
5414   PetscErrorCode ierr;
5415 
5416   PetscFunctionBegin;
5417   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5418   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5419   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5420   ierr = PLCCreate(&in);CHKERRQ(ierr);
5421   ierr = PLCCreate(&out);CHKERRQ(ierr);
5422   in->numberofpoints = vEnd - vStart;
5423   if (in->numberofpoints > 0) {
5424     PetscSection coordSection;
5425     Vec          coordinates;
5426     PetscScalar *array;
5427 
5428     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5429     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5430     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5431     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5432     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5433     for (v = vStart; v < vEnd; ++v) {
5434       const PetscInt idx = v - vStart;
5435       PetscInt       off, d, m;
5436 
5437       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5438       for (d = 0; d < dim; ++d) {
5439         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5440       }
5441       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5442       in->pointmarkerlist[idx] = (int) m;
5443     }
5444     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5445   }
5446   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5447   in->numberoffacets = fEnd - fStart;
5448   if (in->numberoffacets > 0) {
5449     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5450     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5451     for (f = fStart; f < fEnd; ++f) {
5452       const PetscInt idx    = f - fStart;
5453       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5454       polygon       *poly;
5455 
5456       in->facetlist[idx].numberofpolygons = 1;
5457       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5458       in->facetlist[idx].numberofholes    = 0;
5459       in->facetlist[idx].holelist         = PETSC_NULL;
5460 
5461       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5462       for (p = 0; p < numPoints*2; p += 2) {
5463         const PetscInt point = points[p];
5464         if ((point >= vStart) && (point < vEnd)) {
5465           points[numVertices++] = point;
5466         }
5467       }
5468 
5469       poly = in->facetlist[idx].polygonlist;
5470       poly->numberofvertices = numVertices;
5471       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5472       for (v = 0; v < numVertices; ++v) {
5473         const PetscInt vIdx = points[v] - vStart;
5474         poly->vertexlist[v] = vIdx;
5475       }
5476       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5477       in->facetmarkerlist[idx] = (int) m;
5478       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5479     }
5480   }
5481   if (!rank) {
5482     TetGenOpts t;
5483 
5484     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5485     t.in        = boundary; /* Should go away */
5486     t.plc       = 1;
5487     t.quality   = 1;
5488     t.edgesout  = 1;
5489     t.zeroindex = 1;
5490     t.quiet     = 1;
5491     t.verbose   = verbose;
5492     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5493     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5494   }
5495   {
5496     const PetscInt numCorners  = 4;
5497     const PetscInt numCells    = out->numberoftetrahedra;
5498     const PetscInt numVertices = out->numberofpoints;
5499     const int     *cells       = out->tetrahedronlist;
5500     const double  *meshCoords  = out->pointlist;
5501 
5502     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5503     /* Set labels */
5504     for (v = 0; v < numVertices; ++v) {
5505       if (out->pointmarkerlist[v]) {
5506         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5507       }
5508     }
5509     if (interpolate) {
5510       PetscInt e;
5511 
5512       for (e = 0; e < out->numberofedges; e++) {
5513         if (out->edgemarkerlist[e]) {
5514           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5515           const PetscInt *edges;
5516           PetscInt        numEdges;
5517 
5518           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5519           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5520           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5521           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5522         }
5523       }
5524       for (f = 0; f < out->numberoftrifaces; f++) {
5525         if (out->trifacemarkerlist[f]) {
5526           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5527           const PetscInt *faces;
5528           PetscInt        numFaces;
5529 
5530           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5531           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5532           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5533           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5534         }
5535       }
5536     }
5537     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5538   }
5539 
5540   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5541   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5542   PetscFunctionReturn(0);
5543 }
5544 
5545 #undef __FUNCT__
5546 #define __FUNCT__ "DMPlexRefine_CTetgen"
5547 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5548 {
5549   MPI_Comm       comm = ((PetscObject) dm)->comm;
5550   const PetscInt dim  = 3;
5551   PLC           *in, *out;
5552   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5553   PetscMPIInt    rank;
5554   PetscErrorCode ierr;
5555 
5556   PetscFunctionBegin;
5557   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5558   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5559   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5560   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5561   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5562   ierr = PLCCreate(&in);CHKERRQ(ierr);
5563   ierr = PLCCreate(&out);CHKERRQ(ierr);
5564   in->numberofpoints = vEnd - vStart;
5565   if (in->numberofpoints > 0) {
5566     PetscSection coordSection;
5567     Vec          coordinates;
5568     PetscScalar *array;
5569 
5570     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5571     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5572     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5573     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5574     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5575     for (v = vStart; v < vEnd; ++v) {
5576       const PetscInt idx = v - vStart;
5577       PetscInt       off, d, m;
5578 
5579       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5580       for (d = 0; d < dim; ++d) {
5581         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5582       }
5583       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5584       in->pointmarkerlist[idx] = (int) m;
5585     }
5586     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5587   }
5588   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5589   in->numberofcorners       = 4;
5590   in->numberoftetrahedra    = cEnd - cStart;
5591   in->tetrahedronvolumelist = maxVolumes;
5592   if (in->numberoftetrahedra > 0) {
5593     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5594     for (c = cStart; c < cEnd; ++c) {
5595       const PetscInt idx     = c - cStart;
5596       PetscInt      *closure = PETSC_NULL;
5597       PetscInt       closureSize;
5598 
5599       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5600       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5601       for (v = 0; v < 4; ++v) {
5602         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5603       }
5604       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5605     }
5606   }
5607   if (!rank) {
5608     TetGenOpts t;
5609 
5610     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5611     t.in        = dm; /* Should go away */
5612     t.refine    = 1;
5613     t.varvolume = 1;
5614     t.quality   = 1;
5615     t.edgesout  = 1;
5616     t.zeroindex = 1;
5617     t.quiet     = 1;
5618     t.verbose   = verbose; /* Change this */
5619     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5620     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5621   }
5622   {
5623     const PetscInt numCorners  = 4;
5624     const PetscInt numCells    = out->numberoftetrahedra;
5625     const PetscInt numVertices = out->numberofpoints;
5626     const int     *cells       = out->tetrahedronlist;
5627     const double  *meshCoords  = out->pointlist;
5628     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5629 
5630     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5631     /* Set labels */
5632     for (v = 0; v < numVertices; ++v) {
5633       if (out->pointmarkerlist[v]) {
5634         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5635       }
5636     }
5637     if (interpolate) {
5638       PetscInt e, f;
5639 
5640       for (e = 0; e < out->numberofedges; e++) {
5641         if (out->edgemarkerlist[e]) {
5642           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5643           const PetscInt *edges;
5644           PetscInt        numEdges;
5645 
5646           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5647           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5648           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5649           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5650         }
5651       }
5652       for (f = 0; f < out->numberoftrifaces; f++) {
5653         if (out->trifacemarkerlist[f]) {
5654           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5655           const PetscInt *faces;
5656           PetscInt        numFaces;
5657 
5658           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5659           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5660           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5661           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5662         }
5663       }
5664     }
5665     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5666   }
5667   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5668   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5669   PetscFunctionReturn(0);
5670 }
5671 #endif
5672 
5673 #undef __FUNCT__
5674 #define __FUNCT__ "DMPlexGenerate"
5675 /*@C
5676   DMPlexGenerate - Generates a mesh.
5677 
5678   Not Collective
5679 
5680   Input Parameters:
5681 + boundary - The DMPlex boundary object
5682 . name - The mesh generation package name
5683 - interpolate - Flag to create intermediate mesh elements
5684 
5685   Output Parameter:
5686 . mesh - The DMPlex object
5687 
5688   Level: intermediate
5689 
5690 .keywords: mesh, elements
5691 .seealso: DMPlexCreate(), DMRefine()
5692 @*/
5693 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5694 {
5695   PetscInt       dim;
5696   char           genname[1024];
5697   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5698   PetscErrorCode ierr;
5699 
5700   PetscFunctionBegin;
5701   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5702   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5703   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5704   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5705   if (flg) {name = genname;}
5706   if (name) {
5707     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5708     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5709     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5710   }
5711   switch (dim) {
5712   case 1:
5713     if (!name || isTriangle) {
5714 #if defined(PETSC_HAVE_TRIANGLE)
5715       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5716 #else
5717       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5718 #endif
5719     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5720     break;
5721   case 2:
5722     if (!name || isCTetgen) {
5723 #if defined(PETSC_HAVE_CTETGEN)
5724       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5725 #else
5726       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5727 #endif
5728     } else if (isTetgen) {
5729 #if defined(PETSC_HAVE_TETGEN)
5730       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5731 #else
5732       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5733 #endif
5734     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5735     break;
5736   default:
5737     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5738   }
5739   PetscFunctionReturn(0);
5740 }
5741 
5742 typedef PetscInt CellRefiner;
5743 
5744 #undef __FUNCT__
5745 #define __FUNCT__ "GetDepthStart_Private"
5746 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5747 {
5748   PetscFunctionBegin;
5749   if (cStart) *cStart = 0;
5750   if (vStart) *vStart = depthSize[depth];
5751   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5752   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5753   PetscFunctionReturn(0);
5754 }
5755 
5756 #undef __FUNCT__
5757 #define __FUNCT__ "GetDepthEnd_Private"
5758 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5759 {
5760   PetscFunctionBegin;
5761   if (cEnd) *cEnd = depthSize[depth];
5762   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5763   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5764   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5765   PetscFunctionReturn(0);
5766 }
5767 
5768 #undef __FUNCT__
5769 #define __FUNCT__ "CellRefinerGetSizes"
5770 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5771 {
5772   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5773   PetscErrorCode ierr;
5774 
5775   PetscFunctionBegin;
5776   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5777   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5778   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5779   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5780   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5781   switch (refiner) {
5782   case 1:
5783     /* Simplicial 2D */
5784     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5785     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5786     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5787     break;
5788   case 3:
5789     /* Hybrid 2D */
5790     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5791     cMax = PetscMin(cEnd, cMax);
5792     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5793     fMax = PetscMin(fEnd, fMax);
5794     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5795     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 */
5796     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5797     break;
5798   case 2:
5799     /* Hex 2D */
5800     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5801     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5802     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5803     break;
5804   default:
5805     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5806   }
5807   PetscFunctionReturn(0);
5808 }
5809 
5810 #undef __FUNCT__
5811 #define __FUNCT__ "CellRefinerSetConeSizes"
5812 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5813 {
5814   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5815   PetscErrorCode ierr;
5816 
5817   PetscFunctionBegin;
5818   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5819   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5820   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5821   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5822   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5823   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5824   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5825   switch (refiner) {
5826   case 1:
5827     /* Simplicial 2D */
5828     /* All cells have 3 faces */
5829     for (c = cStart; c < cEnd; ++c) {
5830       for (r = 0; r < 4; ++r) {
5831         const PetscInt newp = (c - cStart)*4 + r;
5832 
5833         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5834       }
5835     }
5836     /* Split faces have 2 vertices and the same cells as the parent */
5837     for (f = fStart; f < fEnd; ++f) {
5838       for (r = 0; r < 2; ++r) {
5839         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5840         PetscInt       size;
5841 
5842         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5843         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5844         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5845       }
5846     }
5847     /* Interior faces have 2 vertices and 2 cells */
5848     for (c = cStart; c < cEnd; ++c) {
5849       for (r = 0; r < 3; ++r) {
5850         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5851 
5852         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5853         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5854       }
5855     }
5856     /* Old vertices have identical supports */
5857     for (v = vStart; v < vEnd; ++v) {
5858       const PetscInt newp = vStartNew + (v - vStart);
5859       PetscInt       size;
5860 
5861       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5862       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5863     }
5864     /* Face vertices have 2 + cells*2 supports */
5865     for (f = fStart; f < fEnd; ++f) {
5866       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5867       PetscInt       size;
5868 
5869       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5870       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5871     }
5872     break;
5873   case 2:
5874     /* Hex 2D */
5875     /* All cells have 4 faces */
5876     for (c = cStart; c < cEnd; ++c) {
5877       for (r = 0; r < 4; ++r) {
5878         const PetscInt newp = (c - cStart)*4 + r;
5879 
5880         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5881       }
5882     }
5883     /* Split faces have 2 vertices and the same cells as the parent */
5884     for (f = fStart; f < fEnd; ++f) {
5885       for (r = 0; r < 2; ++r) {
5886         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5887         PetscInt       size;
5888 
5889         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5890         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5891         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5892       }
5893     }
5894     /* Interior faces have 2 vertices and 2 cells */
5895     for (c = cStart; c < cEnd; ++c) {
5896       for (r = 0; r < 4; ++r) {
5897         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5898 
5899         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5900         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5901       }
5902     }
5903     /* Old vertices have identical supports */
5904     for (v = vStart; v < vEnd; ++v) {
5905       const PetscInt newp = vStartNew + (v - vStart);
5906       PetscInt       size;
5907 
5908       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5909       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5910     }
5911     /* Face vertices have 2 + cells supports */
5912     for (f = fStart; f < fEnd; ++f) {
5913       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5914       PetscInt       size;
5915 
5916       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5917       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5918     }
5919     /* Cell vertices have 4 supports */
5920     for (c = cStart; c < cEnd; ++c) {
5921       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5922 
5923       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5924     }
5925     break;
5926   case 3:
5927     /* Hybrid 2D */
5928     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5929     cMax = PetscMin(cEnd, cMax);
5930     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5931     fMax = PetscMin(fEnd, fMax);
5932     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5933     /* Interior cells have 3 faces */
5934     for (c = cStart; c < cMax; ++c) {
5935       for (r = 0; r < 4; ++r) {
5936         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5937 
5938         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5939       }
5940     }
5941     /* Hybrid cells have 4 faces */
5942     for (c = cMax; c < cEnd; ++c) {
5943       for (r = 0; r < 2; ++r) {
5944         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5945 
5946         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5947       }
5948     }
5949     /* Interior split faces have 2 vertices and the same cells as the parent */
5950     for (f = fStart; f < fMax; ++f) {
5951       for (r = 0; r < 2; ++r) {
5952         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5953         PetscInt       size;
5954 
5955         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5956         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5957         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5958       }
5959     }
5960     /* Interior cell faces have 2 vertices and 2 cells */
5961     for (c = cStart; c < cMax; ++c) {
5962       for (r = 0; r < 3; ++r) {
5963         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5964 
5965         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5966         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5967       }
5968     }
5969     /* Hybrid faces have 2 vertices and the same cells */
5970     for (f = fMax; f < fEnd; ++f) {
5971       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5972       PetscInt       size;
5973 
5974       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5975       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5976       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5977     }
5978     /* Hybrid cell faces have 2 vertices and 2 cells */
5979     for (c = cMax; c < cEnd; ++c) {
5980       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5981 
5982       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5983       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5984     }
5985     /* Old vertices have identical supports */
5986     for (v = vStart; v < vEnd; ++v) {
5987       const PetscInt newp = vStartNew + (v - vStart);
5988       PetscInt       size;
5989 
5990       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5991       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5992     }
5993     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5994     for (f = fStart; f < fMax; ++f) {
5995       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5996       const PetscInt *support;
5997       PetscInt        size, newSize = 2, s;
5998 
5999       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6000       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6001       for (s = 0; s < size; ++s) {
6002         if (support[s] >= cMax) {
6003           newSize += 1;
6004         } else {
6005           newSize += 2;
6006         }
6007       }
6008       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6009     }
6010     break;
6011   default:
6012     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6013   }
6014   PetscFunctionReturn(0);
6015 }
6016 
6017 #undef __FUNCT__
6018 #define __FUNCT__ "CellRefinerSetCones"
6019 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6020 {
6021   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;
6022   PetscInt       maxSupportSize, *supportRef;
6023   PetscErrorCode ierr;
6024 
6025   PetscFunctionBegin;
6026   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6027   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6028   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6029   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6030   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6031   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6032   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6033   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6034   switch (refiner) {
6035   case 1:
6036     /* Simplicial 2D */
6037     /*
6038      2
6039      |\
6040      | \
6041      |  \
6042      |   \
6043      | C  \
6044      |     \
6045      |      \
6046      2---1---1
6047      |\  D  / \
6048      | 2   0   \
6049      |A \ /  B  \
6050      0---0-------1
6051      */
6052     /* All cells have 3 faces */
6053     for (c = cStart; c < cEnd; ++c) {
6054       const PetscInt  newp = cStartNew + (c - cStart)*4;
6055       const PetscInt *cone, *ornt;
6056       PetscInt        coneNew[3], orntNew[3];
6057 
6058       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6059       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6060       /* A triangle */
6061       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6062       orntNew[0] = ornt[0];
6063       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6064       orntNew[1] = -2;
6065       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6066       orntNew[2] = ornt[2];
6067       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6068       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6069 #if 1
6070       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6071       for (p = 0; p < 3; ++p) {
6072         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6073       }
6074 #endif
6075       /* B triangle */
6076       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6077       orntNew[0] = ornt[0];
6078       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6079       orntNew[1] = ornt[1];
6080       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6081       orntNew[2] = -2;
6082       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6083       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6084 #if 1
6085       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);
6086       for (p = 0; p < 3; ++p) {
6087         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);
6088       }
6089 #endif
6090       /* C triangle */
6091       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6092       orntNew[0] = -2;
6093       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6094       orntNew[1] = ornt[1];
6095       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6096       orntNew[2] = ornt[2];
6097       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6098       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6099 #if 1
6100       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);
6101       for (p = 0; p < 3; ++p) {
6102         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);
6103       }
6104 #endif
6105       /* D triangle */
6106       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6107       orntNew[0] = 0;
6108       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6109       orntNew[1] = 0;
6110       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6111       orntNew[2] = 0;
6112       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6113       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6114 #if 1
6115       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);
6116       for (p = 0; p < 3; ++p) {
6117         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);
6118       }
6119 #endif
6120     }
6121     /* Split faces have 2 vertices and the same cells as the parent */
6122     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6123     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6124     for (f = fStart; f < fEnd; ++f) {
6125       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6126 
6127       for (r = 0; r < 2; ++r) {
6128         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6129         const PetscInt *cone, *support;
6130         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6131 
6132         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6133         coneNew[0] = vStartNew + (cone[0] - vStart);
6134         coneNew[1] = vStartNew + (cone[1] - vStart);
6135         coneNew[(r+1)%2] = newv;
6136         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6137 #if 1
6138         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6139         for (p = 0; p < 2; ++p) {
6140           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);
6141         }
6142 #endif
6143         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6144         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6145         for (s = 0; s < supportSize; ++s) {
6146           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6147           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6148           for (c = 0; c < coneSize; ++c) {
6149             if (cone[c] == f) {
6150               break;
6151             }
6152           }
6153           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6154         }
6155         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6156 #if 1
6157         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6158         for (p = 0; p < supportSize; ++p) {
6159           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);
6160         }
6161 #endif
6162       }
6163     }
6164     /* Interior faces have 2 vertices and 2 cells */
6165     for (c = cStart; c < cEnd; ++c) {
6166       const PetscInt *cone;
6167 
6168       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6169       for (r = 0; r < 3; ++r) {
6170         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6171         PetscInt       coneNew[2];
6172         PetscInt       supportNew[2];
6173 
6174         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6175         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6176         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6177 #if 1
6178         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6179         for (p = 0; p < 2; ++p) {
6180           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);
6181         }
6182 #endif
6183         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6184         supportNew[1] = (c - cStart)*4 + 3;
6185         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6186 #if 1
6187         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6188         for (p = 0; p < 2; ++p) {
6189           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);
6190         }
6191 #endif
6192       }
6193     }
6194     /* Old vertices have identical supports */
6195     for (v = vStart; v < vEnd; ++v) {
6196       const PetscInt  newp = vStartNew + (v - vStart);
6197       const PetscInt *support, *cone;
6198       PetscInt        size, s;
6199 
6200       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6201       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6202       for (s = 0; s < size; ++s) {
6203         PetscInt r = 0;
6204 
6205         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6206         if (cone[1] == v) r = 1;
6207         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6208       }
6209       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6210 #if 1
6211       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6212       for (p = 0; p < size; ++p) {
6213         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);
6214       }
6215 #endif
6216     }
6217     /* Face vertices have 2 + cells*2 supports */
6218     for (f = fStart; f < fEnd; ++f) {
6219       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6220       const PetscInt *cone, *support;
6221       PetscInt        size, s;
6222 
6223       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6224       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6225       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6226       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6227       for (s = 0; s < size; ++s) {
6228         PetscInt r = 0;
6229 
6230         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6231         if      (cone[1] == f) r = 1;
6232         else if (cone[2] == f) r = 2;
6233         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6234         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6235       }
6236       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6237 #if 1
6238       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6239       for (p = 0; p < 2+size*2; ++p) {
6240         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);
6241       }
6242 #endif
6243     }
6244     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6245     break;
6246   case 2:
6247     /* Hex 2D */
6248     /*
6249      3---------2---------2
6250      |         |         |
6251      |    D    2    C    |
6252      |         |         |
6253      3----3----0----1----1
6254      |         |         |
6255      |    A    0    B    |
6256      |         |         |
6257      0---------0---------1
6258      */
6259     /* All cells have 4 faces */
6260     for (c = cStart; c < cEnd; ++c) {
6261       const PetscInt  newp = (c - cStart)*4;
6262       const PetscInt *cone, *ornt;
6263       PetscInt        coneNew[4], orntNew[4];
6264 
6265       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6266       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6267       /* A quad */
6268       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6269       orntNew[0] = ornt[0];
6270       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6271       orntNew[1] = 0;
6272       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6273       orntNew[2] = -2;
6274       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6275       orntNew[3] = ornt[3];
6276       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6277       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6278 #if 1
6279       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);
6280       for (p = 0; p < 4; ++p) {
6281         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);
6282       }
6283 #endif
6284       /* B quad */
6285       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6286       orntNew[0] = ornt[0];
6287       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6288       orntNew[1] = ornt[1];
6289       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6290       orntNew[2] = 0;
6291       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6292       orntNew[3] = -2;
6293       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6294       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6295 #if 1
6296       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);
6297       for (p = 0; p < 4; ++p) {
6298         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);
6299       }
6300 #endif
6301       /* C quad */
6302       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6303       orntNew[0] = -2;
6304       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6305       orntNew[1] = ornt[1];
6306       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6307       orntNew[2] = ornt[2];
6308       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6309       orntNew[3] = 0;
6310       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6311       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6312 #if 1
6313       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);
6314       for (p = 0; p < 4; ++p) {
6315         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);
6316       }
6317 #endif
6318       /* D quad */
6319       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6320       orntNew[0] = 0;
6321       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6322       orntNew[1] = -2;
6323       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6324       orntNew[2] = ornt[2];
6325       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6326       orntNew[3] = ornt[3];
6327       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6328       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6329 #if 1
6330       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);
6331       for (p = 0; p < 4; ++p) {
6332         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);
6333       }
6334 #endif
6335     }
6336     /* Split faces have 2 vertices and the same cells as the parent */
6337     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6338     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6339     for (f = fStart; f < fEnd; ++f) {
6340       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6341 
6342       for (r = 0; r < 2; ++r) {
6343         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6344         const PetscInt *cone, *support;
6345         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6346 
6347         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6348         coneNew[0] = vStartNew + (cone[0] - vStart);
6349         coneNew[1] = vStartNew + (cone[1] - vStart);
6350         coneNew[(r+1)%2] = newv;
6351         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6352 #if 1
6353         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6354         for (p = 0; p < 2; ++p) {
6355           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);
6356         }
6357 #endif
6358         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6359         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6360         for (s = 0; s < supportSize; ++s) {
6361           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6362           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6363           for (c = 0; c < coneSize; ++c) {
6364             if (cone[c] == f) {
6365               break;
6366             }
6367           }
6368           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6369         }
6370         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6371 #if 1
6372         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6373         for (p = 0; p < supportSize; ++p) {
6374           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);
6375         }
6376 #endif
6377       }
6378     }
6379     /* Interior faces have 2 vertices and 2 cells */
6380     for (c = cStart; c < cEnd; ++c) {
6381       const PetscInt *cone;
6382       PetscInt        coneNew[2], supportNew[2];
6383 
6384       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6385       for (r = 0; r < 4; ++r) {
6386         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6387 
6388         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6389         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6390         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6391 #if 1
6392         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6393         for (p = 0; p < 2; ++p) {
6394           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);
6395         }
6396 #endif
6397         supportNew[0] = (c - cStart)*4 + r;
6398         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6399         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6400 #if 1
6401         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6402         for (p = 0; p < 2; ++p) {
6403           if ((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);
6404         }
6405 #endif
6406       }
6407     }
6408     /* Old vertices have identical supports */
6409     for (v = vStart; v < vEnd; ++v) {
6410       const PetscInt  newp = vStartNew + (v - vStart);
6411       const PetscInt *support, *cone;
6412       PetscInt        size, s;
6413 
6414       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6415       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6416       for (s = 0; s < size; ++s) {
6417         PetscInt r = 0;
6418 
6419         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6420         if (cone[1] == v) r = 1;
6421         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6422       }
6423       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6424 #if 1
6425       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6426       for (p = 0; p < size; ++p) {
6427         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);
6428       }
6429 #endif
6430     }
6431     /* Face vertices have 2 + cells supports */
6432     for (f = fStart; f < fEnd; ++f) {
6433       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6434       const PetscInt *cone, *support;
6435       PetscInt        size, s;
6436 
6437       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6438       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6439       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6440       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6441       for (s = 0; s < size; ++s) {
6442         PetscInt r = 0;
6443 
6444         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6445         if      (cone[1] == f) r = 1;
6446         else if (cone[2] == f) r = 2;
6447         else if (cone[3] == f) r = 3;
6448         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6449       }
6450       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6451 #if 1
6452       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6453       for (p = 0; p < 2+size; ++p) {
6454         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);
6455       }
6456 #endif
6457     }
6458     /* Cell vertices have 4 supports */
6459     for (c = cStart; c < cEnd; ++c) {
6460       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6461       PetscInt       supportNew[4];
6462 
6463       for (r = 0; r < 4; ++r) {
6464         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6465       }
6466       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6467     }
6468     break;
6469   case 3:
6470     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6471     cMax = PetscMin(cEnd, cMax);
6472     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6473     fMax = PetscMin(fEnd, fMax);
6474     /* Interior cells have 3 faces */
6475     for (c = cStart; c < cMax; ++c) {
6476       const PetscInt  newp = cStartNew + (c - cStart)*4;
6477       const PetscInt *cone, *ornt;
6478       PetscInt        coneNew[3], orntNew[3];
6479 
6480       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6481       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6482       /* A triangle */
6483       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6484       orntNew[0] = ornt[0];
6485       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6486       orntNew[1] = -2;
6487       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6488       orntNew[2] = ornt[2];
6489       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6490       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6491 #if 1
6492       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);
6493       for (p = 0; p < 3; ++p) {
6494         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);
6495       }
6496 #endif
6497       /* B triangle */
6498       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6499       orntNew[0] = ornt[0];
6500       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6501       orntNew[1] = ornt[1];
6502       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6503       orntNew[2] = -2;
6504       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6505       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6506 #if 1
6507       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);
6508       for (p = 0; p < 3; ++p) {
6509         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);
6510       }
6511 #endif
6512       /* C triangle */
6513       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6514       orntNew[0] = -2;
6515       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6516       orntNew[1] = ornt[1];
6517       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6518       orntNew[2] = ornt[2];
6519       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6520       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6521 #if 1
6522       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);
6523       for (p = 0; p < 3; ++p) {
6524         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);
6525       }
6526 #endif
6527       /* D triangle */
6528       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6529       orntNew[0] = 0;
6530       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6531       orntNew[1] = 0;
6532       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6533       orntNew[2] = 0;
6534       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6535       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6536 #if 1
6537       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);
6538       for (p = 0; p < 3; ++p) {
6539         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);
6540       }
6541 #endif
6542     }
6543     /*
6544      2----3----3
6545      |         |
6546      |    B    |
6547      |         |
6548      0----4--- 1
6549      |         |
6550      |    A    |
6551      |         |
6552      0----2----1
6553      */
6554     /* Hybrid cells have 4 faces */
6555     for (c = cMax; c < cEnd; ++c) {
6556       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6557       const PetscInt *cone, *ornt;
6558       PetscInt        coneNew[4], orntNew[4];
6559 
6560       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6561       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6562       /* A quad */
6563       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6564       orntNew[0] = ornt[0];
6565       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6566       orntNew[1] = ornt[1];
6567       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6568       orntNew[2] = 0;
6569       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6570       orntNew[3] = 0;
6571       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6572       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6573 #if 1
6574       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);
6575       for (p = 0; p < 4; ++p) {
6576         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);
6577       }
6578 #endif
6579       /* B quad */
6580       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6581       orntNew[0] = ornt[0];
6582       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6583       orntNew[1] = ornt[1];
6584       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6585       orntNew[2] = 0;
6586       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6587       orntNew[3] = 0;
6588       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6589       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6590 #if 1
6591       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);
6592       for (p = 0; p < 4; ++p) {
6593         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);
6594       }
6595 #endif
6596     }
6597     /* Interior split faces have 2 vertices and the same cells as the parent */
6598     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6599     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6600     for (f = fStart; f < fMax; ++f) {
6601       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6602 
6603       for (r = 0; r < 2; ++r) {
6604         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6605         const PetscInt *cone, *support;
6606         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6607 
6608         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6609         coneNew[0] = vStartNew + (cone[0] - vStart);
6610         coneNew[1] = vStartNew + (cone[1] - vStart);
6611         coneNew[(r+1)%2] = newv;
6612         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6613 #if 1
6614         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6615         for (p = 0; p < 2; ++p) {
6616           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);
6617         }
6618 #endif
6619         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6620         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6621         for (s = 0; s < supportSize; ++s) {
6622           if (support[s] >= cMax) {
6623             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6624           } else {
6625             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6626             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6627             for (c = 0; c < coneSize; ++c) {
6628               if (cone[c] == f) {
6629                 break;
6630               }
6631             }
6632             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6633           }
6634         }
6635         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6636 #if 1
6637         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6638         for (p = 0; p < supportSize; ++p) {
6639           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);
6640         }
6641 #endif
6642       }
6643     }
6644     /* Interior cell faces have 2 vertices and 2 cells */
6645     for (c = cStart; c < cMax; ++c) {
6646       const PetscInt *cone;
6647 
6648       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6649       for (r = 0; r < 3; ++r) {
6650         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6651         PetscInt       coneNew[2];
6652         PetscInt       supportNew[2];
6653 
6654         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6655         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6656         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6657 #if 1
6658         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6659         for (p = 0; p < 2; ++p) {
6660           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);
6661         }
6662 #endif
6663         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6664         supportNew[1] = (c - cStart)*4 + 3;
6665         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6666 #if 1
6667         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6668         for (p = 0; p < 2; ++p) {
6669           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);
6670         }
6671 #endif
6672       }
6673     }
6674     /* Interior hybrid faces have 2 vertices and the same cells */
6675     for (f = fMax; f < fEnd; ++f) {
6676       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6677       const PetscInt *cone;
6678       const PetscInt *support;
6679       PetscInt        coneNew[2];
6680       PetscInt        supportNew[2];
6681       PetscInt        size, s, r;
6682 
6683       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6684       coneNew[0] = vStartNew + (cone[0] - vStart);
6685       coneNew[1] = vStartNew + (cone[1] - vStart);
6686       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6687 #if 1
6688       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6689       for (p = 0; p < 2; ++p) {
6690         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);
6691       }
6692 #endif
6693       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6694       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6695       for (s = 0; s < size; ++s) {
6696         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6697         for (r = 0; r < 2; ++r) {
6698           if (cone[r+2] == f) break;
6699         }
6700         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6701       }
6702       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6703 #if 1
6704       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6705       for (p = 0; p < size; ++p) {
6706         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);
6707       }
6708 #endif
6709     }
6710     /* Cell hybrid faces have 2 vertices and 2 cells */
6711     for (c = cMax; c < cEnd; ++c) {
6712       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6713       const PetscInt *cone;
6714       PetscInt        coneNew[2];
6715       PetscInt        supportNew[2];
6716 
6717       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6718       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6719       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6720       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6721 #if 1
6722       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6723       for (p = 0; p < 2; ++p) {
6724         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);
6725       }
6726 #endif
6727       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6728       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6729       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6730 #if 1
6731       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6732       for (p = 0; p < 2; ++p) {
6733         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);
6734       }
6735 #endif
6736     }
6737     /* Old vertices have identical supports */
6738     for (v = vStart; v < vEnd; ++v) {
6739       const PetscInt  newp = vStartNew + (v - vStart);
6740       const PetscInt *support, *cone;
6741       PetscInt        size, s;
6742 
6743       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6744       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6745       for (s = 0; s < size; ++s) {
6746         if (support[s] >= fMax) {
6747           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6748         } else {
6749           PetscInt r = 0;
6750 
6751           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6752           if (cone[1] == v) r = 1;
6753           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6754         }
6755       }
6756       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6757 #if 1
6758       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6759       for (p = 0; p < size; ++p) {
6760         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);
6761       }
6762 #endif
6763     }
6764     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6765     for (f = fStart; f < fMax; ++f) {
6766       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6767       const PetscInt *cone, *support;
6768       PetscInt        size, newSize = 2, s;
6769 
6770       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6771       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6772       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6773       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6774       for (s = 0; s < size; ++s) {
6775         PetscInt r = 0;
6776 
6777         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6778         if (support[s] >= cMax) {
6779           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6780           newSize += 1;
6781         } else {
6782           if      (cone[1] == f) r = 1;
6783           else if (cone[2] == f) r = 2;
6784           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6785           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6786           newSize += 2;
6787         }
6788       }
6789       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6790 #if 1
6791       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6792       for (p = 0; p < newSize; ++p) {
6793         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);
6794       }
6795 #endif
6796     }
6797     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6798     break;
6799   default:
6800     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6801   }
6802   PetscFunctionReturn(0);
6803 }
6804 
6805 #undef __FUNCT__
6806 #define __FUNCT__ "CellRefinerSetCoordinates"
6807 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6808 {
6809   PetscSection   coordSection, coordSectionNew;
6810   Vec            coordinates, coordinatesNew;
6811   PetscScalar   *coords, *coordsNew;
6812   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6813   PetscErrorCode ierr;
6814 
6815   PetscFunctionBegin;
6816   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6817   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6818   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6819   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6820   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6821   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6822   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6823   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6824   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6825   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6826   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6827   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6828   if (fMax < 0) fMax = fEnd;
6829   switch (refiner) {
6830   case 1:
6831   case 2:
6832   case 3:
6833     /* Simplicial and Hex 2D */
6834     /* All vertices have the dim coordinates */
6835     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6836       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6837       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6838     }
6839     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6840     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6841     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6842     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6843     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6844     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6845     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6846     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6847     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6848     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6849     /* Old vertices have the same coordinates */
6850     for (v = vStart; v < vEnd; ++v) {
6851       const PetscInt newv = vStartNew + (v - vStart);
6852       PetscInt       off, offnew, d;
6853 
6854       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6855       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6856       for (d = 0; d < dim; ++d) {
6857         coordsNew[offnew+d] = coords[off+d];
6858       }
6859     }
6860     /* Face vertices have the average of endpoint coordinates */
6861     for (f = fStart; f < fMax; ++f) {
6862       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6863       const PetscInt *cone;
6864       PetscInt        coneSize, offA, offB, offnew, d;
6865 
6866       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6867       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6868       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6869       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6870       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6871       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6872       for (d = 0; d < dim; ++d) {
6873         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6874       }
6875     }
6876     /* Just Hex 2D */
6877     if (refiner == 2) {
6878       /* Cell vertices have the average of corner coordinates */
6879       for (c = cStart; c < cEnd; ++c) {
6880         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6881         PetscInt      *cone = PETSC_NULL;
6882         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6883 
6884         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6885         for (p = 0; p < closureSize*2; p += 2) {
6886           const PetscInt point = cone[p];
6887           if ((point >= vStart) && (point < vEnd)) {
6888             cone[coneSize++] = point;
6889           }
6890         }
6891         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6892         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6893         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6894         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6895         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6896         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6897         for (d = 0; d < dim; ++d) {
6898           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6899         }
6900         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6901       }
6902     }
6903     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6904     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6905     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6906     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6907     break;
6908   default:
6909     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6910   }
6911   PetscFunctionReturn(0);
6912 }
6913 
6914 #undef __FUNCT__
6915 #define __FUNCT__ "DMPlexCreateProcessSF"
6916 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6917 {
6918   PetscInt           numRoots, numLeaves, l;
6919   const PetscInt    *localPoints;
6920   const PetscSFNode *remotePoints;
6921   PetscInt          *localPointsNew;
6922   PetscSFNode       *remotePointsNew;
6923   PetscInt          *ranks, *ranksNew;
6924   PetscErrorCode     ierr;
6925 
6926   PetscFunctionBegin;
6927   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6928   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6929   for (l = 0; l < numLeaves; ++l) {
6930     ranks[l] = remotePoints[l].rank;
6931   }
6932   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6933   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6934   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6935   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6936   for (l = 0; l < numLeaves; ++l) {
6937     ranksNew[l]              = ranks[l];
6938     localPointsNew[l]        = l;
6939     remotePointsNew[l].index = 0;
6940     remotePointsNew[l].rank  = ranksNew[l];
6941   }
6942   ierr = PetscFree(ranks);CHKERRQ(ierr);
6943   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6944   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6945   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6946   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6947   PetscFunctionReturn(0);
6948 }
6949 
6950 #undef __FUNCT__
6951 #define __FUNCT__ "CellRefinerCreateSF"
6952 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6953 {
6954   PetscSF            sf, sfNew, sfProcess;
6955   IS                 processRanks;
6956   MPI_Datatype       depthType;
6957   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6958   const PetscInt    *localPoints, *neighbors;
6959   const PetscSFNode *remotePoints;
6960   PetscInt          *localPointsNew;
6961   PetscSFNode       *remotePointsNew;
6962   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6963   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6964   PetscErrorCode     ierr;
6965 
6966   PetscFunctionBegin;
6967   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6968   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6969   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6970   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6971   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6972   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6973   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6974   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6975   switch (refiner) {
6976   case 3:
6977     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6978     cMax = PetscMin(cEnd, cMax);
6979     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6980     fMax = PetscMin(fEnd, fMax);
6981   }
6982   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6983   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6984   /* Caculate size of new SF */
6985   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6986   if (numRoots < 0) PetscFunctionReturn(0);
6987   for (l = 0; l < numLeaves; ++l) {
6988     const PetscInt p = localPoints[l];
6989 
6990     switch (refiner) {
6991     case 1:
6992       /* Simplicial 2D */
6993       if ((p >= vStart) && (p < vEnd)) {
6994         /* Old vertices stay the same */
6995         ++numLeavesNew;
6996       } else if ((p >= fStart) && (p < fEnd)) {
6997         /* Old faces add new faces and vertex */
6998         numLeavesNew += 1 + 2;
6999       } else if ((p >= cStart) && (p < cEnd)) {
7000         /* Old cells add new cells and interior faces */
7001         numLeavesNew += 4 + 3;
7002       }
7003       break;
7004     case 2:
7005       /* Hex 2D */
7006       if ((p >= vStart) && (p < vEnd)) {
7007         /* Old vertices stay the same */
7008         ++numLeavesNew;
7009       } else if ((p >= fStart) && (p < fEnd)) {
7010         /* Old faces add new faces and vertex */
7011         numLeavesNew += 1 + 2;
7012       } else if ((p >= cStart) && (p < cEnd)) {
7013         /* Old cells add new cells and interior faces */
7014         numLeavesNew += 4 + 4;
7015       }
7016       break;
7017     default:
7018       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7019     }
7020   }
7021   /* Communicate depthSizes for each remote rank */
7022   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7023   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7024   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7025   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);
7026   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7027   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7028   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7029   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7030   for (n = 0; n < numNeighbors; ++n) {
7031     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7032   }
7033   depthSizeOld[depth]   = cMax;
7034   depthSizeOld[0]       = vMax;
7035   depthSizeOld[depth-1] = fMax;
7036   depthSizeOld[1]       = eMax;
7037   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7038   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7039   depthSizeOld[depth]   = cEnd - cStart;
7040   depthSizeOld[0]       = vEnd - vStart;
7041   depthSizeOld[depth-1] = fEnd - fStart;
7042   depthSizeOld[1]       = eEnd - eStart;
7043   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7044   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7045   for (n = 0; n < numNeighbors; ++n) {
7046     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7047   }
7048   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7049   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7050   /* Calculate new point SF */
7051   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7052   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7053   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7054   for (l = 0, m = 0; l < numLeaves; ++l) {
7055     PetscInt    p     = localPoints[l];
7056     PetscInt    rp    = remotePoints[l].index, n;
7057     PetscMPIInt rrank = remotePoints[l].rank;
7058 
7059     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7060     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7061     switch (refiner) {
7062     case 1:
7063       /* Simplicial 2D */
7064       if ((p >= vStart) && (p < vEnd)) {
7065         /* Old vertices stay the same */
7066         localPointsNew[m]        = vStartNew     + (p  - vStart);
7067         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7068         remotePointsNew[m].rank  = rrank;
7069         ++m;
7070       } else if ((p >= fStart) && (p < fEnd)) {
7071         /* Old faces add new faces and vertex */
7072         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7073         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7074         remotePointsNew[m].rank  = rrank;
7075         ++m;
7076         for (r = 0; r < 2; ++r, ++m) {
7077           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7078           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7079           remotePointsNew[m].rank  = rrank;
7080         }
7081       } else if ((p >= cStart) && (p < cEnd)) {
7082         /* Old cells add new cells and interior faces */
7083         for (r = 0; r < 4; ++r, ++m) {
7084           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7085           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7086           remotePointsNew[m].rank  = rrank;
7087         }
7088         for (r = 0; r < 3; ++r, ++m) {
7089           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7090           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7091           remotePointsNew[m].rank  = rrank;
7092         }
7093       }
7094       break;
7095     case 2:
7096       /* Hex 2D */
7097       if ((p >= vStart) && (p < vEnd)) {
7098         /* Old vertices stay the same */
7099         localPointsNew[m]        = vStartNew     + (p  - vStart);
7100         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7101         remotePointsNew[m].rank  = rrank;
7102         ++m;
7103       } else if ((p >= fStart) && (p < fEnd)) {
7104         /* Old faces add new faces and vertex */
7105         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7106         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7107         remotePointsNew[m].rank  = rrank;
7108         ++m;
7109         for (r = 0; r < 2; ++r, ++m) {
7110           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7111           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7112           remotePointsNew[m].rank  = rrank;
7113         }
7114       } else if ((p >= cStart) && (p < cEnd)) {
7115         /* Old cells add new cells and interior faces */
7116         for (r = 0; r < 4; ++r, ++m) {
7117           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7118           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7119           remotePointsNew[m].rank  = rrank;
7120         }
7121         for (r = 0; r < 4; ++r, ++m) {
7122           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7123           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7124           remotePointsNew[m].rank  = rrank;
7125         }
7126       }
7127       break;
7128     case 3:
7129       /* Hybrid simplicial 2D */
7130       if ((p >= vStart) && (p < vEnd)) {
7131         /* Old vertices stay the same */
7132         localPointsNew[m]        = vStartNew     + (p  - vStart);
7133         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7134         remotePointsNew[m].rank  = rrank;
7135         ++m;
7136       } else if ((p >= fStart) && (p < fMax)) {
7137         /* Old interior faces add new faces and vertex */
7138         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7139         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7140         remotePointsNew[m].rank  = rrank;
7141         ++m;
7142         for (r = 0; r < 2; ++r, ++m) {
7143           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7144           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7145           remotePointsNew[m].rank  = rrank;
7146         }
7147       } else if ((p >= fMax) && (p < fEnd)) {
7148         /* Old hybrid faces stay the same */
7149         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7150         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7151         remotePointsNew[m].rank  = rrank;
7152         ++m;
7153       } else if ((p >= cStart) && (p < cMax)) {
7154         /* Old interior cells add new cells and interior faces */
7155         for (r = 0; r < 4; ++r, ++m) {
7156           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7157           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7158           remotePointsNew[m].rank  = rrank;
7159         }
7160         for (r = 0; r < 3; ++r, ++m) {
7161           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7162           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7163           remotePointsNew[m].rank  = rrank;
7164         }
7165       } else if ((p >= cStart) && (p < cMax)) {
7166         /* Old hybrid cells add new cells and hybrid face */
7167         for (r = 0; r < 2; ++r, ++m) {
7168           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7169           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7170           remotePointsNew[m].rank  = rrank;
7171         }
7172         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7173         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]);
7174         remotePointsNew[m].rank  = rrank;
7175         ++m;
7176       }
7177       break;
7178     default:
7179       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7180     }
7181   }
7182   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7183   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7184   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7185   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7186   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7187   PetscFunctionReturn(0);
7188 }
7189 
7190 #undef __FUNCT__
7191 #define __FUNCT__ "CellRefinerCreateLabels"
7192 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7193 {
7194   PetscInt       numLabels, l;
7195   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7196   PetscErrorCode ierr;
7197 
7198   PetscFunctionBegin;
7199   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7200   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7201   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7202   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7203   cStartNew = 0;
7204   vStartNew = depthSize[2];
7205   fStartNew = depthSize[2] + depthSize[0];
7206   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7207   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7208   switch (refiner) {
7209   case 3:
7210     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7211     cMax = PetscMin(cEnd, cMax);
7212     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7213     fMax = PetscMin(fEnd, fMax);
7214   }
7215   for (l = 0; l < numLabels; ++l) {
7216     DMLabel         label, labelNew;
7217     const char     *lname;
7218     PetscBool       isDepth;
7219     IS              valueIS;
7220     const PetscInt *values;
7221     PetscInt        numValues, val;
7222 
7223     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7224     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7225     if (isDepth) continue;
7226     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7227     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7228     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7229     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7230     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7231     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7232     for (val = 0; val < numValues; ++val) {
7233       IS              pointIS;
7234       const PetscInt *points;
7235       PetscInt        numPoints, n;
7236 
7237       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7238       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7239       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7240       for (n = 0; n < numPoints; ++n) {
7241         const PetscInt p = points[n];
7242         switch (refiner) {
7243         case 1:
7244           /* Simplicial 2D */
7245           if ((p >= vStart) && (p < vEnd)) {
7246             /* Old vertices stay the same */
7247             newp = vStartNew + (p - vStart);
7248             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7249           } else if ((p >= fStart) && (p < fEnd)) {
7250             /* Old faces add new faces and vertex */
7251             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7252             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7253             for (r = 0; r < 2; ++r) {
7254               newp = fStartNew + (p - fStart)*2 + r;
7255               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7256             }
7257           } else if ((p >= cStart) && (p < cEnd)) {
7258             /* Old cells add new cells and interior faces */
7259             for (r = 0; r < 4; ++r) {
7260               newp = cStartNew + (p - cStart)*4 + r;
7261               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7262             }
7263             for (r = 0; r < 3; ++r) {
7264               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7265               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7266             }
7267           }
7268           break;
7269         case 2:
7270           /* Hex 2D */
7271           if ((p >= vStart) && (p < vEnd)) {
7272             /* Old vertices stay the same */
7273             newp = vStartNew + (p - vStart);
7274             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7275           } else if ((p >= fStart) && (p < fEnd)) {
7276             /* Old faces add new faces and vertex */
7277             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7278             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7279             for (r = 0; r < 2; ++r) {
7280               newp = fStartNew + (p - fStart)*2 + r;
7281               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7282             }
7283           } else if ((p >= cStart) && (p < cEnd)) {
7284             /* Old cells add new cells and interior faces and vertex */
7285             for (r = 0; r < 4; ++r) {
7286               newp = cStartNew + (p - cStart)*4 + r;
7287               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7288             }
7289             for (r = 0; r < 4; ++r) {
7290               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7291               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7292             }
7293             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7294             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7295           }
7296           break;
7297         case 3:
7298           /* Hybrid simplicial 2D */
7299           if ((p >= vStart) && (p < vEnd)) {
7300             /* Old vertices stay the same */
7301             newp = vStartNew + (p - vStart);
7302             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7303           } else if ((p >= fStart) && (p < fMax)) {
7304             /* Old interior faces add new faces and vertex */
7305             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7306             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7307             for (r = 0; r < 2; ++r) {
7308               newp = fStartNew + (p - fStart)*2 + r;
7309               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7310             }
7311           } else if ((p >= fMax) && (p < fEnd)) {
7312             /* Old hybrid faces stay the same */
7313             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7314             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7315           } else if ((p >= cStart) && (p < cMax)) {
7316             /* Old interior cells add new cells and interior faces */
7317             for (r = 0; r < 4; ++r) {
7318               newp = cStartNew + (p - cStart)*4 + r;
7319               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7320             }
7321             for (r = 0; r < 3; ++r) {
7322               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7323               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7324             }
7325           } else if ((p >= cMax) && (p < cEnd)) {
7326             /* Old hybrid cells add new cells and hybrid face */
7327             for (r = 0; r < 2; ++r) {
7328               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7329               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7330             }
7331             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7332             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7333           }
7334           break;
7335         default:
7336           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7337         }
7338       }
7339       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7340       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7341     }
7342     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7343     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7344     if (0) {
7345       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7346       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7347       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7348     }
7349   }
7350   PetscFunctionReturn(0);
7351 }
7352 
7353 #undef __FUNCT__
7354 #define __FUNCT__ "DMPlexRefine_Uniform"
7355 /* This will only work for interpolated meshes */
7356 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7357 {
7358   DM              rdm;
7359   PetscInt       *depthSize;
7360   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
7361   PetscErrorCode  ierr;
7362 
7363   PetscFunctionBegin;
7364   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7365   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7366   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7367   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7368   /* Calculate number of new points of each depth */
7369   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7370   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7371   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7372   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7373   /* Step 1: Set chart */
7374   for (d = 0; d <= depth; ++d) {
7375     pEnd += depthSize[d];
7376   }
7377   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7378   /* Step 2: Set cone/support sizes */
7379   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7380   /* Step 3: Setup refined DM */
7381   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7382   /* Step 4: Set cones and supports */
7383   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7384   /* Step 5: Stratify */
7385   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7386   /* Step 6: Set coordinates for vertices */
7387   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7388   /* Step 7: Create pointSF */
7389   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7390   /* Step 8: Create labels */
7391   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7392   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7393 
7394   *dmRefined = rdm;
7395 #if 0
7396   DM_Plex *mesh = (DM_Plex *) dm->data;
7397   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7398   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7399 
7400   PetscFunctionBegin;
7401   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7402   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7403   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7404   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7405   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7406 
7407   /* Count number of new cells which are normal and extra */
7408   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7409   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7410   for (c = cStart; c < cEnd2; ++c) {
7411     PetscInt n;
7412     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7413     newNumCellsNormal += n;
7414   }
7415   for (c = cEnd2; c < cEnd; ++c) {
7416     PetscInt n;
7417     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7418     newNumCellsExtra += n;
7419   }
7420   newNumCells = newNumCellsNormal + newNumCellsExtra;
7421   /* Count number of new vertices which are normal and extra */
7422   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7423   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7424   for (c = cStart; c < cEnd; ++c) {
7425     PetscInt *closure = PETSC_NULL;
7426     PetscInt  closureSize, numCorners = 0, p;
7427 
7428     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7429     for (p = 0; p < closureSize*2; p += 2) {
7430       const PetscInt point = closure[p];
7431       if ((point >= vStart) && (point < vEnd)) {
7432         closure[numCorners++] = point;
7433       }
7434     }
7435     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7436     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7437   }
7438   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7439   for (c = cEnd2; c < cEnd; ++c) {
7440     PetscInt *closure = PETSC_NULL;
7441     PetscInt  closureSize, numCorners = 0, p;
7442 
7443     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7444     for (p = 0; p < closureSize*2; p += 2) {
7445       const PetscInt point = closure[p];
7446       if ((point >= vStart) && (point < vEnd)) {
7447         closure[numCorners++] = point;
7448       }
7449     }
7450     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7451     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7452   } /* for */
7453   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7454   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
7455 
7456 #if 1
7457   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
7458   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
7459   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7460   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7461   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7462   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7463   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7464   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7465   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7466   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7467   ierr = PetscSynchronizedFlush(comm);
7468 #endif
7469 
7470   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7471   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7472   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7473   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7474   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7475   /* Set cone and support sizes for new normal cells */
7476   PetscInt newCell = 0;
7477   for (c = cStart; c < cEnd2; ++c) {
7478     PetscInt coneSize, n, i;
7479 
7480     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7481     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7482     for (i = 0; i < n; ++i, ++newCell) {
7483       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7484     }
7485 
7486     PetscInt *closure = PETSC_NULL;
7487     PetscInt  closureSize, numCorners = 0, p;
7488 
7489     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7490     for (p = 0; p < closureSize*2; p += 2) {
7491       const PetscInt point = closure[p];
7492       if ((point >= vStart) && (point < vEnd)) {
7493         closure[numCorners++] = point;
7494       }
7495     }
7496     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7497     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7498   }
7499 
7500   /* Reset current new cell value and loop over censored cells. */
7501   curNewCell = _orderNewMesh->cellsCensored().min();
7502   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7503   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7504     /* Set new cone and support sizes */
7505     cV.clear();
7506     sieve->cone(*c_iter, cV);
7507     const point_type* cone = cV.getPoints();
7508     const int coneSize = cV.getSize();
7509 
7510     const point_type* newCells;
7511     int numNewCells = 0;
7512     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7513 
7514     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7515       newSieve->setConeSize(curNewCell, coneSize);
7516       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7517         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7518       } /* for */
7519     } /* for */
7520   } /* for */
7521   newSieve->allocate();
7522 
7523   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7524 
7525   /* Create refined cells in new sieve. */
7526   curNewCell = _orderNewMesh->cellsNormal().min();
7527   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7528   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7529     cV.clear();
7530     sieve->cone(*c_iter, cV);
7531     const point_type *cone = cV.getPoints();
7532     const int coneSize = cV.getSize();
7533 
7534     const point_type* newCells;
7535     int numNewCells = 0;
7536     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7537 
7538     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7539       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7540     } /* for */
7541   } /* for */
7542   curNewCell = _orderNewMesh->cellsCensored().min();
7543   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7544   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7545     cV.clear();
7546     sieve->cone(*c_iter, cV);
7547     const point_type *cone = cV.getPoints();
7548     const int coneSize = cV.getSize();
7549 
7550     const point_type* newCells;
7551     int numNewCells = 0;
7552     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7553 
7554     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7555       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7556     } /* for */
7557   } /* for */
7558   newSieve->symmetrize();
7559 
7560   /* Set coordinates in refined mesh. */
7561   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7562   assert(!coordinates.isNull());
7563   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7564   assert(!newCoordinates.isNull());
7565 
7566   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7567   assert(vertices->size() > 0);
7568   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7569   assert(spaceDim > 0);
7570   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7571 
7572   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7573   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7574     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7575   } /* for */
7576   newCoordinates->allocatePoint();
7577 
7578   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7579   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7580     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7581     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7582   } /* for */
7583   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7584   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7585     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7586     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7587   } /* for */
7588 
7589   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7590 
7591   /* Create sensored depth */
7592   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7593   assert(!censoredLabel.isNull());
7594 
7595   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7596 
7597   newSieve->roots(depthVisitor);
7598   while (depthVisitor.isModified()) {
7599     /* FIX: Avoid the copy here somehow by fixing the traversal */
7600     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7601 
7602     depthVisitor.clear();
7603     newSieve->support(modifiedPoints, depthVisitor);
7604   } /* while */
7605   /* Stratify refined mesh */
7606   /* Calculate new point SF */
7607   _calcNewOverlap(newMesh, mesh, refiner);
7608   /* Calculate new labels */
7609   _createLabels(newMesh, mesh, refiner);
7610 #endif
7611   PetscFunctionReturn(0);
7612 }
7613 
7614 #undef __FUNCT__
7615 #define __FUNCT__ "DMPlexSetRefinementUniform"
7616 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7617 {
7618   DM_Plex *mesh = (DM_Plex *) dm->data;
7619 
7620   PetscFunctionBegin;
7621   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7622   mesh->refinementUniform = refinementUniform;
7623   PetscFunctionReturn(0);
7624 }
7625 
7626 #undef __FUNCT__
7627 #define __FUNCT__ "DMPlexGetRefinementUniform"
7628 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7629 {
7630   DM_Plex *mesh = (DM_Plex *) dm->data;
7631 
7632   PetscFunctionBegin;
7633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7634   PetscValidPointer(refinementUniform,  2);
7635   *refinementUniform = mesh->refinementUniform;
7636   PetscFunctionReturn(0);
7637 }
7638 
7639 #undef __FUNCT__
7640 #define __FUNCT__ "DMPlexSetRefinementLimit"
7641 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7642 {
7643   DM_Plex *mesh = (DM_Plex *) dm->data;
7644 
7645   PetscFunctionBegin;
7646   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7647   mesh->refinementLimit = refinementLimit;
7648   PetscFunctionReturn(0);
7649 }
7650 
7651 #undef __FUNCT__
7652 #define __FUNCT__ "DMPlexGetRefinementLimit"
7653 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7654 {
7655   DM_Plex *mesh = (DM_Plex *) dm->data;
7656 
7657   PetscFunctionBegin;
7658   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7659   PetscValidPointer(refinementLimit,  2);
7660   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7661   *refinementLimit = mesh->refinementLimit;
7662   PetscFunctionReturn(0);
7663 }
7664 
7665 #undef __FUNCT__
7666 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7667 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7668 {
7669   PetscInt       dim, cStart, coneSize, cMax;
7670   PetscErrorCode ierr;
7671 
7672   PetscFunctionBegin;
7673   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7674   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7675   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7676   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7677   switch (dim) {
7678   case 2:
7679     switch (coneSize) {
7680     case 3:
7681       if (cMax >= 0) {
7682         *cellRefiner = 3; /* Hybrid */
7683       } else {
7684         *cellRefiner = 1; /* Triangular */
7685       }
7686       break;
7687     case 4:
7688       if (cMax >= 0) {
7689         *cellRefiner = 4; /* Hybrid */
7690       } else {
7691         *cellRefiner = 2; /* Quadrilateral */
7692       }
7693       break;
7694     default:
7695       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7696     }
7697     break;
7698   default:
7699     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7700   }
7701   PetscFunctionReturn(0);
7702 }
7703 
7704 #undef __FUNCT__
7705 #define __FUNCT__ "DMRefine_Plex"
7706 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7707 {
7708   PetscReal      refinementLimit;
7709   PetscInt       dim, cStart, cEnd;
7710   char           genname[1024], *name = PETSC_NULL;
7711   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7712   PetscErrorCode ierr;
7713 
7714   PetscFunctionBegin;
7715   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7716   if (isUniform) {
7717     CellRefiner cellRefiner;
7718 
7719     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7720     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7721     PetscFunctionReturn(0);
7722   }
7723   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7724   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7725   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7726   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7727   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7728   if (flg) {name = genname;}
7729   if (name) {
7730     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7731     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7732     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7733   }
7734   switch (dim) {
7735   case 2:
7736     if (!name || isTriangle) {
7737 #if defined(PETSC_HAVE_TRIANGLE)
7738       double  *maxVolumes;
7739       PetscInt c;
7740 
7741       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7742       for (c = 0; c < cEnd-cStart; ++c) {
7743         maxVolumes[c] = refinementLimit;
7744       }
7745       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7746 #else
7747       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7748 #endif
7749     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7750     break;
7751   case 3:
7752     if (!name || isCTetgen) {
7753 #if defined(PETSC_HAVE_CTETGEN)
7754       PetscReal *maxVolumes;
7755       PetscInt   c;
7756 
7757       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7758       for (c = 0; c < cEnd-cStart; ++c) {
7759         maxVolumes[c] = refinementLimit;
7760       }
7761       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7762 #else
7763       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7764 #endif
7765     } else if (isTetgen) {
7766 #if defined(PETSC_HAVE_TETGEN)
7767       double  *maxVolumes;
7768       PetscInt c;
7769 
7770       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7771       for (c = 0; c < cEnd-cStart; ++c) {
7772         maxVolumes[c] = refinementLimit;
7773       }
7774       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7775 #else
7776       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7777 #endif
7778     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7779     break;
7780   default:
7781     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7782   }
7783   PetscFunctionReturn(0);
7784 }
7785 
7786 #undef __FUNCT__
7787 #define __FUNCT__ "DMPlexGetDepth"
7788 /*@
7789   DMPlexGetDepth - get the number of strata
7790 
7791   Not Collective
7792 
7793   Input Parameters:
7794 . dm           - The DMPlex object
7795 
7796   Output Parameters:
7797 . depth - number of strata
7798 
7799   Level: developer
7800 
7801   Notes:
7802   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7803 
7804 .keywords: mesh, points
7805 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7806 @*/
7807 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7808 {
7809   PetscInt       d;
7810   PetscErrorCode ierr;
7811 
7812   PetscFunctionBegin;
7813   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7814   PetscValidPointer(depth, 2);
7815   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7816   *depth = d-1;
7817   PetscFunctionReturn(0);
7818 }
7819 
7820 #undef __FUNCT__
7821 #define __FUNCT__ "DMPlexGetDepthStratum"
7822 /*@
7823   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7824 
7825   Not Collective
7826 
7827   Input Parameters:
7828 + dm           - The DMPlex object
7829 - stratumValue - The requested depth
7830 
7831   Output Parameters:
7832 + start - The first point at this depth
7833 - end   - One beyond the last point at this depth
7834 
7835   Level: developer
7836 
7837 .keywords: mesh, points
7838 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7839 @*/
7840 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7841 {
7842   DM_Plex    *mesh = (DM_Plex *) dm->data;
7843   DMLabel        next = mesh->labels;
7844   PetscBool      flg  = PETSC_FALSE;
7845   PetscInt       depth;
7846   PetscErrorCode ierr;
7847 
7848   PetscFunctionBegin;
7849   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7850   if (stratumValue < 0) {
7851     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7852     PetscFunctionReturn(0);
7853   } else {
7854     PetscInt pStart, pEnd;
7855 
7856     if (start) {*start = 0;}
7857     if (end)   {*end   = 0;}
7858     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7859     if (pStart == pEnd) {PetscFunctionReturn(0);}
7860   }
7861   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7862   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7863   /* We should have a generic GetLabel() and a Label class */
7864   while (next) {
7865     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7866     if (flg) break;
7867     next = next->next;
7868   }
7869   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7870   depth = stratumValue;
7871   if ((depth < 0) || (depth >= next->numStrata)) {
7872     if (start) {*start = 0;}
7873     if (end)   {*end   = 0;}
7874   } else {
7875     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7876     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7877   }
7878   PetscFunctionReturn(0);
7879 }
7880 
7881 #undef __FUNCT__
7882 #define __FUNCT__ "DMPlexGetHeightStratum"
7883 /*@
7884   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7885 
7886   Not Collective
7887 
7888   Input Parameters:
7889 + dm           - The DMPlex object
7890 - stratumValue - The requested height
7891 
7892   Output Parameters:
7893 + start - The first point at this height
7894 - end   - One beyond the last point at this height
7895 
7896   Level: developer
7897 
7898 .keywords: mesh, points
7899 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7900 @*/
7901 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7902 {
7903   DM_Plex        *mesh = (DM_Plex *) dm->data;
7904   DMLabel        next = mesh->labels;
7905   PetscBool      flg  = PETSC_FALSE;
7906   PetscInt       depth;
7907   PetscErrorCode ierr;
7908 
7909   PetscFunctionBegin;
7910   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7911   if (stratumValue < 0) {
7912     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7913   } else {
7914     PetscInt pStart, pEnd;
7915 
7916     if (start) {*start = 0;}
7917     if (end)   {*end   = 0;}
7918     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7919     if (pStart == pEnd) {PetscFunctionReturn(0);}
7920   }
7921   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7922   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7923   /* We should have a generic GetLabel() and a Label class */
7924   while (next) {
7925     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7926     if (flg) break;
7927     next = next->next;
7928   }
7929   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7930   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7931   if ((depth < 0) || (depth >= next->numStrata)) {
7932     if (start) {*start = 0;}
7933     if (end)   {*end   = 0;}
7934   } else {
7935     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7936     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7937   }
7938   PetscFunctionReturn(0);
7939 }
7940 
7941 #undef __FUNCT__
7942 #define __FUNCT__ "DMPlexCreateSectionInitial"
7943 /* Set the number of dof on each point and separate by fields */
7944 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7945 {
7946   PetscInt      *numDofTot;
7947   PetscInt       pStart = 0, pEnd = 0;
7948   PetscInt       p, d, f;
7949   PetscErrorCode ierr;
7950 
7951   PetscFunctionBegin;
7952   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7953   for (d = 0; d <= dim; ++d) {
7954     numDofTot[d] = 0;
7955     for (f = 0; f < numFields; ++f) {
7956       numDofTot[d] += numDof[f*(dim+1)+d];
7957     }
7958   }
7959   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7960   if (numFields > 0) {
7961     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7962     if (numComp) {
7963       for (f = 0; f < numFields; ++f) {
7964         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7965       }
7966     }
7967   }
7968   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7969   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7970   for (d = 0; d <= dim; ++d) {
7971     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7972     for (p = pStart; p < pEnd; ++p) {
7973       for (f = 0; f < numFields; ++f) {
7974         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7975       }
7976       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7977     }
7978   }
7979   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7980   PetscFunctionReturn(0);
7981 }
7982 
7983 #undef __FUNCT__
7984 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7985 /* Set the number of dof on each point and separate by fields
7986    If constDof is PETSC_DETERMINE, constrain every dof on the point
7987 */
7988 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7989 {
7990   PetscInt       numFields;
7991   PetscInt       bc;
7992   PetscErrorCode ierr;
7993 
7994   PetscFunctionBegin;
7995   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7996   for (bc = 0; bc < numBC; ++bc) {
7997     PetscInt        field = 0;
7998     const PetscInt *idx;
7999     PetscInt        n, i;
8000 
8001     if (numFields) {field = bcField[bc];}
8002     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
8003     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8004     for (i = 0; i < n; ++i) {
8005       const PetscInt p = idx[i];
8006       PetscInt       numConst = constDof;
8007 
8008       /* Constrain every dof on the point */
8009       if (numConst < 0) {
8010         if (numFields) {
8011           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
8012         } else {
8013           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
8014         }
8015       }
8016       if (numFields) {
8017         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
8018       }
8019       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
8020     }
8021     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8022   }
8023   PetscFunctionReturn(0);
8024 }
8025 
8026 #undef __FUNCT__
8027 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
8028 /* Set the constrained indices on each point and separate by fields */
8029 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
8030 {
8031   PetscInt      *maxConstraints;
8032   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
8033   PetscErrorCode ierr;
8034 
8035   PetscFunctionBegin;
8036   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8037   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8038   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
8039   for (f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
8040   for (p = pStart; p < pEnd; ++p) {
8041     PetscInt cdof;
8042 
8043     if (numFields) {
8044       for (f = 0; f < numFields; ++f) {
8045         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
8046         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
8047       }
8048     } else {
8049       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8050       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
8051     }
8052   }
8053   for (f = 0; f < numFields; ++f) {
8054     maxConstraints[numFields] += maxConstraints[f];
8055   }
8056   if (maxConstraints[numFields]) {
8057     PetscInt *indices;
8058 
8059     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8060     for (p = pStart; p < pEnd; ++p) {
8061       PetscInt cdof, d;
8062 
8063       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8064       if (cdof) {
8065         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
8066         if (numFields) {
8067           PetscInt numConst = 0, foff = 0;
8068 
8069           for (f = 0; f < numFields; ++f) {
8070             PetscInt cfdof, fdof;
8071 
8072             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8073             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
8074             /* Change constraint numbering from absolute local dof number to field relative local dof number */
8075             for (d = 0; d < cfdof; ++d) {
8076               indices[numConst+d] = d;
8077             }
8078             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
8079             for (d = 0; d < cfdof; ++d) {
8080               indices[numConst+d] += foff;
8081             }
8082             numConst += cfdof;
8083             foff     += fdof;
8084           }
8085           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8086         } else {
8087           for (d = 0; d < cdof; ++d) {
8088             indices[d] = d;
8089           }
8090         }
8091         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8092       }
8093     }
8094     ierr = PetscFree(indices);CHKERRQ(ierr);
8095   }
8096   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
8097   PetscFunctionReturn(0);
8098 }
8099 
8100 #undef __FUNCT__
8101 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
8102 /* Set the constrained field indices on each point */
8103 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
8104 {
8105   const PetscInt *points, *indices;
8106   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
8107   PetscErrorCode  ierr;
8108 
8109   PetscFunctionBegin;
8110   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8111   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8112 
8113   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8114   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8115   if (!constraintIndices) {
8116     PetscInt *idx, i;
8117 
8118     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8119     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8120     for (i = 0; i < maxDof; ++i) {idx[i] = i;}
8121     for (p = 0; p < numPoints; ++p) {
8122       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8123     }
8124     ierr = PetscFree(idx);CHKERRQ(ierr);
8125   } else {
8126     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8127     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8128     for (p = 0; p < numPoints; ++p) {
8129       PetscInt fcdof;
8130 
8131       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8132       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);
8133       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8134     }
8135     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8136   }
8137   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8138   PetscFunctionReturn(0);
8139 }
8140 
8141 #undef __FUNCT__
8142 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8143 /* Set the constrained indices on each point and separate by fields */
8144 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8145 {
8146   PetscInt      *indices;
8147   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8148   PetscErrorCode ierr;
8149 
8150   PetscFunctionBegin;
8151   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8152   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8153   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8154   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8155   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8156   for (p = pStart; p < pEnd; ++p) {
8157     PetscInt cdof, d;
8158 
8159     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8160     if (cdof) {
8161       PetscInt numConst = 0, foff = 0;
8162 
8163       for (f = 0; f < numFields; ++f) {
8164         const PetscInt *fcind;
8165         PetscInt        fdof, fcdof;
8166 
8167         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8168         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8169         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8170         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8171         for (d = 0; d < fcdof; ++d) {
8172           indices[numConst+d] = fcind[d]+foff;
8173         }
8174         foff     += fdof;
8175         numConst += fcdof;
8176       }
8177       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8178       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8179     }
8180   }
8181   ierr = PetscFree(indices);CHKERRQ(ierr);
8182   PetscFunctionReturn(0);
8183 }
8184 
8185 #undef __FUNCT__
8186 #define __FUNCT__ "DMPlexCreateSection"
8187 /*@C
8188   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8189 
8190   Not Collective
8191 
8192   Input Parameters:
8193 + dm        - The DMPlex object
8194 . dim       - The spatial dimension of the problem
8195 . numFields - The number of fields in the problem
8196 . numComp   - An array of size numFields that holds the number of components for each field
8197 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8198 . numBC     - The number of boundary conditions
8199 . bcField   - An array of size numBC giving the field number for each boundry condition
8200 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8201 
8202   Output Parameter:
8203 . section - The PetscSection object
8204 
8205   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
8206   nubmer of dof for field 0 on each edge.
8207 
8208   Level: developer
8209 
8210 .keywords: mesh, elements
8211 .seealso: DMPlexCreate(), PetscSectionCreate()
8212 @*/
8213 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8214 {
8215   PetscErrorCode ierr;
8216 
8217   PetscFunctionBegin;
8218   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8219   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8220   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8221   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8222   {
8223     PetscBool view = PETSC_FALSE;
8224 
8225     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8226     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8227   }
8228   PetscFunctionReturn(0);
8229 }
8230 
8231 #undef __FUNCT__
8232 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8233 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8234 {
8235   PetscSection   section;
8236   PetscErrorCode ierr;
8237 
8238   PetscFunctionBegin;
8239   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8240   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8241   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8242   PetscFunctionReturn(0);
8243 }
8244 
8245 #undef __FUNCT__
8246 #define __FUNCT__ "DMPlexGetCoordinateSection"
8247 /*@
8248   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8249 
8250   Not Collective
8251 
8252   Input Parameter:
8253 . dm - The DMPlex object
8254 
8255   Output Parameter:
8256 . section - The PetscSection object
8257 
8258   Level: intermediate
8259 
8260 .keywords: mesh, coordinates
8261 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8262 @*/
8263 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8264 {
8265   DM             cdm;
8266   PetscErrorCode ierr;
8267 
8268   PetscFunctionBegin;
8269   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8270   PetscValidPointer(section, 2);
8271   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8272   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8273   PetscFunctionReturn(0);
8274 }
8275 
8276 #undef __FUNCT__
8277 #define __FUNCT__ "DMPlexSetCoordinateSection"
8278 /*@
8279   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8280 
8281   Not Collective
8282 
8283   Input Parameters:
8284 + dm      - The DMPlex object
8285 - section - The PetscSection object
8286 
8287   Level: intermediate
8288 
8289 .keywords: mesh, coordinates
8290 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8291 @*/
8292 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8293 {
8294   DM             cdm;
8295   PetscErrorCode ierr;
8296 
8297   PetscFunctionBegin;
8298   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8299   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8300   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8301   PetscFunctionReturn(0);
8302 }
8303 
8304 #undef __FUNCT__
8305 #define __FUNCT__ "DMPlexGetConeSection"
8306 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8307 {
8308   DM_Plex *mesh = (DM_Plex *) dm->data;
8309 
8310   PetscFunctionBegin;
8311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8312   if (section) *section = mesh->coneSection;
8313   PetscFunctionReturn(0);
8314 }
8315 
8316 #undef __FUNCT__
8317 #define __FUNCT__ "DMPlexGetCones"
8318 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8319 {
8320   DM_Plex *mesh = (DM_Plex *) dm->data;
8321 
8322   PetscFunctionBegin;
8323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8324   if (cones) *cones = mesh->cones;
8325   PetscFunctionReturn(0);
8326 }
8327 
8328 #undef __FUNCT__
8329 #define __FUNCT__ "DMPlexGetConeOrientations"
8330 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8331 {
8332   DM_Plex *mesh = (DM_Plex *) dm->data;
8333 
8334   PetscFunctionBegin;
8335   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8336   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8337   PetscFunctionReturn(0);
8338 }
8339 
8340 #undef __FUNCT__
8341 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8342 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8343 {
8344   const PetscInt embedDim = 2;
8345   PetscReal      x = PetscRealPart(point[0]);
8346   PetscReal      y = PetscRealPart(point[1]);
8347   PetscReal      v0[2], J[4], invJ[4], detJ;
8348   PetscReal      xi, eta;
8349   PetscErrorCode ierr;
8350 
8351   PetscFunctionBegin;
8352   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8353   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8354   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8355 
8356   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
8357     *cell = c;
8358   } else {
8359     *cell = -1;
8360   }
8361   PetscFunctionReturn(0);
8362 }
8363 
8364 #undef __FUNCT__
8365 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8366 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8367 {
8368   PetscSection       coordSection;
8369   Vec                coordsLocal;
8370   const PetscScalar *coords;
8371   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8372   PetscReal          x         = PetscRealPart(point[0]);
8373   PetscReal          y         = PetscRealPart(point[1]);
8374   PetscInt           crossings = 0, f;
8375   PetscErrorCode     ierr;
8376 
8377   PetscFunctionBegin;
8378   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8379   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8380   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8381   for (f = 0; f < 4; ++f) {
8382     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8383     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8384     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8385     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8386     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8387     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8388     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8389     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8390     if ((cond1 || cond2)  && above) ++crossings;
8391   }
8392   if (crossings % 2) {
8393     *cell = c;
8394   } else {
8395     *cell = -1;
8396   }
8397   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8398   PetscFunctionReturn(0);
8399 }
8400 
8401 #undef __FUNCT__
8402 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8403 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8404 {
8405   const PetscInt embedDim = 3;
8406   PetscReal      v0[3], J[9], invJ[9], detJ;
8407   PetscReal      x = PetscRealPart(point[0]);
8408   PetscReal      y = PetscRealPart(point[1]);
8409   PetscReal      z = PetscRealPart(point[2]);
8410   PetscReal      xi, eta, zeta;
8411   PetscErrorCode ierr;
8412 
8413   PetscFunctionBegin;
8414   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8415   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8416   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8417   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8418 
8419   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
8420     *cell = c;
8421   } else {
8422     *cell = -1;
8423   }
8424   PetscFunctionReturn(0);
8425 }
8426 
8427 #undef __FUNCT__
8428 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8429 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8430 {
8431   PetscSection       coordSection;
8432   Vec                coordsLocal;
8433   const PetscScalar *coords;
8434   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8435                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8436   PetscBool          found     = PETSC_TRUE;
8437   PetscInt           f;
8438   PetscErrorCode     ierr;
8439 
8440   PetscFunctionBegin;
8441   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8442   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8443   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8444   for (f = 0; f < 6; ++f) {
8445     /* Check the point is under plane */
8446     /*   Get face normal */
8447     PetscReal v_i[3];
8448     PetscReal v_j[3];
8449     PetscReal normal[3];
8450     PetscReal pp[3];
8451     PetscReal dot;
8452 
8453     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8454     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8455     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8456     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8457     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8458     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8459     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8460     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8461     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8462     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8463     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8464     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8465     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8466 
8467     /* Check that projected point is in face (2D location problem) */
8468     if (dot < 0.0) {
8469       found = PETSC_FALSE;
8470       break;
8471     }
8472   }
8473   if (found) {
8474     *cell = c;
8475   } else {
8476     *cell = -1;
8477   }
8478   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8479   PetscFunctionReturn(0);
8480 }
8481 
8482 #undef __FUNCT__
8483 #define __FUNCT__ "DMLocatePoints_Plex"
8484 /*
8485  Need to implement using the guess
8486 */
8487 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8488 {
8489   PetscInt       cell = -1/*, guess = -1*/;
8490   PetscInt       bs, numPoints, p;
8491   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8492   PetscInt      *cells;
8493   PetscScalar   *a;
8494   PetscErrorCode ierr;
8495 
8496   PetscFunctionBegin;
8497   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8498   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8499   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8500   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8501   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8502   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8503   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8504   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);
8505   numPoints /= bs;
8506   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8507   for (p = 0; p < numPoints; ++p) {
8508     const PetscScalar *point = &a[p*bs];
8509 
8510     switch (dim) {
8511     case 2:
8512       for (c = cStart; c < cEnd; ++c) {
8513         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8514         switch (coneSize) {
8515         case 3:
8516           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8517           break;
8518         case 4:
8519           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8520           break;
8521         default:
8522           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8523         }
8524         if (cell >= 0) break;
8525       }
8526       break;
8527     case 3:
8528       for (c = cStart; c < cEnd; ++c) {
8529         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8530         switch (coneSize) {
8531         case 4:
8532           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8533           break;
8534         case 8:
8535           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8536           break;
8537         default:
8538           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8539         }
8540         if (cell >= 0) break;
8541       }
8542       break;
8543     default:
8544       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8545     }
8546     cells[p] = cell;
8547   }
8548   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8549   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8550   PetscFunctionReturn(0);
8551 }
8552 
8553 /******************************** FEM Support **********************************/
8554 
8555 #undef __FUNCT__
8556 #define __FUNCT__ "DMPlexVecGetClosure"
8557 /*@C
8558   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8559 
8560   Not collective
8561 
8562   Input Parameters:
8563 + dm - The DM
8564 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8565 . v - The local vector
8566 - point - The sieve point in the DM
8567 
8568   Output Parameters:
8569 + csize - The number of values in the closure, or PETSC_NULL
8570 - values - The array of values, which is a borrowed array and should not be freed
8571 
8572   Level: intermediate
8573 
8574 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8575 @*/
8576 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8577 {
8578   PetscScalar    *array, *vArray;
8579   PetscInt       *points = PETSC_NULL;
8580   PetscInt        offsets[32];
8581   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8582   PetscErrorCode  ierr;
8583 
8584   PetscFunctionBegin;
8585   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8586   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8587   if (!section) {
8588     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8589   }
8590   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8591   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8592   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8593   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8594   /* Compress out points not in the section */
8595   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8596   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8597     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8598       points[q*2]   = points[p];
8599       points[q*2+1] = points[p+1];
8600       ++q;
8601     }
8602   }
8603   numPoints = q;
8604   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8605     PetscInt dof, fdof;
8606 
8607     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8608     for (f = 0; f < numFields; ++f) {
8609       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8610       offsets[f+1] += fdof;
8611     }
8612     size += dof;
8613   }
8614   for (f = 1; f < numFields; ++f) {
8615     offsets[f+1] += offsets[f];
8616   }
8617   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8618   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8619   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8620   for (p = 0; p < numPoints*2; p += 2) {
8621     PetscInt     o = points[p+1];
8622     PetscInt     dof, off, d;
8623     PetscScalar *varr;
8624 
8625     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8626     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8627     varr = &vArray[off];
8628     if (numFields) {
8629       PetscInt fdof, foff, fcomp, f, c;
8630 
8631       for (f = 0, foff = 0; f < numFields; ++f) {
8632         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8633         if (o >= 0) {
8634           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8635             array[offsets[f]] = varr[foff+d];
8636           }
8637         } else {
8638           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8639           for (d = fdof/fcomp-1; d >= 0; --d) {
8640             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8641               array[offsets[f]] = varr[foff+d*fcomp+c];
8642             }
8643           }
8644         }
8645         foff += fdof;
8646       }
8647     } else {
8648       if (o >= 0) {
8649         for (d = 0; d < dof; ++d, ++offsets[0]) {
8650           array[offsets[0]] = varr[d];
8651         }
8652       } else {
8653         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8654           array[offsets[0]] = varr[d];
8655         }
8656       }
8657     }
8658   }
8659   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8660   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8661   if (csize) *csize = size;
8662   *values = array;
8663   PetscFunctionReturn(0);
8664 }
8665 
8666 #undef __FUNCT__
8667 #define __FUNCT__ "DMPlexVecRestoreClosure"
8668 /*@C
8669   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8670 
8671   Not collective
8672 
8673   Input Parameters:
8674 + dm - The DM
8675 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8676 . v - The local vector
8677 . point - The sieve point in the DM
8678 . csize - The number of values in the closure, or PETSC_NULL
8679 - values - The array of values, which is a borrowed array and should not be freed
8680 
8681   Level: intermediate
8682 
8683 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8684 @*/
8685 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8686 {
8687   PetscInt        size = 0;
8688   PetscErrorCode  ierr;
8689 
8690   PetscFunctionBegin;
8691   /* Should work without recalculating size */
8692   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8693   PetscFunctionReturn(0);
8694 }
8695 
8696 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8697 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8698 
8699 #undef __FUNCT__
8700 #define __FUNCT__ "updatePoint_private"
8701 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8702 {
8703   PetscInt        cdof;  /* The number of constraints on this point */
8704   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8705   PetscScalar    *a;
8706   PetscInt        off, cind = 0, k;
8707   PetscErrorCode  ierr;
8708 
8709   PetscFunctionBegin;
8710   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8711   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8712   a    = &array[off];
8713   if (!cdof || setBC) {
8714     if (orientation >= 0) {
8715       for (k = 0; k < dof; ++k) {
8716         fuse(&a[k], values[k]);
8717       }
8718     } else {
8719       for (k = 0; k < dof; ++k) {
8720         fuse(&a[k], values[dof-k-1]);
8721       }
8722     }
8723   } else {
8724     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8725     if (orientation >= 0) {
8726       for (k = 0; k < dof; ++k) {
8727         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8728         fuse(&a[k], values[k]);
8729       }
8730     } else {
8731       for (k = 0; k < dof; ++k) {
8732         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8733         fuse(&a[k], values[dof-k-1]);
8734       }
8735     }
8736   }
8737   PetscFunctionReturn(0);
8738 }
8739 
8740 #undef __FUNCT__
8741 #define __FUNCT__ "updatePointFields_private"
8742 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8743 {
8744   PetscScalar   *a;
8745   PetscInt       numFields, off, foff, f;
8746   PetscErrorCode ierr;
8747 
8748   PetscFunctionBegin;
8749   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8750   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8751   a    = &array[off];
8752   for (f = 0, foff = 0; f < numFields; ++f) {
8753     PetscInt        fdof, fcomp, fcdof;
8754     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8755     PetscInt        cind = 0, k, c;
8756 
8757     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8758     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8759     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8760     if (!fcdof || setBC) {
8761       if (orientation >= 0) {
8762         for (k = 0; k < fdof; ++k) {
8763           fuse(&a[foff+k], values[foffs[f]+k]);
8764         }
8765       } else {
8766         for (k = fdof/fcomp-1; k >= 0; --k) {
8767           for (c = 0; c < fcomp; ++c) {
8768             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8769           }
8770         }
8771       }
8772     } else {
8773       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8774       if (orientation >= 0) {
8775         for (k = 0; k < fdof; ++k) {
8776           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8777           fuse(&a[foff+k], values[foffs[f]+k]);
8778         }
8779       } else {
8780         for (k = fdof/fcomp-1; k >= 0; --k) {
8781           for (c = 0; c < fcomp; ++c) {
8782             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8783             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8784           }
8785         }
8786       }
8787     }
8788     foff     += fdof;
8789     foffs[f] += fdof;
8790   }
8791   PetscFunctionReturn(0);
8792 }
8793 
8794 #undef __FUNCT__
8795 #define __FUNCT__ "DMPlexVecSetClosure"
8796 /*@C
8797   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8798 
8799   Not collective
8800 
8801   Input Parameters:
8802 + dm - The DM
8803 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8804 . v - The local vector
8805 . point - The sieve point in the DM
8806 . values - The array of values, which is a borrowed array and should not be freed
8807 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8808 
8809   Level: intermediate
8810 
8811 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8812 @*/
8813 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8814 {
8815   PetscScalar    *array;
8816   PetscInt       *points = PETSC_NULL;
8817   PetscInt        offsets[32];
8818   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8819   PetscErrorCode  ierr;
8820 
8821   PetscFunctionBegin;
8822   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8823   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8824   if (!section) {
8825     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8826   }
8827   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8828   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8829   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8830   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8831   /* Compress out points not in the section */
8832   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8833   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8834     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8835       points[q*2]   = points[p];
8836       points[q*2+1] = points[p+1];
8837       ++q;
8838     }
8839   }
8840   numPoints = q;
8841   for (p = 0; p < numPoints*2; p += 2) {
8842     PetscInt fdof;
8843 
8844     for (f = 0; f < numFields; ++f) {
8845       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8846       offsets[f+1] += fdof;
8847     }
8848   }
8849   for (f = 1; f < numFields; ++f) {
8850     offsets[f+1] += offsets[f];
8851   }
8852   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8853   if (numFields) {
8854     switch (mode) {
8855     case INSERT_VALUES:
8856       for (p = 0; p < numPoints*2; p += 2) {
8857         PetscInt o = points[p+1];
8858         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8859       } break;
8860     case INSERT_ALL_VALUES:
8861       for (p = 0; p < numPoints*2; p += 2) {
8862         PetscInt o = points[p+1];
8863         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8864       } break;
8865     case ADD_VALUES:
8866       for (p = 0; p < numPoints*2; p += 2) {
8867         PetscInt o = points[p+1];
8868         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8869       } break;
8870     case ADD_ALL_VALUES:
8871       for (p = 0; p < numPoints*2; p += 2) {
8872         PetscInt o = points[p+1];
8873         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8874       } break;
8875     default:
8876       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8877     }
8878   } else {
8879     switch (mode) {
8880     case INSERT_VALUES:
8881       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8882         PetscInt o = points[p+1];
8883         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8884         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8885       } break;
8886     case INSERT_ALL_VALUES:
8887       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8888         PetscInt o = points[p+1];
8889         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8890         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8891       } break;
8892     case ADD_VALUES:
8893       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8894         PetscInt o = points[p+1];
8895         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8896         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8897       } break;
8898     case ADD_ALL_VALUES:
8899       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8900         PetscInt o = points[p+1];
8901         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8902         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8903       } break;
8904     default:
8905       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8906     }
8907   }
8908   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8909   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8910   PetscFunctionReturn(0);
8911 }
8912 
8913 #undef __FUNCT__
8914 #define __FUNCT__ "DMPlexPrintMatSetValues"
8915 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8916 {
8917   PetscMPIInt    rank;
8918   PetscInt       i, j;
8919   PetscErrorCode ierr;
8920 
8921   PetscFunctionBegin;
8922   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8923   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8924   for (i = 0; i < numIndices; i++) {
8925     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8926   }
8927   for (i = 0; i < numIndices; i++) {
8928     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8929     for (j = 0; j < numIndices; j++) {
8930 #if defined(PETSC_USE_COMPLEX)
8931       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8932 #else
8933       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8934 #endif
8935     }
8936     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8937   }
8938   PetscFunctionReturn(0);
8939 }
8940 
8941 #undef __FUNCT__
8942 #define __FUNCT__ "indicesPoint_private"
8943 /* . off - The global offset of this point */
8944 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8945 {
8946   PetscInt        cdof;  /* The number of constraints on this point */
8947   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8948   PetscInt        cind = 0, k;
8949   PetscErrorCode  ierr;
8950 
8951   PetscFunctionBegin;
8952   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8953   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8954   if (!cdof || setBC) {
8955     if (orientation >= 0) {
8956       for (k = 0; k < dof; ++k) {
8957         indices[k] = off+k;
8958       }
8959     } else {
8960       for (k = 0; k < dof; ++k) {
8961         indices[dof-k-1] = off+k;
8962       }
8963     }
8964   } else {
8965     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8966     if (orientation >= 0) {
8967       for (k = 0; k < dof; ++k) {
8968         if ((cind < cdof) && (k == cdofs[cind])) {
8969           /* Insert check for returning constrained indices */
8970           indices[k] = -(off+k+1);
8971           ++cind;
8972         } else {
8973           indices[k] = off+k-cind;
8974         }
8975       }
8976     } else {
8977       for (k = 0; k < dof; ++k) {
8978         if ((cind < cdof) && (k == cdofs[cind])) {
8979           /* Insert check for returning constrained indices */
8980           indices[dof-k-1] = -(off+k+1);
8981           ++cind;
8982         } else {
8983           indices[dof-k-1] = off+k-cind;
8984         }
8985       }
8986     }
8987   }
8988   PetscFunctionReturn(0);
8989 }
8990 
8991 #undef __FUNCT__
8992 #define __FUNCT__ "indicesPointFields_private"
8993 /* . off - The global offset of this point */
8994 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8995 {
8996   PetscInt       numFields, foff, f;
8997   PetscErrorCode ierr;
8998 
8999   PetscFunctionBegin;
9000   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9001   for (f = 0, foff = 0; f < numFields; ++f) {
9002     PetscInt        fdof, fcomp, cfdof;
9003     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
9004     PetscInt        cind = 0, k, c;
9005 
9006     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
9007     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
9008     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
9009     if (!cfdof || setBC) {
9010       if (orientation >= 0) {
9011         for (k = 0; k < fdof; ++k) {
9012           indices[foffs[f]+k] = off+foff+k;
9013         }
9014       } else {
9015         for (k = fdof/fcomp-1; k >= 0; --k) {
9016           for (c = 0; c < fcomp; ++c) {
9017             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
9018           }
9019         }
9020       }
9021     } else {
9022       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
9023       if (orientation >= 0) {
9024         for (k = 0; k < fdof; ++k) {
9025           if ((cind < cfdof) && (k == fcdofs[cind])) {
9026             indices[foffs[f]+k] = -(off+foff+k+1);
9027             ++cind;
9028           } else {
9029             indices[foffs[f]+k] = off+foff+k-cind;
9030           }
9031         }
9032       } else {
9033         for (k = fdof/fcomp-1; k >= 0; --k) {
9034           for (c = 0; c < fcomp; ++c) {
9035             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
9036               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
9037               ++cind;
9038             } else {
9039               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
9040             }
9041           }
9042         }
9043       }
9044     }
9045     foff     += fdof - cfdof;
9046     foffs[f] += fdof;
9047   }
9048   PetscFunctionReturn(0);
9049 }
9050 
9051 #undef __FUNCT__
9052 #define __FUNCT__ "DMPlexMatSetClosure"
9053 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
9054 {
9055   DM_Plex     *mesh   = (DM_Plex *) dm->data;
9056   PetscInt       *points = PETSC_NULL;
9057   PetscInt       *indices;
9058   PetscInt        offsets[32];
9059   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
9060   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
9061   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
9062   PetscErrorCode  ierr;
9063 
9064   PetscFunctionBegin;
9065   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9066   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
9067   if (useDefault) {
9068     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9069   }
9070   if (useGlobalDefault) {
9071     if (useDefault) {
9072       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
9073     } else {
9074       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9075     }
9076   }
9077   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9078   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
9079   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
9080   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9081   /* Compress out points not in the section */
9082   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
9083   for (p = 0, q = 0; p < numPoints*2; p += 2) {
9084     if ((points[p] >= pStart) && (points[p] < pEnd)) {
9085       points[q*2]   = points[p];
9086       points[q*2+1] = points[p+1];
9087       ++q;
9088     }
9089   }
9090   numPoints = q;
9091   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
9092     PetscInt fdof;
9093 
9094     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
9095     for (f = 0; f < numFields; ++f) {
9096       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
9097       offsets[f+1] += fdof;
9098     }
9099     numIndices += dof;
9100   }
9101   for (f = 1; f < numFields; ++f) {
9102     offsets[f+1] += offsets[f];
9103   }
9104   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
9105   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9106   if (numFields) {
9107     for (p = 0; p < numPoints*2; p += 2) {
9108       PetscInt o = points[p+1];
9109       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9110       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
9111     }
9112   } else {
9113     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
9114       PetscInt o = points[p+1];
9115       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9116       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
9117     }
9118   }
9119   if (useGlobalDefault && !useDefault) {
9120     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9121   }
9122   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
9123   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9124   if (ierr) {
9125     PetscMPIInt    rank;
9126     PetscErrorCode ierr2;
9127 
9128     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
9129     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9130     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9131     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9132     CHKERRQ(ierr);
9133   }
9134   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9135   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9136   PetscFunctionReturn(0);
9137 }
9138 
9139 #undef __FUNCT__
9140 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9141 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9142 {
9143   PetscSection       coordSection;
9144   Vec                coordinates;
9145   const PetscScalar *coords;
9146   const PetscInt     dim = 2;
9147   PetscInt           d, f;
9148   PetscErrorCode     ierr;
9149 
9150   PetscFunctionBegin;
9151   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9152   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9153   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9154   if (v0) {
9155     for (d = 0; d < dim; d++) {
9156       v0[d] = PetscRealPart(coords[d]);
9157     }
9158   }
9159   if (J) {
9160     for (d = 0; d < dim; d++) {
9161       for (f = 0; f < dim; f++) {
9162         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9163       }
9164     }
9165     *detJ = J[0]*J[3] - J[1]*J[2];
9166 #if 0
9167     if (detJ < 0.0) {
9168       const PetscReal xLength = mesh->periodicity[0];
9169 
9170       if (xLength != 0.0) {
9171         PetscReal v0x = coords[0*dim+0];
9172 
9173         if (v0x == 0.0) {
9174           v0x = v0[0] = xLength;
9175         }
9176         for (f = 0; f < dim; f++) {
9177           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9178 
9179           J[0*dim+f] = 0.5*(px - v0x);
9180         }
9181       }
9182       detJ = J[0]*J[3] - J[1]*J[2];
9183     }
9184 #endif
9185     PetscLogFlops(8.0 + 3.0);
9186   }
9187   if (invJ) {
9188     const PetscReal invDet = 1.0/(*detJ);
9189 
9190     invJ[0] =  invDet*J[3];
9191     invJ[1] = -invDet*J[1];
9192     invJ[2] = -invDet*J[2];
9193     invJ[3] =  invDet*J[0];
9194     PetscLogFlops(5.0);
9195   }
9196   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9197   PetscFunctionReturn(0);
9198 }
9199 
9200 #undef __FUNCT__
9201 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9202 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9203 {
9204   PetscSection       coordSection;
9205   Vec                coordinates;
9206   const PetscScalar *coords;
9207   const PetscInt     dim = 2;
9208   PetscInt           d, f;
9209   PetscErrorCode     ierr;
9210 
9211   PetscFunctionBegin;
9212   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9213   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9214   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9215   if (v0) {
9216     for (d = 0; d < dim; d++) {
9217       v0[d] = PetscRealPart(coords[d]);
9218     }
9219   }
9220   if (J) {
9221     for (d = 0; d < dim; d++) {
9222       for (f = 0; f < dim; f++) {
9223         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9224       }
9225     }
9226     *detJ = J[0]*J[3] - J[1]*J[2];
9227     PetscLogFlops(8.0 + 3.0);
9228   }
9229   if (invJ) {
9230     const PetscReal invDet = 1.0/(*detJ);
9231 
9232     invJ[0] =  invDet*J[3];
9233     invJ[1] = -invDet*J[1];
9234     invJ[2] = -invDet*J[2];
9235     invJ[3] =  invDet*J[0];
9236     PetscLogFlops(5.0);
9237   }
9238   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9239   PetscFunctionReturn(0);
9240 }
9241 
9242 #undef __FUNCT__
9243 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9244 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9245 {
9246   PetscSection       coordSection;
9247   Vec                coordinates;
9248   const PetscScalar *coords;
9249   const PetscInt     dim = 3;
9250   PetscInt           d, f;
9251   PetscErrorCode     ierr;
9252 
9253   PetscFunctionBegin;
9254   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9255   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9256   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9257   if (v0) {
9258     for (d = 0; d < dim; d++) {
9259       v0[d] = PetscRealPart(coords[d]);
9260     }
9261   }
9262   if (J) {
9263     for (d = 0; d < dim; d++) {
9264       for (f = 0; f < dim; f++) {
9265         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9266       }
9267     }
9268     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9269     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9270              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9271              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9272     PetscLogFlops(18.0 + 12.0);
9273   }
9274   if (invJ) {
9275     const PetscReal invDet = 1.0/(*detJ);
9276 
9277     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9278     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9279     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9280     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9281     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9282     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9283     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9284     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9285     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9286     PetscLogFlops(37.0);
9287   }
9288   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9289   PetscFunctionReturn(0);
9290 }
9291 
9292 #undef __FUNCT__
9293 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9294 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9295 {
9296   PetscSection       coordSection;
9297   Vec                coordinates;
9298   const PetscScalar *coords;
9299   const PetscInt     dim = 3;
9300   PetscInt           d;
9301   PetscErrorCode     ierr;
9302 
9303   PetscFunctionBegin;
9304   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9305   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9306   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9307   if (v0) {
9308     for (d = 0; d < dim; d++) {
9309       v0[d] = PetscRealPart(coords[d]);
9310     }
9311   }
9312   if (J) {
9313     for (d = 0; d < dim; d++) {
9314       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9315       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9316       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9317     }
9318     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9319              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9320              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9321     PetscLogFlops(18.0 + 12.0);
9322   }
9323   if (invJ) {
9324     const PetscReal invDet = -1.0/(*detJ);
9325 
9326     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9327     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9328     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9329     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9330     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9331     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9332     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9333     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9334     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9335     PetscLogFlops(37.0);
9336   }
9337   *detJ *= 8.0;
9338   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9339   PetscFunctionReturn(0);
9340 }
9341 
9342 #undef __FUNCT__
9343 #define __FUNCT__ "DMPlexComputeCellGeometry"
9344 /*@C
9345   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9346 
9347   Collective on DM
9348 
9349   Input Arguments:
9350 + dm   - the DM
9351 - cell - the cell
9352 
9353   Output Arguments:
9354 + v0   - the translation part of this affine transform
9355 . J    - the Jacobian of the transform to the reference element
9356 . invJ - the inverse of the Jacobian
9357 - detJ - the Jacobian determinant
9358 
9359   Level: advanced
9360 
9361 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9362 @*/
9363 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9364 {
9365   PetscInt       dim, coneSize;
9366   PetscErrorCode ierr;
9367 
9368   PetscFunctionBegin;
9369   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9370   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9371   switch (dim) {
9372   case 2:
9373     switch (coneSize) {
9374     case 3:
9375       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9376       break;
9377     case 4:
9378       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9379       break;
9380     default:
9381       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9382     }
9383     break;
9384   case 3:
9385     switch (coneSize) {
9386     case 4:
9387       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9388       break;
9389     case 8:
9390       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9391       break;
9392     default:
9393       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9394     }
9395     break;
9396   default:
9397     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9398   }
9399   PetscFunctionReturn(0);
9400 }
9401 
9402 #undef __FUNCT__
9403 #define __FUNCT__ "DMPlexGetFaceOrientation"
9404 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9405 {
9406   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9407   PetscBool      posOrient = PETSC_FALSE;
9408   const PetscInt debug     = 0;
9409   PetscInt       cellDim, faceSize, f;
9410   PetscErrorCode ierr;
9411 
9412   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9413   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9414 
9415   if (cellDim == numCorners-1) {
9416     /* Simplices */
9417     faceSize  = numCorners-1;
9418     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9419   } else if (cellDim == 1 && numCorners == 3) {
9420     /* Quadratic line */
9421     faceSize  = 1;
9422     posOrient = PETSC_TRUE;
9423   } else if (cellDim == 2 && numCorners == 4) {
9424     /* Quads */
9425     faceSize  = 2;
9426     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9427       posOrient = PETSC_TRUE;
9428     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9429       posOrient = PETSC_TRUE;
9430     } else {
9431       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9432         posOrient = PETSC_FALSE;
9433       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9434     }
9435   } else if (cellDim == 2 && numCorners == 6) {
9436     /* Quadratic triangle (I hate this) */
9437     /* Edges are determined by the first 2 vertices (corners of edges) */
9438     const PetscInt faceSizeTri = 3;
9439     PetscInt  sortedIndices[3], i, iFace;
9440     PetscBool found = PETSC_FALSE;
9441     PetscInt  faceVerticesTriSorted[9] = {
9442       0, 3,  4, /* bottom */
9443       1, 4,  5, /* right */
9444       2, 3,  5, /* left */
9445     };
9446     PetscInt  faceVerticesTri[9] = {
9447       0, 3,  4, /* bottom */
9448       1, 4,  5, /* right */
9449       2, 5,  3, /* left */
9450     };
9451 
9452     faceSize = faceSizeTri;
9453     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9454     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9455     for (iFace = 0; iFace < 3; ++iFace) {
9456       const PetscInt ii = iFace*faceSizeTri;
9457       PetscInt       fVertex, cVertex;
9458 
9459       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9460           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9461         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9462           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9463             if (indices[cVertex] == faceVerticesTri[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 tri crossface");
9474     if (posOriented) {*posOriented = PETSC_TRUE;}
9475     PetscFunctionReturn(0);
9476   } else if (cellDim == 2 && numCorners == 9) {
9477     /* Quadratic quad (I hate this) */
9478     /* Edges are determined by the first 2 vertices (corners of edges) */
9479     const PetscInt faceSizeQuad = 3;
9480     PetscInt  sortedIndices[3], i, iFace;
9481     PetscBool found = PETSC_FALSE;
9482     PetscInt  faceVerticesQuadSorted[12] = {
9483       0, 1,  4, /* bottom */
9484       1, 2,  5, /* right */
9485       2, 3,  6, /* top */
9486       0, 3,  7, /* left */
9487     };
9488     PetscInt  faceVerticesQuad[12] = {
9489       0, 1,  4, /* bottom */
9490       1, 2,  5, /* right */
9491       2, 3,  6, /* top */
9492       3, 0,  7, /* left */
9493     };
9494 
9495     faceSize = faceSizeQuad;
9496     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9497     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9498     for (iFace = 0; iFace < 4; ++iFace) {
9499       const PetscInt ii = iFace*faceSizeQuad;
9500       PetscInt       fVertex, cVertex;
9501 
9502       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9503           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9504         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9505           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9506             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9507               faceVertices[fVertex] = origVertices[cVertex];
9508               break;
9509             }
9510           }
9511         }
9512         found = PETSC_TRUE;
9513         break;
9514       }
9515     }
9516     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9517     if (posOriented) {*posOriented = PETSC_TRUE;}
9518     PetscFunctionReturn(0);
9519   } else if (cellDim == 3 && numCorners == 8) {
9520     /* Hexes
9521        A hex is two oriented quads with the normal of the first
9522        pointing up at the second.
9523 
9524           7---6
9525          /|  /|
9526         4---5 |
9527         | 3-|-2
9528         |/  |/
9529         0---1
9530 
9531         Faces are determined by the first 4 vertices (corners of faces) */
9532     const PetscInt faceSizeHex = 4;
9533     PetscInt  sortedIndices[4], i, iFace;
9534     PetscBool found = PETSC_FALSE;
9535     PetscInt faceVerticesHexSorted[24] = {
9536       0, 1, 2, 3,  /* bottom */
9537       4, 5, 6, 7,  /* top */
9538       0, 1, 4, 5,  /* front */
9539       1, 2, 5, 6,  /* right */
9540       2, 3, 6, 7,  /* back */
9541       0, 3, 4, 7,  /* left */
9542     };
9543     PetscInt faceVerticesHex[24] = {
9544       3, 2, 1, 0,  /* bottom */
9545       4, 5, 6, 7,  /* top */
9546       0, 1, 5, 4,  /* front */
9547       1, 2, 6, 5,  /* right */
9548       2, 3, 7, 6,  /* back */
9549       3, 0, 4, 7,  /* left */
9550     };
9551 
9552     faceSize = faceSizeHex;
9553     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9554     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9555     for (iFace = 0; iFace < 6; ++iFace) {
9556       const PetscInt ii = iFace*faceSizeHex;
9557       PetscInt       fVertex, cVertex;
9558 
9559       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9560           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9561           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9562           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9563         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9564           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9565             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9566               faceVertices[fVertex] = origVertices[cVertex];
9567               break;
9568             }
9569           }
9570         }
9571         found = PETSC_TRUE;
9572         break;
9573       }
9574     }
9575     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9576     if (posOriented) {*posOriented = PETSC_TRUE;}
9577     PetscFunctionReturn(0);
9578   } else if (cellDim == 3 && numCorners == 10) {
9579     /* Quadratic tet */
9580     /* Faces are determined by the first 3 vertices (corners of faces) */
9581     const PetscInt faceSizeTet = 6;
9582     PetscInt  sortedIndices[6], i, iFace;
9583     PetscBool found = PETSC_FALSE;
9584     PetscInt faceVerticesTetSorted[24] = {
9585       0, 1, 2,  6, 7, 8, /* bottom */
9586       0, 3, 4,  6, 7, 9,  /* front */
9587       1, 4, 5,  7, 8, 9,  /* right */
9588       2, 3, 5,  6, 8, 9,  /* left */
9589     };
9590     PetscInt faceVerticesTet[24] = {
9591       0, 1, 2,  6, 7, 8, /* bottom */
9592       0, 4, 3,  6, 7, 9,  /* front */
9593       1, 5, 4,  7, 8, 9,  /* right */
9594       2, 3, 5,  8, 6, 9,  /* left */
9595     };
9596 
9597     faceSize = faceSizeTet;
9598     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9599     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9600     for (iFace=0; iFace < 4; ++iFace) {
9601       const PetscInt ii = iFace*faceSizeTet;
9602       PetscInt       fVertex, cVertex;
9603 
9604       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9605           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9606           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9607           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9608         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9609           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9610             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9611               faceVertices[fVertex] = origVertices[cVertex];
9612               break;
9613             }
9614           }
9615         }
9616         found = PETSC_TRUE;
9617         break;
9618       }
9619     }
9620     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9621     if (posOriented) {*posOriented = PETSC_TRUE;}
9622     PetscFunctionReturn(0);
9623   } else if (cellDim == 3 && numCorners == 27) {
9624     /* Quadratic hexes (I hate this)
9625        A hex is two oriented quads with the normal of the first
9626        pointing up at the second.
9627 
9628          7---6
9629         /|  /|
9630        4---5 |
9631        | 3-|-2
9632        |/  |/
9633        0---1
9634 
9635        Faces are determined by the first 4 vertices (corners of faces) */
9636     const PetscInt faceSizeQuadHex = 9;
9637     PetscInt  sortedIndices[9], i, iFace;
9638     PetscBool found = PETSC_FALSE;
9639     PetscInt faceVerticesQuadHexSorted[54] = {
9640       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9641       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9642       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9643       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9644       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9645       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9646     };
9647     PetscInt faceVerticesQuadHex[54] = {
9648       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9649       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9650       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9651       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9652       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9653       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9654     };
9655 
9656     faceSize = faceSizeQuadHex;
9657     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9658     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9659     for (iFace = 0; iFace < 6; ++iFace) {
9660       const PetscInt ii = iFace*faceSizeQuadHex;
9661       PetscInt       fVertex, cVertex;
9662 
9663       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9664           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9665           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9666           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9667         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9668           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9669             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9670               faceVertices[fVertex] = origVertices[cVertex];
9671               break;
9672             }
9673           }
9674         }
9675         found = PETSC_TRUE;
9676         break;
9677       }
9678     }
9679     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9680     if (posOriented) {*posOriented = PETSC_TRUE;}
9681     PetscFunctionReturn(0);
9682   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9683   if (!posOrient) {
9684     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9685     for (f = 0; f < faceSize; ++f) {
9686       faceVertices[f] = origVertices[faceSize-1 - f];
9687     }
9688   } else {
9689     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9690     for (f = 0; f < faceSize; ++f) {
9691       faceVertices[f] = origVertices[f];
9692     }
9693   }
9694   if (posOriented) {*posOriented = posOrient;}
9695   PetscFunctionReturn(0);
9696 }
9697 
9698 #undef __FUNCT__
9699 #define __FUNCT__ "DMPlexGetOrientedFace"
9700 /*
9701     Given a cell and a face, as a set of vertices,
9702       return the oriented face, as a set of vertices, in faceVertices
9703     The orientation is such that the face normal points out of the cell
9704 */
9705 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9706 {
9707   const PetscInt *cone = PETSC_NULL;
9708   PetscInt        coneSize, v, f, v2;
9709   PetscInt        oppositeVertex = -1;
9710   PetscErrorCode  ierr;
9711 
9712   PetscFunctionBegin;
9713   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9714   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9715   for (v = 0, v2 = 0; v < coneSize; ++v) {
9716     PetscBool found  = PETSC_FALSE;
9717 
9718     for (f = 0; f < faceSize; ++f) {
9719       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9720     }
9721     if (found) {
9722       indices[v2]      = v;
9723       origVertices[v2] = cone[v];
9724       ++v2;
9725     } else {
9726       oppositeVertex = v;
9727     }
9728   }
9729   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9730   PetscFunctionReturn(0);
9731 }
9732 
9733 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9734 {
9735   switch (i) {
9736   case 0:
9737     switch (j) {
9738     case 0: return 0;
9739     case 1:
9740       switch (k) {
9741       case 0: return 0;
9742       case 1: return 0;
9743       case 2: return 1;
9744       }
9745     case 2:
9746       switch (k) {
9747       case 0: return 0;
9748       case 1: return -1;
9749       case 2: return 0;
9750       }
9751     }
9752   case 1:
9753     switch (j) {
9754     case 0:
9755       switch (k) {
9756       case 0: return 0;
9757       case 1: return 0;
9758       case 2: return -1;
9759       }
9760     case 1: return 0;
9761     case 2:
9762       switch (k) {
9763       case 0: return 1;
9764       case 1: return 0;
9765       case 2: return 0;
9766       }
9767     }
9768   case 2:
9769     switch (j) {
9770     case 0:
9771       switch (k) {
9772       case 0: return 0;
9773       case 1: return 1;
9774       case 2: return 0;
9775       }
9776     case 1:
9777       switch (k) {
9778       case 0: return -1;
9779       case 1: return 0;
9780       case 2: return 0;
9781       }
9782     case 2: return 0;
9783     }
9784   }
9785   return 0;
9786 }
9787 
9788 #undef __FUNCT__
9789 #define __FUNCT__ "DMPlexCreateRigidBody"
9790 /*@C
9791   DMPlexCreateRigidBody - create rigid body modes from coordinates
9792 
9793   Collective on DM
9794 
9795   Input Arguments:
9796 + dm - the DM
9797 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9798 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9799 
9800   Output Argument:
9801 . sp - the null space
9802 
9803   Note: This is necessary to take account of Dirichlet conditions on the displacements
9804 
9805   Level: advanced
9806 
9807 .seealso: MatNullSpaceCreate()
9808 @*/
9809 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9810 {
9811   MPI_Comm       comm = ((PetscObject) dm)->comm;
9812   Vec            coordinates, localMode, mode[6];
9813   PetscSection   coordSection;
9814   PetscScalar   *coords;
9815   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9816   PetscErrorCode ierr;
9817 
9818   PetscFunctionBegin;
9819   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9820   if (dim == 1) {
9821     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9822     PetscFunctionReturn(0);
9823   }
9824   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9825   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9826   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9827   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9828   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9829   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9830   m    = (dim*(dim+1))/2;
9831   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9832   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9833   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9834   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9835   /* Assume P1 */
9836   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9837   for (d = 0; d < dim; ++d) {
9838     PetscScalar values[3] = {0.0, 0.0, 0.0};
9839 
9840     values[d] = 1.0;
9841     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9842     for (v = vStart; v < vEnd; ++v) {
9843       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9844     }
9845     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9846     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9847   }
9848   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9849   for (d = dim; d < dim*(dim+1)/2; ++d) {
9850     PetscInt i, j, k = dim > 2 ? d - dim : d;
9851 
9852     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9853     for (v = vStart; v < vEnd; ++v) {
9854       PetscScalar values[3] = {0.0, 0.0, 0.0};
9855       PetscInt    off;
9856 
9857       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9858       for (i = 0; i < dim; ++i) {
9859         for (j = 0; j < dim; ++j) {
9860           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9861         }
9862       }
9863       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9864     }
9865     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9866     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9867   }
9868   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9869   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9870   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9871   /* Orthonormalize system */
9872   for (i = dim; i < m; ++i) {
9873     PetscScalar dots[6];
9874 
9875     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9876     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9877     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9878     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9879   }
9880   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9881   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9882   PetscFunctionReturn(0);
9883 }
9884 
9885 #undef __FUNCT__
9886 #define __FUNCT__ "DMPlexGetHybridBounds"
9887 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9888 {
9889   DM_Plex       *mesh = (DM_Plex *) dm->data;
9890   PetscInt       dim;
9891   PetscErrorCode ierr;
9892 
9893   PetscFunctionBegin;
9894   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9895   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9896   if (cMax) *cMax = mesh->hybridPointMax[dim];
9897   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9898   if (eMax) *eMax = mesh->hybridPointMax[1];
9899   if (vMax) *vMax = mesh->hybridPointMax[0];
9900   PetscFunctionReturn(0);
9901 }
9902 
9903 #undef __FUNCT__
9904 #define __FUNCT__ "DMPlexSetHybridBounds"
9905 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9906 {
9907   DM_Plex       *mesh = (DM_Plex *) dm->data;
9908   PetscInt       dim;
9909   PetscErrorCode ierr;
9910 
9911   PetscFunctionBegin;
9912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9913   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9914   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9915   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9916   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9917   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9918   PetscFunctionReturn(0);
9919 }
9920 
9921 #undef __FUNCT__
9922 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9923 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9924 {
9925   DM_Plex *mesh = (DM_Plex *) dm->data;
9926 
9927   PetscFunctionBegin;
9928   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9929   PetscValidPointer(cellHeight, 2);
9930   *cellHeight = mesh->vtkCellHeight;
9931   PetscFunctionReturn(0);
9932 }
9933 
9934 #undef __FUNCT__
9935 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9936 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9937 {
9938   DM_Plex *mesh = (DM_Plex *) dm->data;
9939 
9940   PetscFunctionBegin;
9941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9942   mesh->vtkCellHeight = cellHeight;
9943   PetscFunctionReturn(0);
9944 }
9945 
9946 #undef __FUNCT__
9947 #define __FUNCT__ "DMPlexInsertFace_Private"
9948 /*
9949   DMPlexInsertFace_Private - Puts a face into the mesh
9950 
9951   Not collective
9952 
9953   Input Parameters:
9954   + dm              - The DMPlex
9955   . numFaceVertex   - The number of vertices in the face
9956   . faceVertices    - The vertices in the face for dm
9957   . subfaceVertices - The vertices in the face for subdm
9958   . numCorners      - The number of vertices in the cell
9959   . cell            - A cell in dm containing the face
9960   . subcell         - A cell in subdm containing the face
9961   . firstFace       - First face in the mesh
9962   - newFacePoint    - Next face in the mesh
9963 
9964   Output Parameters:
9965   . newFacePoint - Contains next face point number on input, updated on output
9966 
9967   Level: developer
9968 */
9969 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)
9970 {
9971   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9972   DM_Plex     *submesh = (DM_Plex *) subdm->data;
9973   const PetscInt *faces;
9974   PetscInt        numFaces, coneSize;
9975   PetscErrorCode  ierr;
9976 
9977   PetscFunctionBegin;
9978   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9979   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9980 #if 0
9981   /* Cannot use this because support() has not been constructed yet */
9982   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9983 #else
9984   {
9985     PetscInt f;
9986 
9987     numFaces = 0;
9988     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
9989     for (f = firstFace; f < *newFacePoint; ++f) {
9990       PetscInt dof, off, d;
9991 
9992       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9993       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9994       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9995       for (d = 0; d < dof; ++d) {
9996         const PetscInt p = submesh->cones[off+d];
9997         PetscInt       v;
9998 
9999         for (v = 0; v < numFaceVertices; ++v) {
10000           if (subfaceVertices[v] == p) break;
10001         }
10002         if (v == numFaceVertices) break;
10003       }
10004       if (d == dof) {
10005         numFaces = 1;
10006         ((PetscInt *) faces)[0] = f;
10007       }
10008     }
10009   }
10010 #endif
10011   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
10012   else if (numFaces == 1) {
10013     /* Add the other cell neighbor for this face */
10014     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
10015   } else {
10016     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
10017     PetscBool posOriented;
10018 
10019     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10020     origVertices = &orientedVertices[numFaceVertices];
10021     indices      = &orientedVertices[numFaceVertices*2];
10022     orientedSubVertices = &orientedVertices[numFaceVertices*3];
10023     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
10024     /* TODO: I know that routine should return a permutation, not the indices */
10025     for (v = 0; v < numFaceVertices; ++v) {
10026       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
10027       for (ov = 0; ov < numFaceVertices; ++ov) {
10028         if (orientedVertices[ov] == vertex) {
10029           orientedSubVertices[ov] = subvertex;
10030           break;
10031         }
10032       }
10033       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
10034     }
10035     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
10036     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
10037     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10038     ++(*newFacePoint);
10039   }
10040   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10041   PetscFunctionReturn(0);
10042 }
10043 
10044 #undef __FUNCT__
10045 #define __FUNCT__ "DMPlexCreateSubmesh"
10046 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
10047 {
10048   MPI_Comm        comm = ((PetscObject) dm)->comm;
10049   DM_Plex     *submesh;
10050   PetscBool       boundaryFaces = PETSC_FALSE;
10051   PetscSection    coordSection, subCoordSection;
10052   Vec             coordinates, subCoordinates;
10053   PetscScalar    *coords, *subCoords;
10054   IS              labelIS;
10055   const PetscInt *subVertices;
10056   PetscInt       *subVerticesActive, *tmpPoints;
10057   PetscInt       *subCells = PETSC_NULL;
10058   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
10059   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
10060   PetscInt        dim; /* Right now, do not specify dimension */
10061   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
10062   PetscErrorCode  ierr;
10063 
10064   PetscFunctionBegin;
10065   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10066   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10067   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10068   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
10069   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10070   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10071   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10072   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10073   subface = &face[maxConeSize];
10074   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
10075   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10076   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10077   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
10078   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
10079   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
10080   maxSubCells = numSubVertices;
10081   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
10082   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
10083   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
10084   for (v = 0; v < numSubVertices; ++v) {
10085     const PetscInt vertex = subVertices[v];
10086     PetscInt *star = PETSC_NULL;
10087     PetscInt  starSize, numCells = 0;
10088 
10089     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10090     for (p = 0; p < starSize*2; p += 2) {
10091       const PetscInt point = star[p];
10092       if ((point >= cStart) && (point < cEnd)) {
10093         star[numCells++] = point;
10094       }
10095     }
10096     numOldSubCells = numSubCells;
10097     for (c = 0; c < numCells; ++c) {
10098       const PetscInt cell    = star[c];
10099       PetscInt      *closure = PETSC_NULL;
10100       PetscInt       closureSize, numCorners = 0, faceSize = 0;
10101       PetscInt       cellLoc;
10102 
10103       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
10104       if (cellLoc >= 0) continue;
10105       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10106       for (p = 0; p < closureSize*2; p += 2) {
10107         const PetscInt point = closure[p];
10108         if ((point >= vStart) && (point < vEnd)) {
10109           closure[numCorners++] = point;
10110         }
10111       }
10112       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
10113       for (corner = 0; corner < numCorners; ++corner) {
10114         const PetscInt cellVertex = closure[corner];
10115         PetscInt       subVertex;
10116 
10117         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
10118         if (subVertex >= 0) { /* contains submesh vertex */
10119           for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10120           if (i == faceSize) {
10121             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
10122             face[faceSize]    = cellVertex;
10123             subface[faceSize] = subVertex;
10124             ++faceSize;
10125           }
10126         }
10127       }
10128       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10129       if (faceSize >= nFV) {
10130         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10131         if (numSubCells >= maxSubCells) {
10132           PetscInt *tmpCells;
10133           maxSubCells *= 2;
10134           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
10135           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
10136           ierr = PetscFree(subCells);CHKERRQ(ierr);
10137           subCells = tmpCells;
10138         }
10139         /* TOOD: Maybe overestimate then squeeze out empty faces */
10140         if (faceSize > nFV) {
10141           /* TODO: This is tricky. Maybe just add all faces */
10142           numSubFaces++;
10143         } else {
10144           numSubFaces++;
10145         }
10146         for (f = 0; f < faceSize; ++f) {
10147           subVerticesActive[subface[f]] = 1;
10148         }
10149         subCells[numSubCells++] = cell;
10150       }
10151     }
10152     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10153     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
10154   }
10155   /* Pick out active subvertices */
10156   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
10157     if (subVerticesActive[v]) {
10158       subVerticesActive[numSubVerticesActive++] = subVertices[v];
10159     }
10160   }
10161   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
10162   /* Set cone sizes */
10163   firstSubVertex = numSubCells;
10164   firstSubFace   = numSubCells+numSubVerticesActive;
10165   newFacePoint   = firstSubFace;
10166   for (c = 0; c < numSubCells; ++c) {
10167     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
10168   }
10169   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
10170     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
10171   }
10172   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
10173   /* Create face cones */
10174   for (c = 0; c < numSubCells; ++c) {
10175     const PetscInt cell    = subCells[c];
10176     PetscInt      *closure = PETSC_NULL;
10177     PetscInt       closureSize, numCorners = 0, faceSize = 0;
10178 
10179     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10180     for (p = 0; p < closureSize*2; p += 2) {
10181       const PetscInt point = closure[p];
10182       if ((point >= vStart) && (point < vEnd)) {
10183         closure[numCorners++] = point;
10184       }
10185     }
10186     for (corner = 0; corner < numCorners; ++corner) {
10187       const PetscInt cellVertex = closure[corner];
10188       PetscInt       subVertex;
10189 
10190       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
10191       if (subVertex >= 0) { /* contains submesh vertex */
10192         for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10193         if (i == faceSize) {
10194           face[faceSize]    = cellVertex;
10195           subface[faceSize] = numSubCells+subVertex;
10196           ++faceSize;
10197         }
10198       }
10199     }
10200     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10201     if (faceSize >= nFV) {
10202       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10203       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
10204       /*   We have to take all the faces, and discard those in the interior */
10205       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
10206 #if 0
10207       /* This object just calls insert on each face that comes from subsets() */
10208       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
10209       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
10210       PointArray                          faceVec(face->begin(), face->end());
10211 
10212       subsets(faceVec, nFV, inserter);
10213 #endif
10214       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10215     }
10216   }
10217   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
10218   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
10219   /* Build coordinates */
10220   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10221   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10222   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
10223   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10224   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10225     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10226   }
10227   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10228   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10229   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
10230   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10231   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10232   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10233   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10234   for (v = 0; v < numSubVerticesActive; ++v) {
10235     const PetscInt vertex    = subVerticesActive[v];
10236     const PetscInt subVertex = firstSubVertex+v;
10237     PetscInt dof, off, sdof, soff;
10238 
10239     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10240     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10241     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10242     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10243     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10244     for (d = 0; d < dof; ++d) {
10245       subCoords[soff+d] = coords[off+d];
10246     }
10247   }
10248   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10249   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10250   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
10251   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10252 
10253   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
10254   /* Create map from submesh points to original mesh points */
10255   submesh = (DM_Plex *) (*subdm)->data;
10256   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10257   for (c = 0; c < numSubCells; ++c) {
10258     tmpPoints[c] = subCells[c];
10259   }
10260   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
10261     tmpPoints[v] = subVerticesActive[v-numSubCells];
10262   }
10263   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
10264 
10265   ierr = PetscFree(subCells);CHKERRQ(ierr);
10266   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10267   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10268   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10269   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10270   PetscFunctionReturn(0);
10271 }
10272 
10273 #undef __FUNCT__
10274 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10275 /* We can easily have a form that takes an IS instead */
10276 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10277 {
10278   PetscSection   section, globalSection;
10279   PetscInt      *numbers, p;
10280   PetscErrorCode ierr;
10281 
10282   PetscFunctionBegin;
10283   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10284   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10285   for (p = pStart; p < pEnd; ++p) {
10286     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10287   }
10288   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10289   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10290   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10291   for (p = pStart; p < pEnd; ++p) {
10292     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10293   }
10294   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10295   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10296   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10297   PetscFunctionReturn(0);
10298 }
10299 
10300 #undef __FUNCT__
10301 #define __FUNCT__ "DMPlexGetCellNumbering"
10302 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10303 {
10304   DM_Plex    *mesh = (DM_Plex *) dm->data;
10305   PetscInt       cellHeight, cStart, cEnd, cMax;
10306   PetscErrorCode ierr;
10307 
10308   PetscFunctionBegin;
10309   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10310   if (!mesh->globalCellNumbers) {
10311     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10312     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10313     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10314     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10315     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10316   }
10317   *globalCellNumbers = mesh->globalCellNumbers;
10318   PetscFunctionReturn(0);
10319 }
10320 
10321 #undef __FUNCT__
10322 #define __FUNCT__ "DMPlexGetVertexNumbering"
10323 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10324 {
10325   DM_Plex    *mesh = (DM_Plex *) dm->data;
10326   PetscInt       vStart, vEnd, vMax;
10327   PetscErrorCode ierr;
10328 
10329   PetscFunctionBegin;
10330   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10331   if (!mesh->globalVertexNumbers) {
10332     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10333     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10334     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10335     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10336   }
10337   *globalVertexNumbers = mesh->globalVertexNumbers;
10338   PetscFunctionReturn(0);
10339 }
10340 
10341 #undef __FUNCT__
10342 #define __FUNCT__ "DMPlexGetSubpointMap"
10343 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10344 {
10345   DM_Plex *mesh = (DM_Plex *) dm->data;
10346 
10347   PetscFunctionBegin;
10348   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10349   PetscValidPointer(subpointMap, 2);
10350   *subpointMap = mesh->subpointMap;
10351   PetscFunctionReturn(0);
10352 }
10353 
10354 #undef __FUNCT__
10355 #define __FUNCT__ "DMPlexSetSubpointMap"
10356 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10357 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10358 {
10359   DM_Plex *mesh = (DM_Plex *) dm->data;
10360 
10361   PetscFunctionBegin;
10362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10363   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10364   mesh->subpointMap = subpointMap;
10365   PetscFunctionReturn(0);
10366 }
10367 
10368 #undef __FUNCT__
10369 #define __FUNCT__ "DMPlexGetScale"
10370 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10371 {
10372   DM_Plex *mesh = (DM_Plex *) dm->data;
10373 
10374   PetscFunctionBegin;
10375   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10376   PetscValidPointer(scale, 3);
10377   *scale = mesh->scale[unit];
10378   PetscFunctionReturn(0);
10379 }
10380 
10381 #undef __FUNCT__
10382 #define __FUNCT__ "DMPlexSetScale"
10383 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10384 {
10385   DM_Plex *mesh = (DM_Plex *) dm->data;
10386 
10387   PetscFunctionBegin;
10388   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10389   mesh->scale[unit] = scale;
10390   PetscFunctionReturn(0);
10391 }
10392 
10393 
10394 /*******************************************************************************
10395 This should be in a separate Discretization object, but I am not sure how to lay
10396 it out yet, so I am stuffing things here while I experiment.
10397 *******************************************************************************/
10398 #undef __FUNCT__
10399 #define __FUNCT__ "DMPlexSetFEMIntegration"
10400 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10401                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10402                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10403                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10404                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10405                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10406                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10407                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10408                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10409                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10410                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10411                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10412                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10413                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10414                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10415                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10416                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10417 {
10418   DM_Plex *mesh = (DM_Plex *) dm->data;
10419 
10420   PetscFunctionBegin;
10421   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10422   mesh->integrateResidualFEM       = integrateResidualFEM;
10423   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10424   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10425   PetscFunctionReturn(0);
10426 }
10427 
10428 #undef __FUNCT__
10429 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10430 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10431 {
10432   Vec            coordinates;
10433   PetscSection   section, cSection;
10434   PetscInt       dim, vStart, vEnd, v, c, d;
10435   PetscScalar   *values, *cArray;
10436   PetscReal     *coords;
10437   PetscErrorCode ierr;
10438 
10439   PetscFunctionBegin;
10440   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10441   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10442   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10443   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10444   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10445   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10446   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10447   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10448   for (v = vStart; v < vEnd; ++v) {
10449     PetscInt dof, off;
10450 
10451     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10452     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10453     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10454     for (d = 0; d < dof; ++d) {
10455       coords[d] = PetscRealPart(cArray[off+d]);
10456     }
10457     for (c = 0; c < numComp; ++c) {
10458       values[c] = (*funcs[c])(coords);
10459     }
10460     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10461   }
10462   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10463   /* Temporary, must be replaced by a projection on the finite element basis */
10464   {
10465     PetscInt eStart = 0, eEnd = 0, e, depth;
10466 
10467     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10468     --depth;
10469     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10470     for (e = eStart; e < eEnd; ++e) {
10471       const PetscInt *cone = PETSC_NULL;
10472       PetscInt        coneSize, d;
10473       PetscScalar    *coordsA, *coordsB;
10474 
10475       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10476       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10477       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10478       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10479       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10480       for (d = 0; d < dim; ++d) {
10481         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10482       }
10483       for (c = 0; c < numComp; ++c) {
10484         values[c] = (*funcs[c])(coords);
10485       }
10486       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10487     }
10488   }
10489 
10490   ierr = PetscFree(coords);CHKERRQ(ierr);
10491   ierr = PetscFree(values);CHKERRQ(ierr);
10492 #if 0
10493   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10494   PetscReal      detJ;
10495 
10496   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10497   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10498   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10499 
10500   for (PetscInt c = cStart; c < cEnd; ++c) {
10501     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10502     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10503     const int                          oSize   = pV.getSize();
10504     int                                v       = 0;
10505 
10506     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10507     for (PetscInt cl = 0; cl < oSize; ++cl) {
10508       const PetscInt fDim;
10509 
10510       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10511       if (pointDim) {
10512         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10513           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10514         }
10515       }
10516     }
10517     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10518     pV.clear();
10519   }
10520   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10521   ierr = PetscFree(values);CHKERRQ(ierr);
10522 #endif
10523   PetscFunctionReturn(0);
10524 }
10525 
10526 #undef __FUNCT__
10527 #define __FUNCT__ "DMPlexProjectFunction"
10528 /*@C
10529   DMPlexProjectFunction - This projects the given function into the function space provided.
10530 
10531   Input Parameters:
10532 + dm      - The DM
10533 . numComp - The number of components (functions)
10534 . funcs   - The coordinate functions to evaluate
10535 - mode    - The insertion mode for values
10536 
10537   Output Parameter:
10538 . X - vector
10539 
10540   Level: developer
10541 
10542   Note:
10543   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10544   We will eventually fix it.
10545 
10546 ,seealso: DMPlexComputeL2Diff()
10547 */
10548 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10549 {
10550   Vec            localX;
10551   PetscErrorCode ierr;
10552 
10553   PetscFunctionBegin;
10554   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10555   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10556   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10557   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10558   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10559   PetscFunctionReturn(0);
10560 }
10561 
10562 #undef __FUNCT__
10563 #define __FUNCT__ "DMPlexComputeL2Diff"
10564 /*@C
10565   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10566 
10567   Input Parameters:
10568 + dm    - The DM
10569 . quad  - The PetscQuadrature object for each field
10570 . funcs - The functions to evaluate for each field component
10571 - X     - The coefficient vector u_h
10572 
10573   Output Parameter:
10574 . diff - The diff ||u - u_h||_2
10575 
10576   Level: developer
10577 
10578 .seealso: DMPlexProjectFunction()
10579 */
10580 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10581 {
10582   const PetscInt   debug = 0;
10583   PetscSection     section;
10584   Vec              localX;
10585   PetscReal       *coords, *v0, *J, *invJ, detJ;
10586   PetscReal        localDiff = 0.0;
10587   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10588   PetscErrorCode   ierr;
10589 
10590   PetscFunctionBegin;
10591   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10592   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10593   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10594   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10595   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10596   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10597   for (field = 0; field < numFields; ++field) {
10598     numComponents += quad[field].numComponents;
10599   }
10600   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10601   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10602   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10603   for (c = cStart; c < cEnd; ++c) {
10604     const PetscScalar *x;
10605     PetscReal          elemDiff = 0.0;
10606 
10607     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10608     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10609     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10610 
10611     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10612       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10613       const PetscReal *quadPoints    = quad[field].quadPoints;
10614       const PetscReal *quadWeights   = quad[field].quadWeights;
10615       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10616       const PetscInt   numBasisComps = quad[field].numComponents;
10617       const PetscReal *basis         = quad[field].basis;
10618       PetscInt         q, d, e, fc, f;
10619 
10620       if (debug) {
10621         char title[1024];
10622         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10623         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10624       }
10625       for (q = 0; q < numQuadPoints; ++q) {
10626         for (d = 0; d < dim; d++) {
10627           coords[d] = v0[d];
10628           for (e = 0; e < dim; e++) {
10629             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10630           }
10631         }
10632         for (fc = 0; fc < numBasisComps; ++fc) {
10633           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10634           PetscReal       interpolant = 0.0;
10635           for (f = 0; f < numBasisFuncs; ++f) {
10636             const PetscInt fidx = f*numBasisComps+fc;
10637             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10638           }
10639           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10640           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10641         }
10642       }
10643       comp        += numBasisComps;
10644       fieldOffset += numBasisFuncs*numBasisComps;
10645     }
10646     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10647     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10648     localDiff += elemDiff;
10649   }
10650   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10651   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10652   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10653   *diff = PetscSqrtReal(*diff);
10654   PetscFunctionReturn(0);
10655 }
10656 
10657 #undef __FUNCT__
10658 #define __FUNCT__ "DMPlexComputeResidualFEM"
10659 /*@
10660   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10661 
10662   Input Parameters:
10663 + dm - The mesh
10664 . X  - Local input vector
10665 - user - The user context
10666 
10667   Output Parameter:
10668 . F  - Local output vector
10669 
10670   Note:
10671   The second member of the user context must be an FEMContext.
10672 
10673   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10674   like a GPU, or vectorize on a multicore machine.
10675 
10676 .seealso: DMPlexComputeJacobianActionFEM()
10677 */
10678 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10679 {
10680   DM_Plex      *mesh = (DM_Plex *) dm->data;
10681   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10682   PetscQuadrature *quad = fem->quad;
10683   PetscSection     section;
10684   PetscReal       *v0, *J, *invJ, *detJ;
10685   PetscScalar     *elemVec, *u;
10686   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10687   PetscInt         cellDof = 0, numComponents = 0;
10688   PetscErrorCode   ierr;
10689 
10690   PetscFunctionBegin;
10691   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10692   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10693   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10694   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10695   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10696   numCells = cEnd - cStart;
10697   for (field = 0; field < numFields; ++field) {
10698     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10699     numComponents += quad[field].numComponents;
10700   }
10701   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10702   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10703   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);
10704   for (c = cStart; c < cEnd; ++c) {
10705     const PetscScalar *x;
10706     PetscInt           i;
10707 
10708     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10709     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10710     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10711 
10712     for (i = 0; i < cellDof; ++i) {
10713       u[c*cellDof+i] = x[i];
10714     }
10715     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10716   }
10717   for (field = 0; field < numFields; ++field) {
10718     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10719     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10720     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10721     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10722     /* Conforming batches */
10723     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10724     PetscInt numBlocks  = 1;
10725     PetscInt batchSize  = numBlocks * blockSize;
10726     PetscInt numBatches = numBatchesTmp;
10727     PetscInt numChunks  = numCells / (numBatches*batchSize);
10728     /* Remainder */
10729     PetscInt numRemainder = numCells % (numBatches * batchSize);
10730     PetscInt offset       = numCells - numRemainder;
10731 
10732     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10733     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10734                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10735   }
10736   for (c = cStart; c < cEnd; ++c) {
10737     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10738     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10739   }
10740   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10741   if (mesh->printFEM) {
10742     PetscMPIInt rank, numProcs;
10743     PetscInt    p;
10744 
10745     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10746     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10747     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10748     for (p = 0; p < numProcs; ++p) {
10749       if (p == rank) {
10750         Vec f;
10751 
10752         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10753         ierr = VecCopy(F, f);CHKERRQ(ierr);
10754         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10755         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10756         ierr = VecDestroy(&f);CHKERRQ(ierr);
10757         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10758       }
10759       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10760     }
10761   }
10762   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10763   PetscFunctionReturn(0);
10764 }
10765 
10766 #undef __FUNCT__
10767 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10768 /*@C
10769   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10770 
10771   Input Parameters:
10772 + dm - The mesh
10773 . J  - The Jacobian shell matrix
10774 . X  - Local input vector
10775 - user - The user context
10776 
10777   Output Parameter:
10778 . F  - Local output vector
10779 
10780   Note:
10781   The second member of the user context must be an FEMContext.
10782 
10783   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10784   like a GPU, or vectorize on a multicore machine.
10785 
10786 .seealso: DMPlexComputeResidualFEM()
10787 */
10788 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10789 {
10790   DM_Plex      *mesh = (DM_Plex *) dm->data;
10791   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10792   PetscQuadrature *quad = fem->quad;
10793   PetscSection     section;
10794   JacActionCtx    *jctx;
10795   PetscReal       *v0, *J, *invJ, *detJ;
10796   PetscScalar     *elemVec, *u, *a;
10797   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10798   PetscInt         cellDof = 0;
10799   PetscErrorCode   ierr;
10800 
10801   PetscFunctionBegin;
10802   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10803   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10804   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10805   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10806   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10807   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10808   numCells = cEnd - cStart;
10809   for (field = 0; field < numFields; ++field) {
10810     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10811   }
10812   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10813   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);
10814   for (c = cStart; c < cEnd; ++c) {
10815     const PetscScalar *x;
10816     PetscInt           i;
10817 
10818     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10819     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10820     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10821     for (i = 0; i < cellDof; ++i) {
10822       u[c*cellDof+i] = x[i];
10823     }
10824     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10825     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10826     for (i = 0; i < cellDof; ++i) {
10827       a[c*cellDof+i] = x[i];
10828     }
10829     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10830   }
10831   for (field = 0; field < numFields; ++field) {
10832     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10833     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10834     /* Conforming batches */
10835     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10836     PetscInt numBlocks  = 1;
10837     PetscInt batchSize  = numBlocks * blockSize;
10838     PetscInt numBatches = numBatchesTmp;
10839     PetscInt numChunks  = numCells / (numBatches*batchSize);
10840     /* Remainder */
10841     PetscInt numRemainder = numCells % (numBatches * batchSize);
10842     PetscInt offset       = numCells - numRemainder;
10843 
10844     ierr = (*mesh->integrateJacobianActionFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, a, v0, J, invJ, detJ, fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, elemVec);CHKERRQ(ierr);
10845     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],
10846                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10847   }
10848   for (c = cStart; c < cEnd; ++c) {
10849     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10850     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10851   }
10852   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10853   if (mesh->printFEM) {
10854     PetscMPIInt rank, numProcs;
10855     PetscInt    p;
10856 
10857     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10858     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10859     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10860     for (p = 0; p < numProcs; ++p) {
10861       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10862       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10863     }
10864   }
10865   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10866   PetscFunctionReturn(0);
10867 }
10868 
10869 #undef __FUNCT__
10870 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10871 /*@
10872   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10873 
10874   Input Parameters:
10875 + dm - The mesh
10876 . X  - Local input vector
10877 - user - The user context
10878 
10879   Output Parameter:
10880 . Jac  - Jacobian matrix
10881 
10882   Note:
10883   The second member of the user context must be an FEMContext.
10884 
10885   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10886   like a GPU, or vectorize on a multicore machine.
10887 
10888 .seealso: FormFunctionLocal()
10889 */
10890 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10891 {
10892   DM_Plex      *mesh = (DM_Plex *) dm->data;
10893   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10894   PetscQuadrature *quad = fem->quad;
10895   PetscSection     section;
10896   PetscReal       *v0, *J, *invJ, *detJ;
10897   PetscScalar     *elemMat, *u;
10898   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10899   PetscInt         cellDof = 0, numComponents = 0;
10900   PetscBool        isShell;
10901   PetscErrorCode   ierr;
10902 
10903   PetscFunctionBegin;
10904   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10905   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10906   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10907   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10908   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10909   numCells = cEnd - cStart;
10910   for (field = 0; field < numFields; ++field) {
10911     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10912     numComponents += quad[field].numComponents;
10913   }
10914   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10915   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10916   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);
10917   for (c = cStart; c < cEnd; ++c) {
10918     const PetscScalar *x;
10919     PetscInt           i;
10920 
10921     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10922     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10923     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10924 
10925     for (i = 0; i < cellDof; ++i) {
10926       u[c*cellDof+i] = x[i];
10927     }
10928     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10929   }
10930   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10931   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10932     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10933     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10934     PetscInt       fieldJ;
10935 
10936     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10937       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10938       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10939       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10940       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10941       /* Conforming batches */
10942       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10943       PetscInt numBlocks  = 1;
10944       PetscInt batchSize  = numBlocks * blockSize;
10945       PetscInt numBatches = numBatchesTmp;
10946       PetscInt numChunks  = numCells / (numBatches*batchSize);
10947       /* Remainder */
10948       PetscInt numRemainder = numCells % (numBatches * batchSize);
10949       PetscInt offset       = numCells - numRemainder;
10950 
10951       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10952       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10953                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10954     }
10955   }
10956   for (c = cStart; c < cEnd; ++c) {
10957     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10958     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10959   }
10960   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10961 
10962   /* Assemble matrix, using the 2-step process:
10963        MatAssemblyBegin(), MatAssemblyEnd(). */
10964   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10965   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10966 
10967   if (mesh->printFEM) {
10968     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10969     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10970     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10971   }
10972   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10973   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10974   if (isShell) {
10975     JacActionCtx *jctx;
10976 
10977     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10978     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10979   }
10980   *str = SAME_NONZERO_PATTERN;
10981   PetscFunctionReturn(0);
10982 }
10983 
10984 
10985 #undef __FUNCT__
10986 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10987 /*@C
10988   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10989   the local section and an SF describing the section point overlap.
10990 
10991   Input Parameters:
10992   + s - The PetscSection for the local field layout
10993   . sf - The SF describing parallel layout of the section points
10994   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10995   . label - The label specifying the points
10996   - labelValue - The label stratum specifying the points
10997 
10998   Output Parameter:
10999   . gsection - The PetscSection for the global field layout
11000 
11001   Note: This gives negative sizes and offsets to points not owned by this process
11002 
11003   Level: developer
11004 
11005 .seealso: PetscSectionCreate()
11006 @*/
11007 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
11008 {
11009   PetscInt      *neg;
11010   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
11011   PetscErrorCode ierr;
11012 
11013   PetscFunctionBegin;
11014   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
11015   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
11016   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
11017   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
11018   /* Mark ghost points with negative dof */
11019   for (p = pStart; p < pEnd; ++p) {
11020     PetscInt value;
11021 
11022     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11023     if (value != labelValue) continue;
11024     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11025     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11026     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11027     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11028     neg[p-pStart] = -(dof+1);
11029   }
11030   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11031   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11032   if (nroots >= 0) {
11033     if (nroots > pEnd - pStart) {
11034       PetscInt *tmpDof;
11035       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11036       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11037       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11038       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11039       for (p = pStart; p < pEnd; ++p) {
11040         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
11041       }
11042       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11043     } else {
11044       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11045       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11046     }
11047   }
11048   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11049   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11050     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11051     (*gsection)->atlasOff[p] = off;
11052     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11053   }
11054   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11055   globalOff -= off;
11056   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11057     (*gsection)->atlasOff[p] += globalOff;
11058     neg[p] = -((*gsection)->atlasOff[p]+1);
11059   }
11060   /* Put in negative offsets for ghost points */
11061   if (nroots >= 0) {
11062     if (nroots > pEnd - pStart) {
11063       PetscInt *tmpOff;
11064       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11065       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11066       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11067       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11068       for (p = pStart; p < pEnd; ++p) {
11069         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
11070       }
11071       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11072     } else {
11073       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11074       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11075     }
11076   }
11077   ierr = PetscFree(neg);CHKERRQ(ierr);
11078   PetscFunctionReturn(0);
11079 }
11080