xref: /petsc/src/dm/impls/plex/plex.c (revision ce94432eddcd14845bc7e8083b7f8ea723b9bf7d)
1 #include <petsc-private/pleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/vecimpl.h>
4 
5 /* Logging support */
6 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
7 
8 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
9 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
10 
11 #undef __FUNCT__
12 #define __FUNCT__ "VecView_Plex_Local"
13 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
14 {
15   DM             dm;
16   PetscBool      isvtk;
17   PetscErrorCode ierr;
18 
19   PetscFunctionBegin;
20   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
21   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
22   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
23   if (isvtk) {
24     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
25     PetscSection            section;
26     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
27 
28     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
29     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, NULL);CHKERRQ(ierr);
32     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, NULL);CHKERRQ(ierr);
33     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
34     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
35     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
36     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
37     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
38     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
39       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
40     } else if (cdof && vdof) {
41       SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
42     } else if (cdof) {
43       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
44        * vector or just happens to have the same number of dofs as the dimension. */
45       if (cdof == dim) {
46         ft = PETSC_VTK_CELL_VECTOR_FIELD;
47       } else {
48         ft = PETSC_VTK_CELL_FIELD;
49       }
50     } else if (vdof) {
51       if (vdof == dim) {
52         ft = PETSC_VTK_POINT_VECTOR_FIELD;
53       } else {
54         ft = PETSC_VTK_POINT_FIELD;
55       }
56     } else SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
57 
58     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
59     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
60     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
61   } else {
62     PetscBool isseq;
63 
64     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
65     if (isseq) {
66       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
67     } else {
68       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
69     }
70   }
71   PetscFunctionReturn(0);
72 }
73 
74 #undef __FUNCT__
75 #define __FUNCT__ "VecView_Plex"
76 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
77 {
78   DM             dm;
79   PetscBool      isvtk;
80   PetscErrorCode ierr;
81 
82   PetscFunctionBegin;
83   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
84   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
85   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
86   if (isvtk) {
87     Vec         locv;
88     const char *name;
89 
90     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
91     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
92     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
95     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
96     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
97   } else {
98     PetscBool isseq;
99 
100     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
101     if (isseq) {
102       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
103     } else {
104       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
105     }
106   }
107   PetscFunctionReturn(0);
108 }
109 
110 #undef __FUNCT__
111 #define __FUNCT__ "DMPlexView_Ascii"
112 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
113 {
114   DM_Plex          *mesh = (DM_Plex*) dm->data;
115   DM                cdm;
116   DMLabel           markers;
117   PetscSection      coordSection;
118   Vec               coordinates;
119   PetscViewerFormat format;
120   PetscErrorCode    ierr;
121 
122   PetscFunctionBegin;
123   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
124   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
125   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
126   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
127   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
128     const char *name;
129     PetscInt    maxConeSize, maxSupportSize;
130     PetscInt    pStart, pEnd, p;
131     PetscMPIInt rank, size;
132 
133     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
134     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
135     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
136     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
137     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
138     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
139     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
140     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
142     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
143     for (p = pStart; p < pEnd; ++p) {
144       PetscInt dof, off, s;
145 
146       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
147       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
148       for (s = off; s < off+dof; ++s) {
149         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
150       }
151     }
152     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
153     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
154     for (p = pStart; p < pEnd; ++p) {
155       PetscInt dof, off, c;
156 
157       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
158       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
159       for (c = off; c < off+dof; ++c) {
160         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
161       }
162     }
163     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
164     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
165     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
166     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
167     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
168     if (size > 1) {
169       PetscSF sf;
170 
171       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
172       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
173     }
174     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
175   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
176     const char  *name;
177     const char  *colors[3] = {"red", "blue", "green"};
178     const int    numColors  = 3;
179     PetscReal    scale      = 2.0;
180     PetscScalar *coords;
181     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
182     PetscMPIInt  rank, size;
183 
184     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
185     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
186     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
187     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
188     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
189     ierr = PetscViewerASCIIPrintf(viewer, "\
190 \\documentclass[crop,multi=false]{standalone}\n\n\
191 \\usepackage{tikz}\n\
192 \\usepackage{pgflibraryshapes}\n\
193 \\usetikzlibrary{backgrounds}\n\
194 \\usetikzlibrary{arrows}\n\
195 \\begin{document}\n\
196 \\section{%s}\n\
197 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
198     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
199     for (p = 0; p < size; ++p) {
200       if (p > 0 && p == size-1) {
201         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
202       } else if (p > 0) {
203         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
204       }
205       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
206     }
207     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
208 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
209     /* Plot vertices */
210     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
211     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
212     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
213     for (v = vStart; v < vEnd; ++v) {
214       PetscInt off, dof, d;
215 
216       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
217       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
218       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
219       for (d = 0; d < dof; ++d) {
220         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
221         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
222       }
223       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
224     }
225     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
226     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
227     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
228     /* Plot edges */
229     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
230     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
231     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
232     for (e = eStart; e < eEnd; ++e) {
233       const PetscInt *cone;
234       PetscInt        coneSize, offA, offB, dof, d;
235 
236       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
237       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
238       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
239       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
240       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
242       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
243       for (d = 0; d < dof; ++d) {
244         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
245         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
246       }
247       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
248     }
249     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
250     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
251     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
252     /* Plot cells */
253     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
254     for (c = cStart; c < cEnd; ++c) {
255       PetscInt *closure = NULL;
256       PetscInt  closureSize, firstPoint = -1;
257 
258       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
259       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
260       for (p = 0; p < closureSize*2; p += 2) {
261         const PetscInt point = closure[p];
262 
263         if ((point < vStart) || (point >= vEnd)) continue;
264         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
265         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
266         if (firstPoint < 0) firstPoint = point;
267       }
268       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
269       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
270       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
271     }
272     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
273     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
275   } else {
276     MPI_Comm    comm = ((PetscObject) dm)->comm;
277     PetscInt   *sizes;
278     PetscInt    locDepth, depth, dim, d;
279     PetscInt    pStart, pEnd, p;
280     PetscMPIInt size;
281 
282     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
283     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
284     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
285     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
286     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
287     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
288     if (depth == 1) {
289       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
290       pEnd = pEnd - pStart;
291       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
292       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
293       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
294       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
295       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
296       pEnd = pEnd - pStart;
297       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
298       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
299       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
300       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
301     } else {
302       for (d = 0; d <= dim; d++) {
303         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
304         pEnd = pEnd - pStart;
305         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
306         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
307         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
308         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
309       }
310     }
311     ierr = PetscFree(sizes);CHKERRQ(ierr);
312   }
313   PetscFunctionReturn(0);
314 }
315 
316 #undef __FUNCT__
317 #define __FUNCT__ "DMView_Plex"
318 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
319 {
320   PetscBool      iascii, isbinary;
321   PetscErrorCode ierr;
322 
323   PetscFunctionBegin;
324   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
325   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
326   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
327   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
328   if (iascii) {
329     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
330 #if 0
331   } else if (isbinary) {
332     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
333 #endif
334   }
335   PetscFunctionReturn(0);
336 }
337 
338 #undef __FUNCT__
339 #define __FUNCT__ "DMDestroy_Plex"
340 PetscErrorCode DMDestroy_Plex(DM dm)
341 {
342   DM_Plex       *mesh = (DM_Plex*) dm->data;
343   DMLabel        next  = mesh->labels;
344   PetscErrorCode ierr;
345 
346   PetscFunctionBegin;
347   if (--mesh->refct > 0) PetscFunctionReturn(0);
348   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
349   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
350   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
351   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
353   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
354   while (next) {
355     DMLabel tmp = next->next;
356 
357     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
358     next = tmp;
359   }
360   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
361   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
362   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
363   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
364   ierr = PetscFree(mesh);CHKERRQ(ierr);
365   PetscFunctionReturn(0);
366 }
367 
368 #undef __FUNCT__
369 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
370 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
371 {
372   const PetscInt *support = NULL;
373   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
374   PetscErrorCode  ierr;
375 
376   PetscFunctionBegin;
377   if (useClosure) {
378     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
379     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
380     for (s = 0; s < supportSize; ++s) {
381       const PetscInt *cone = NULL;
382       PetscInt        coneSize, c, q;
383 
384       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
385       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
386       for (c = 0; c < coneSize; ++c) {
387         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
388           if (cone[c] == adj[q]) break;
389         }
390         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
391       }
392     }
393   } else {
394     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
395     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
396     for (s = 0; s < supportSize; ++s) {
397       const PetscInt *cone = NULL;
398       PetscInt        coneSize, c, q;
399 
400       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
401       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
402       for (c = 0; c < coneSize; ++c) {
403         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
404           if (cone[c] == adj[q]) break;
405         }
406         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
407       }
408     }
409   }
410   *adjSize = numAdj;
411   PetscFunctionReturn(0);
412 }
413 
414 #undef __FUNCT__
415 #define __FUNCT__ "DMPlexGetAdjacency_Private"
416 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
417 {
418   const PetscInt *star  = tmpClosure;
419   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
420   PetscErrorCode  ierr;
421 
422   PetscFunctionBegin;
423   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
424   for (s = 2; s < starSize*2; s += 2) {
425     const PetscInt *closure = NULL;
426     PetscInt        closureSize, c, q;
427 
428     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
429     for (c = 0; c < closureSize*2; c += 2) {
430       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
431         if (closure[c] == adj[q]) break;
432       }
433       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
434     }
435     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
436   }
437   *adjSize = numAdj;
438   PetscFunctionReturn(0);
439 }
440 
441 #undef __FUNCT__
442 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
443 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
444 {
445   DM_Plex *mesh = (DM_Plex*) dm->data;
446 
447   PetscFunctionBegin;
448   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
449   mesh->preallocCenterDim = preallocCenterDim;
450   PetscFunctionReturn(0);
451 }
452 
453 #undef __FUNCT__
454 #define __FUNCT__ "DMPlexPreallocateOperator"
455 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
456 {
457   DM_Plex           *mesh = (DM_Plex*) dm->data;
458   MPI_Comm           comm  = ((PetscObject) dm)->comm;
459   PetscSF            sf, sfDof, sfAdj;
460   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
461   PetscInt           nleaves, l, p;
462   const PetscInt    *leaves;
463   const PetscSFNode *remotes;
464   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
465   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
466   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
467   PetscLayout        rLayout;
468   PetscInt           locRows, rStart, rEnd, r;
469   PetscMPIInt        size;
470   PetscBool          useClosure, debug = PETSC_FALSE;
471   PetscErrorCode     ierr;
472 
473   PetscFunctionBegin;
474   ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr);
475   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
476   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
477   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
478   /* Create dof SF based on point SF */
479   if (debug) {
480     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
481     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
482     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
483     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
484     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
485     ierr = PetscSFView(sf, NULL);CHKERRQ(ierr);
486   }
487   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
488   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
489   if (debug) {
490     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
491     ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr);
492   }
493   /* Create section for dof adjacency (dof ==> # adj dof) */
494   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
495   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
496   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
497   if (mesh->preallocCenterDim == dim) {
498     useClosure = PETSC_FALSE;
499   } else if (mesh->preallocCenterDim == 0) {
500     useClosure = PETSC_TRUE;
501   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
502 
503   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
504   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
505   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
506   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
507   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
508   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
509   /*   Fill in the ghost dofs on the interface */
510   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
511   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
512   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
513 
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 
517   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
518 
519   /*
520    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
521     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
522        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
523     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
524        Create sfAdj connecting rootSectionAdj and leafSectionAdj
525     3. Visit unowned points on interface, write adjacencies to adj
526        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
527     4. Visit owned points on interface, write adjacencies to rootAdj
528        Remove redundancy in rootAdj
529    ** The last two traversals use transitive closure
530     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
531        Allocate memory addressed by sectionAdj (cols)
532     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
533    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
534   */
535 
536   for (l = 0; l < nleaves; ++l) {
537     PetscInt dof, off, d, q;
538     PetscInt p = leaves[l], numAdj = maxAdjSize;
539 
540     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
541     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
542     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
543     for (q = 0; q < numAdj; ++q) {
544       PetscInt ndof, ncdof;
545 
546       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
547       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
548       for (d = off; d < off+dof; ++d) {
549         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
550       }
551     }
552   }
553   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
554   if (debug) {
555     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
556     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
557   }
558   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
559   if (size > 1) {
560     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
562   }
563   if (debug) {
564     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
565     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
566   }
567   /* Add in local adjacency sizes for owned dofs on interface (roots) */
568   for (p = pStart; p < pEnd; ++p) {
569     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
570 
571     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
572     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
573     if (!dof) continue;
574     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
575     if (adof <= 0) continue;
576     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
577     for (q = 0; q < numAdj; ++q) {
578       PetscInt ndof, ncdof;
579 
580       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
581       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
582       for (d = off; d < off+dof; ++d) {
583         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
584       }
585     }
586   }
587   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
588   if (debug) {
589     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
590     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
591   }
592   /* Create adj SF based on dof SF */
593   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
594   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
595   if (debug) {
596     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
597     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
598   }
599   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
600   /* Create leaf adjacency */
601   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
602   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
603   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
604   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
605   for (l = 0; l < nleaves; ++l) {
606     PetscInt dof, off, d, q;
607     PetscInt p = leaves[l], numAdj = maxAdjSize;
608 
609     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
610     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
611     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
612     for (d = off; d < off+dof; ++d) {
613       PetscInt aoff, i = 0;
614 
615       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
616       for (q = 0; q < numAdj; ++q) {
617         PetscInt ndof, ncdof, ngoff, nd;
618 
619         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
620         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
621         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
622         for (nd = 0; nd < ndof-ncdof; ++nd) {
623           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
624           ++i;
625         }
626       }
627     }
628   }
629   /* Debugging */
630   if (debug) {
631     IS tmp;
632     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
633     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
634     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
635   }
636   /* Gather adjacenct indices to root */
637   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
638   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
639   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
640   if (size > 1) {
641     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
642     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
643   }
644   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
645   ierr = PetscFree(adj);CHKERRQ(ierr);
646   /* Debugging */
647   if (debug) {
648     IS tmp;
649     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
650     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
651     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
652   }
653   /* Add in local adjacency indices for owned dofs on interface (roots) */
654   for (p = pStart; p < pEnd; ++p) {
655     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
656 
657     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
658     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
659     if (!dof) continue;
660     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
661     if (adof <= 0) continue;
662     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
663     for (d = off; d < off+dof; ++d) {
664       PetscInt adof, aoff, i;
665 
666       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
667       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
668       i    = adof-1;
669       for (q = 0; q < numAdj; ++q) {
670         PetscInt ndof, ncdof, ngoff, nd;
671 
672         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
673         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
674         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
675         for (nd = 0; nd < ndof-ncdof; ++nd) {
676           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
677           --i;
678         }
679       }
680     }
681   }
682   /* Debugging */
683   if (debug) {
684     IS tmp;
685     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
686     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
687     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
688   }
689   /* Compress indices */
690   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
691   for (p = pStart; p < pEnd; ++p) {
692     PetscInt dof, cdof, off, d;
693     PetscInt adof, aoff;
694 
695     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
696     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
697     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
698     if (!dof) continue;
699     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
700     if (adof <= 0) continue;
701     for (d = off; d < off+dof-cdof; ++d) {
702       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
703       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
704       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
705       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
706     }
707   }
708   /* Debugging */
709   if (debug) {
710     IS tmp;
711     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
712     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
713     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
714     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
715     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
716   }
717   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
718   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
719   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
720   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
721   for (p = pStart; p < pEnd; ++p) {
722     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
723     PetscBool found  = PETSC_TRUE;
724 
725     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
726     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
727     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
728     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
729     for (d = 0; d < dof-cdof; ++d) {
730       PetscInt ldof, rdof;
731 
732       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
733       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
734       if (ldof > 0) {
735         /* We do not own this point */
736       } else if (rdof > 0) {
737         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
738       } else {
739         found = PETSC_FALSE;
740       }
741     }
742     if (found) continue;
743     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
744     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
745     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
746     for (q = 0; q < numAdj; ++q) {
747       PetscInt ndof, ncdof, noff;
748 
749       /* Adjacent points may not be in the section chart */
750       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
751       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
752       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
753       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
754       for (d = goff; d < goff+dof-cdof; ++d) {
755         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
756       }
757     }
758   }
759   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
760   if (debug) {
761     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
762     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
763   }
764   /* Get adjacent indices */
765   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
766   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
767   for (p = pStart; p < pEnd; ++p) {
768     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
769     PetscBool found  = PETSC_TRUE;
770 
771     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
772     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
773     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
774     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
775     for (d = 0; d < dof-cdof; ++d) {
776       PetscInt ldof, rdof;
777 
778       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
779       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
780       if (ldof > 0) {
781         /* We do not own this point */
782       } else if (rdof > 0) {
783         PetscInt aoff, roff;
784 
785         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
786         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
787         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
788       } else {
789         found = PETSC_FALSE;
790       }
791     }
792     if (found) continue;
793     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
794     for (d = goff; d < goff+dof-cdof; ++d) {
795       PetscInt adof, aoff, i = 0;
796 
797       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
798       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
799       for (q = 0; q < numAdj; ++q) {
800         PetscInt        ndof, ncdof, ngoff, nd;
801         const PetscInt *ncind;
802 
803         /* Adjacent points may not be in the section chart */
804         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
805         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
806         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
807         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
808         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
809         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
810           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
811         }
812       }
813       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);
814     }
815   }
816   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
817   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
818   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
819   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
820   /* Debugging */
821   if (debug) {
822     IS tmp;
823     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
824     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
825     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
826   }
827   /* Create allocation vectors from adjacency graph */
828   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
829   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
830   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
831   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
832   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
833   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
834   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
835   /* Only loop over blocks of rows */
836   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);
837   for (r = rStart/bs; r < rEnd/bs; ++r) {
838     const PetscInt row = r*bs;
839     PetscInt       numCols, cStart, c;
840 
841     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
842     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
843     for (c = cStart; c < cStart+numCols; ++c) {
844       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
845         ++dnz[r-rStart];
846         if (cols[c] >= row) ++dnzu[r-rStart];
847       } else {
848         ++onz[r-rStart];
849         if (cols[c] >= row) ++onzu[r-rStart];
850       }
851     }
852   }
853   if (bs > 1) {
854     for (r = 0; r < locRows/bs; ++r) {
855       dnz[r]  /= bs;
856       onz[r]  /= bs;
857       dnzu[r] /= bs;
858       onzu[r] /= bs;
859     }
860   }
861   /* Set matrix pattern */
862   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
863   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
864   /* Fill matrix with zeros */
865   if (fillMatrix) {
866     PetscScalar *values;
867     PetscInt     maxRowLen = 0;
868 
869     for (r = rStart; r < rEnd; ++r) {
870       PetscInt len;
871 
872       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
873       maxRowLen = PetscMax(maxRowLen, len);
874     }
875     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
876     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
877     for (r = rStart; r < rEnd; ++r) {
878       PetscInt numCols, cStart;
879 
880       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
881       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
882       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
883     }
884     ierr = PetscFree(values);CHKERRQ(ierr);
885     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
886     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
887   }
888   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
889   ierr = PetscFree(cols);CHKERRQ(ierr);
890   PetscFunctionReturn(0);
891 }
892 
893 #if 0
894 #undef __FUNCT__
895 #define __FUNCT__ "DMPlexPreallocateOperator_2"
896 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
897 {
898   PetscInt       *tmpClosure,*tmpAdj,*visits;
899   PetscInt        c,cStart,cEnd,pStart,pEnd;
900   PetscErrorCode  ierr;
901 
902   PetscFunctionBegin;
903   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
904   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
905   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
906 
907   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
908 
909   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
910   npoints = pEnd - pStart;
911 
912   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
913   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
914   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
915   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
916   for (c=cStart; c<cEnd; c++) {
917     PetscInt *support = tmpClosure;
918     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
919     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
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(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, bsMax, bsMin;
983 
984     if (bs < 0) {
985       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
986         PetscInt pStart, pEnd, p, dof, cdof;
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           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
992           if (dof-cdof) {
993             if (bs < 0) {
994               bs = dof-cdof;
995             } else if (bs != dof-cdof) {
996               /* Layout does not admit a pointwise block size */
997               bs = 1;
998               break;
999             }
1000           }
1001         }
1002         /* Must have same blocksize on all procs (some might have no points) */
1003         bsLocal = bs;
1004         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1005         bsLocal = bs < 0 ? bsMax : bs;
1006         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1007         if (bsMin != bsMax) {
1008           bs = 1;
1009         } else {
1010           bs = bsMax;
1011         }
1012       } else {
1013         bs = 1;
1014       }
1015     }
1016     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1017     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1018     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1019     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1020     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1021     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1022     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1023   }
1024   PetscFunctionReturn(0);
1025 }
1026 
1027 #undef __FUNCT__
1028 #define __FUNCT__ "DMPlexGetDimension"
1029 /*@
1030   DMPlexGetDimension - Return the topological mesh dimension
1031 
1032   Not collective
1033 
1034   Input Parameter:
1035 . mesh - The DMPlex
1036 
1037   Output Parameter:
1038 . dim - The topological mesh dimension
1039 
1040   Level: beginner
1041 
1042 .seealso: DMPlexCreate()
1043 @*/
1044 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1045 {
1046   DM_Plex *mesh = (DM_Plex*) dm->data;
1047 
1048   PetscFunctionBegin;
1049   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1050   PetscValidPointer(dim, 2);
1051   *dim = mesh->dim;
1052   PetscFunctionReturn(0);
1053 }
1054 
1055 #undef __FUNCT__
1056 #define __FUNCT__ "DMPlexSetDimension"
1057 /*@
1058   DMPlexSetDimension - Set the topological mesh dimension
1059 
1060   Collective on mesh
1061 
1062   Input Parameters:
1063 + mesh - The DMPlex
1064 - dim - The topological mesh dimension
1065 
1066   Level: beginner
1067 
1068 .seealso: DMPlexCreate()
1069 @*/
1070 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1071 {
1072   DM_Plex *mesh = (DM_Plex*) dm->data;
1073 
1074   PetscFunctionBegin;
1075   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1076   PetscValidLogicalCollectiveInt(dm, dim, 2);
1077   mesh->dim               = dim;
1078   mesh->preallocCenterDim = dim;
1079   PetscFunctionReturn(0);
1080 }
1081 
1082 #undef __FUNCT__
1083 #define __FUNCT__ "DMPlexGetChart"
1084 /*@
1085   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1086 
1087   Not collective
1088 
1089   Input Parameter:
1090 . mesh - The DMPlex
1091 
1092   Output Parameters:
1093 + pStart - The first mesh point
1094 - pEnd   - The upper bound for mesh points
1095 
1096   Level: beginner
1097 
1098 .seealso: DMPlexCreate(), DMPlexSetChart()
1099 @*/
1100 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1101 {
1102   DM_Plex       *mesh = (DM_Plex*) dm->data;
1103   PetscErrorCode ierr;
1104 
1105   PetscFunctionBegin;
1106   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1107   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1108   PetscFunctionReturn(0);
1109 }
1110 
1111 #undef __FUNCT__
1112 #define __FUNCT__ "DMPlexSetChart"
1113 /*@
1114   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1115 
1116   Not collective
1117 
1118   Input Parameters:
1119 + mesh - The DMPlex
1120 . pStart - The first mesh point
1121 - pEnd   - The upper bound for mesh points
1122 
1123   Output Parameters:
1124 
1125   Level: beginner
1126 
1127 .seealso: DMPlexCreate(), DMPlexGetChart()
1128 @*/
1129 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1130 {
1131   DM_Plex       *mesh = (DM_Plex*) dm->data;
1132   PetscErrorCode ierr;
1133 
1134   PetscFunctionBegin;
1135   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1136   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1137   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1138   PetscFunctionReturn(0);
1139 }
1140 
1141 #undef __FUNCT__
1142 #define __FUNCT__ "DMPlexGetConeSize"
1143 /*@
1144   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1145 
1146   Not collective
1147 
1148   Input Parameters:
1149 + mesh - The DMPlex
1150 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1151 
1152   Output Parameter:
1153 . size - The cone size for point p
1154 
1155   Level: beginner
1156 
1157 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1158 @*/
1159 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1160 {
1161   DM_Plex       *mesh = (DM_Plex*) dm->data;
1162   PetscErrorCode ierr;
1163 
1164   PetscFunctionBegin;
1165   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1166   PetscValidPointer(size, 3);
1167   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1168   PetscFunctionReturn(0);
1169 }
1170 
1171 #undef __FUNCT__
1172 #define __FUNCT__ "DMPlexSetConeSize"
1173 /*@
1174   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1175 
1176   Not collective
1177 
1178   Input Parameters:
1179 + mesh - The DMPlex
1180 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1181 - size - The cone size for point p
1182 
1183   Output Parameter:
1184 
1185   Note:
1186   This should be called after DMPlexSetChart().
1187 
1188   Level: beginner
1189 
1190 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1191 @*/
1192 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1193 {
1194   DM_Plex       *mesh = (DM_Plex*) dm->data;
1195   PetscErrorCode ierr;
1196 
1197   PetscFunctionBegin;
1198   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1199   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1200 
1201   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1202   PetscFunctionReturn(0);
1203 }
1204 
1205 #undef __FUNCT__
1206 #define __FUNCT__ "DMPlexGetCone"
1207 /*@C
1208   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1209 
1210   Not collective
1211 
1212   Input Parameters:
1213 + mesh - The DMPlex
1214 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1215 
1216   Output Parameter:
1217 . cone - An array of points which are on the in-edges for point p
1218 
1219   Level: beginner
1220 
1221   Note:
1222   This routine is not available in Fortran.
1223 
1224 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1225 @*/
1226 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1227 {
1228   DM_Plex       *mesh = (DM_Plex*) dm->data;
1229   PetscInt       off;
1230   PetscErrorCode ierr;
1231 
1232   PetscFunctionBegin;
1233   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1234   PetscValidPointer(cone, 3);
1235   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1236   *cone = &mesh->cones[off];
1237   PetscFunctionReturn(0);
1238 }
1239 
1240 #undef __FUNCT__
1241 #define __FUNCT__ "DMPlexSetCone"
1242 /*@
1243   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1244 
1245   Not collective
1246 
1247   Input Parameters:
1248 + mesh - The DMPlex
1249 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1250 - cone - An array of points which are on the in-edges for point p
1251 
1252   Output Parameter:
1253 
1254   Note:
1255   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1256 
1257   Level: beginner
1258 
1259 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1260 @*/
1261 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1262 {
1263   DM_Plex       *mesh = (DM_Plex*) dm->data;
1264   PetscInt       pStart, pEnd;
1265   PetscInt       dof, off, c;
1266   PetscErrorCode ierr;
1267 
1268   PetscFunctionBegin;
1269   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1270   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1271   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1272   if (dof) PetscValidPointer(cone, 3);
1273   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1274   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);
1275   for (c = 0; c < dof; ++c) {
1276     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);
1277     mesh->cones[off+c] = cone[c];
1278   }
1279   PetscFunctionReturn(0);
1280 }
1281 
1282 #undef __FUNCT__
1283 #define __FUNCT__ "DMPlexGetConeOrientation"
1284 /*@C
1285   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1286 
1287   Not collective
1288 
1289   Input Parameters:
1290 + mesh - The DMPlex
1291 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1292 
1293   Output Parameter:
1294 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1295                     integer giving the prescription for cone traversal. If it is negative, the cone is
1296                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1297                     the index of the cone point on which to start.
1298 
1299   Level: beginner
1300 
1301   Note:
1302   This routine is not available in Fortran.
1303 
1304 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1305 @*/
1306 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1307 {
1308   DM_Plex       *mesh = (DM_Plex*) dm->data;
1309   PetscInt       off;
1310   PetscErrorCode ierr;
1311 
1312   PetscFunctionBegin;
1313   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1314 #if defined(PETSC_USE_DEBUG)
1315   {
1316     PetscInt dof;
1317     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1318     if (dof) PetscValidPointer(coneOrientation, 3);
1319   }
1320 #endif
1321   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1322 
1323   *coneOrientation = &mesh->coneOrientations[off];
1324   PetscFunctionReturn(0);
1325 }
1326 
1327 #undef __FUNCT__
1328 #define __FUNCT__ "DMPlexSetConeOrientation"
1329 /*@
1330   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1331 
1332   Not collective
1333 
1334   Input Parameters:
1335 + mesh - The DMPlex
1336 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1337 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1338                     integer giving the prescription for cone traversal. If it is negative, the cone is
1339                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1340                     the index of the cone point on which to start.
1341 
1342   Output Parameter:
1343 
1344   Note:
1345   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1346 
1347   Level: beginner
1348 
1349 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1350 @*/
1351 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1352 {
1353   DM_Plex       *mesh = (DM_Plex*) dm->data;
1354   PetscInt       pStart, pEnd;
1355   PetscInt       dof, off, c;
1356   PetscErrorCode ierr;
1357 
1358   PetscFunctionBegin;
1359   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1360   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1361   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1362   if (dof) PetscValidPointer(coneOrientation, 3);
1363   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1364   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);
1365   for (c = 0; c < dof; ++c) {
1366     PetscInt cdof, o = coneOrientation[c];
1367 
1368     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1369     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);
1370     mesh->coneOrientations[off+c] = o;
1371   }
1372   PetscFunctionReturn(0);
1373 }
1374 
1375 #undef __FUNCT__
1376 #define __FUNCT__ "DMPlexInsertCone"
1377 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1378 {
1379   DM_Plex       *mesh = (DM_Plex*) dm->data;
1380   PetscInt       pStart, pEnd;
1381   PetscInt       dof, off;
1382   PetscErrorCode ierr;
1383 
1384   PetscFunctionBegin;
1385   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1386   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1387   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1388   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1389   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);
1390   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);
1391   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);
1392   mesh->cones[off+conePos] = conePoint;
1393   PetscFunctionReturn(0);
1394 }
1395 
1396 #undef __FUNCT__
1397 #define __FUNCT__ "DMPlexGetSupportSize"
1398 /*@
1399   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1400 
1401   Not collective
1402 
1403   Input Parameters:
1404 + mesh - The DMPlex
1405 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1406 
1407   Output Parameter:
1408 . size - The support size for point p
1409 
1410   Level: beginner
1411 
1412 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1413 @*/
1414 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1415 {
1416   DM_Plex       *mesh = (DM_Plex*) dm->data;
1417   PetscErrorCode ierr;
1418 
1419   PetscFunctionBegin;
1420   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1421   PetscValidPointer(size, 3);
1422   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1423   PetscFunctionReturn(0);
1424 }
1425 
1426 #undef __FUNCT__
1427 #define __FUNCT__ "DMPlexSetSupportSize"
1428 /*@
1429   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1430 
1431   Not collective
1432 
1433   Input Parameters:
1434 + mesh - The DMPlex
1435 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1436 - size - The support size for point p
1437 
1438   Output Parameter:
1439 
1440   Note:
1441   This should be called after DMPlexSetChart().
1442 
1443   Level: beginner
1444 
1445 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1446 @*/
1447 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1448 {
1449   DM_Plex       *mesh = (DM_Plex*) dm->data;
1450   PetscErrorCode ierr;
1451 
1452   PetscFunctionBegin;
1453   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1454   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1455 
1456   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1457   PetscFunctionReturn(0);
1458 }
1459 
1460 #undef __FUNCT__
1461 #define __FUNCT__ "DMPlexGetSupport"
1462 /*@C
1463   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1464 
1465   Not collective
1466 
1467   Input Parameters:
1468 + mesh - The DMPlex
1469 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1470 
1471   Output Parameter:
1472 . support - An array of points which are on the out-edges for point p
1473 
1474   Level: beginner
1475 
1476 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1477 @*/
1478 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1479 {
1480   DM_Plex       *mesh = (DM_Plex*) dm->data;
1481   PetscInt       off;
1482   PetscErrorCode ierr;
1483 
1484   PetscFunctionBegin;
1485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1486   PetscValidPointer(support, 3);
1487   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1488   *support = &mesh->supports[off];
1489   PetscFunctionReturn(0);
1490 }
1491 
1492 #undef __FUNCT__
1493 #define __FUNCT__ "DMPlexSetSupport"
1494 /*@
1495   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1496 
1497   Not collective
1498 
1499   Input Parameters:
1500 + mesh - The DMPlex
1501 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1502 - support - An array of points which are on the in-edges for point p
1503 
1504   Output Parameter:
1505 
1506   Note:
1507   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1508 
1509   Level: beginner
1510 
1511 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1512 @*/
1513 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1514 {
1515   DM_Plex       *mesh = (DM_Plex*) dm->data;
1516   PetscInt       pStart, pEnd;
1517   PetscInt       dof, off, c;
1518   PetscErrorCode ierr;
1519 
1520   PetscFunctionBegin;
1521   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1522   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1523   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1524   if (dof) PetscValidPointer(support, 3);
1525   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1526   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);
1527   for (c = 0; c < dof; ++c) {
1528     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);
1529     mesh->supports[off+c] = support[c];
1530   }
1531   PetscFunctionReturn(0);
1532 }
1533 
1534 #undef __FUNCT__
1535 #define __FUNCT__ "DMPlexInsertSupport"
1536 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1537 {
1538   DM_Plex       *mesh = (DM_Plex*) dm->data;
1539   PetscInt       pStart, pEnd;
1540   PetscInt       dof, off;
1541   PetscErrorCode ierr;
1542 
1543   PetscFunctionBegin;
1544   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1545   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1546   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1547   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1548   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);
1549   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);
1550   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);
1551   mesh->supports[off+supportPos] = supportPoint;
1552   PetscFunctionReturn(0);
1553 }
1554 
1555 #undef __FUNCT__
1556 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1557 /*@C
1558   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1559 
1560   Not collective
1561 
1562   Input Parameters:
1563 + mesh - The DMPlex
1564 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1565 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1566 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1567 
1568   Output Parameters:
1569 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1570 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1571 
1572   Note:
1573   If using internal storage (points is NULL on input), each call overwrites the last output.
1574 
1575   Level: beginner
1576 
1577 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1578 @*/
1579 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1580 {
1581   DM_Plex        *mesh = (DM_Plex*) dm->data;
1582   PetscInt       *closure, *fifo;
1583   const PetscInt *tmp = NULL, *tmpO = NULL;
1584   PetscInt        tmpSize, t;
1585   PetscInt        depth       = 0, maxSize;
1586   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1587   PetscErrorCode  ierr;
1588 
1589   PetscFunctionBegin;
1590   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1591   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1592   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1593   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1594   if (*points) {
1595     closure = *points;
1596   } else {
1597     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1598   }
1599   closure[0] = p; closure[1] = 0;
1600   /* This is only 1-level */
1601   if (useCone) {
1602     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1603     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1604     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1605   } else {
1606     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1607     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1608   }
1609   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1610     const PetscInt cp = tmp[t];
1611     const PetscInt co = tmpO ? tmpO[t] : 0;
1612 
1613     closure[closureSize]   = cp;
1614     closure[closureSize+1] = co;
1615     fifo[fifoSize]         = cp;
1616     fifo[fifoSize+1]       = co;
1617   }
1618   while (fifoSize - fifoStart) {
1619     const PetscInt q   = fifo[fifoStart];
1620     const PetscInt o   = fifo[fifoStart+1];
1621     const PetscInt rev = o >= 0 ? 0 : 1;
1622     const PetscInt off = rev ? -(o+1) : o;
1623 
1624     if (useCone) {
1625       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1626       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1627       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1628     } else {
1629       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1630       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1631       tmpO = NULL;
1632     }
1633     for (t = 0; t < tmpSize; ++t) {
1634       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1635       const PetscInt cp = tmp[i];
1636       /* Must propogate orientation */
1637       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1638       PetscInt       c;
1639 
1640       /* Check for duplicate */
1641       for (c = 0; c < closureSize; c += 2) {
1642         if (closure[c] == cp) break;
1643       }
1644       if (c == closureSize) {
1645         closure[closureSize]   = cp;
1646         closure[closureSize+1] = co;
1647         fifo[fifoSize]         = cp;
1648         fifo[fifoSize+1]       = co;
1649         closureSize           += 2;
1650         fifoSize              += 2;
1651       }
1652     }
1653     fifoStart += 2;
1654   }
1655   if (numPoints) *numPoints = closureSize/2;
1656   if (points)    *points    = closure;
1657   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1658   PetscFunctionReturn(0);
1659 }
1660 
1661 #undef __FUNCT__
1662 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1663 /*@C
1664   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1665 
1666   Not collective
1667 
1668   Input Parameters:
1669 + mesh - The DMPlex
1670 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1671 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1672 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1673 
1674   Output Parameters:
1675 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1676 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1677 
1678   Note:
1679   If not using internal storage (points is not NULL on input), this call is unnecessary
1680 
1681   Level: beginner
1682 
1683 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1684 @*/
1685 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1686 {
1687   PetscErrorCode ierr;
1688 
1689   PetscFunctionBegin;
1690   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1691   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1692   PetscFunctionReturn(0);
1693 }
1694 
1695 #undef __FUNCT__
1696 #define __FUNCT__ "DMPlexGetFaces"
1697 /*
1698   DMPlexGetFaces -
1699 
1700   Note: This will only work for cell-vertex meshes.
1701 */
1702 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1703 {
1704   DM_Plex        *mesh = (DM_Plex*) dm->data;
1705   const PetscInt *cone = NULL;
1706   PetscInt        depth = 0, dim, coneSize;
1707   PetscErrorCode  ierr;
1708 
1709   PetscFunctionBegin;
1710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1711   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1712   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1713   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1714   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1715   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1716   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1717   switch (dim) {
1718   case 2:
1719     switch (coneSize) {
1720     case 3:
1721       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1722       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1723       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1724       *numFaces         = 3;
1725       *faceSize         = 2;
1726       *faces            = mesh->facesTmp;
1727       break;
1728     case 4:
1729       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1730       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1731       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1732       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1733       *numFaces         = 4;
1734       *faceSize         = 2;
1735       *faces            = mesh->facesTmp;
1736       break;
1737     default:
1738       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1739     }
1740     break;
1741   case 3:
1742     switch (coneSize) {
1743     case 3:
1744       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1745       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1746       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1747       *numFaces         = 3;
1748       *faceSize         = 2;
1749       *faces            = mesh->facesTmp;
1750       break;
1751     case 4:
1752       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1753       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1754       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1755       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1756       *numFaces         = 4;
1757       *faceSize         = 3;
1758       *faces            = mesh->facesTmp;
1759       break;
1760     default:
1761       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1762     }
1763     break;
1764   default:
1765     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1766   }
1767   PetscFunctionReturn(0);
1768 }
1769 
1770 #undef __FUNCT__
1771 #define __FUNCT__ "DMPlexGetMaxSizes"
1772 /*@
1773   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1774 
1775   Not collective
1776 
1777   Input Parameter:
1778 . mesh - The DMPlex
1779 
1780   Output Parameters:
1781 + maxConeSize - The maximum number of in-edges
1782 - maxSupportSize - The maximum number of out-edges
1783 
1784   Level: beginner
1785 
1786 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1787 @*/
1788 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1789 {
1790   DM_Plex *mesh = (DM_Plex*) dm->data;
1791 
1792   PetscFunctionBegin;
1793   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1794   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1795   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1796   PetscFunctionReturn(0);
1797 }
1798 
1799 #undef __FUNCT__
1800 #define __FUNCT__ "DMSetUp_Plex"
1801 PetscErrorCode DMSetUp_Plex(DM dm)
1802 {
1803   DM_Plex       *mesh = (DM_Plex*) dm->data;
1804   PetscInt       size;
1805   PetscErrorCode ierr;
1806 
1807   PetscFunctionBegin;
1808   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1809   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1810   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1811   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1812   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1813   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1814   if (mesh->maxSupportSize) {
1815     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1816     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1817     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1818   }
1819   PetscFunctionReturn(0);
1820 }
1821 
1822 #undef __FUNCT__
1823 #define __FUNCT__ "DMCreateSubDM_Plex"
1824 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1825 {
1826   PetscSection   section, sectionGlobal;
1827   PetscInt      *subIndices;
1828   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1829   PetscErrorCode ierr;
1830 
1831   PetscFunctionBegin;
1832   if (!numFields) PetscFunctionReturn(0);
1833   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1834   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1835   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1836   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1837   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1838   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);
1839   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1840   for (p = pStart; p < pEnd; ++p) {
1841     PetscInt gdof;
1842 
1843     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1844     if (gdof > 0) {
1845       for (f = 0; f < numFields; ++f) {
1846         PetscInt fdof, fcdof;
1847 
1848         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1849         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1850         subSize += fdof-fcdof;
1851       }
1852     }
1853   }
1854   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1855   for (p = pStart; p < pEnd; ++p) {
1856     PetscInt gdof, goff;
1857 
1858     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1859     if (gdof > 0) {
1860       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1861       for (f = 0; f < numFields; ++f) {
1862         PetscInt fdof, fcdof, fc, f2, poff = 0;
1863 
1864         /* Can get rid of this loop by storing field information in the global section */
1865         for (f2 = 0; f2 < fields[f]; ++f2) {
1866           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1867           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1868           poff += fdof-fcdof;
1869         }
1870         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1871         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1872         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1873           subIndices[subOff] = goff+poff+fc;
1874         }
1875       }
1876     }
1877   }
1878   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1879   if (subdm) {
1880     PetscSection subsection;
1881     PetscBool    haveNull = PETSC_FALSE;
1882     PetscInt     f, nf = 0;
1883 
1884     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1885     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1886     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1887     for (f = 0; f < numFields; ++f) {
1888       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1889       if ((*subdm)->nullspaceConstructors[f]) {
1890         haveNull = PETSC_TRUE;
1891         nf       = f;
1892       }
1893     }
1894     if (haveNull) {
1895       MatNullSpace nullSpace;
1896 
1897       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1898       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1899       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1900     }
1901     if (dm->fields) {
1902       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);
1903       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1904       for (f = 0; f < numFields; ++f) {
1905         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1906       }
1907       if (numFields == 1) {
1908         MatNullSpace space;
1909         Mat          pmat;
1910 
1911         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1912         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1913         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1914         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1915         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1916         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1917       }
1918     }
1919   }
1920   PetscFunctionReturn(0);
1921 }
1922 
1923 #undef __FUNCT__
1924 #define __FUNCT__ "DMPlexSymmetrize"
1925 /*@
1926   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1927 
1928   Not collective
1929 
1930   Input Parameter:
1931 . mesh - The DMPlex
1932 
1933   Output Parameter:
1934 
1935   Note:
1936   This should be called after all calls to DMPlexSetCone()
1937 
1938   Level: beginner
1939 
1940 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1941 @*/
1942 PetscErrorCode DMPlexSymmetrize(DM dm)
1943 {
1944   DM_Plex       *mesh = (DM_Plex*) dm->data;
1945   PetscInt      *offsets;
1946   PetscInt       supportSize;
1947   PetscInt       pStart, pEnd, p;
1948   PetscErrorCode ierr;
1949 
1950   PetscFunctionBegin;
1951   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1952   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1953   /* Calculate support sizes */
1954   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1955   for (p = pStart; p < pEnd; ++p) {
1956     PetscInt dof, off, c;
1957 
1958     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1959     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1960     for (c = off; c < off+dof; ++c) {
1961       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1962     }
1963   }
1964   for (p = pStart; p < pEnd; ++p) {
1965     PetscInt dof;
1966 
1967     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1968 
1969     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1970   }
1971   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1972   /* Calculate supports */
1973   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1974   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1975   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1976   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1977   for (p = pStart; p < pEnd; ++p) {
1978     PetscInt dof, off, c;
1979 
1980     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1981     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1982     for (c = off; c < off+dof; ++c) {
1983       const PetscInt q = mesh->cones[c];
1984       PetscInt       offS;
1985 
1986       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1987 
1988       mesh->supports[offS+offsets[q]] = p;
1989       ++offsets[q];
1990     }
1991   }
1992   ierr = PetscFree(offsets);CHKERRQ(ierr);
1993   PetscFunctionReturn(0);
1994 }
1995 
1996 #undef __FUNCT__
1997 #define __FUNCT__ "DMPlexSetDepth_Private"
1998 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1999 {
2000   PetscInt       d;
2001   PetscErrorCode ierr;
2002 
2003   PetscFunctionBegin;
2004   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2005   if (d < 0) {
2006     /* We are guaranteed that the point has a cone since the depth was not yet set */
2007     const PetscInt *cone = NULL;
2008     PetscInt        dCone;
2009 
2010     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2011     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2012     d    = dCone+1;
2013     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2014   }
2015   *depth = d;
2016   PetscFunctionReturn(0);
2017 }
2018 
2019 #undef __FUNCT__
2020 #define __FUNCT__ "DMPlexStratify"
2021 /*@
2022   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2023   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2024   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2025   the DAG.
2026 
2027   Not collective
2028 
2029   Input Parameter:
2030 . mesh - The DMPlex
2031 
2032   Output Parameter:
2033 
2034   Notes:
2035   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2036   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2037 
2038   This should be called after all calls to DMPlexSymmetrize()
2039 
2040   Level: beginner
2041 
2042 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2043 @*/
2044 PetscErrorCode DMPlexStratify(DM dm)
2045 {
2046   DM_Plex       *mesh = (DM_Plex*) dm->data;
2047   PetscInt       pStart, pEnd, p;
2048   PetscInt       numRoots = 0, numLeaves = 0;
2049   PetscErrorCode ierr;
2050 
2051   PetscFunctionBegin;
2052   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2053   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2054   /* Calculate depth */
2055   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2056   /* Initialize roots and count leaves */
2057   for (p = pStart; p < pEnd; ++p) {
2058     PetscInt coneSize, supportSize;
2059 
2060     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2061     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2062     if (!coneSize && supportSize) {
2063       ++numRoots;
2064       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2065     } else if (!supportSize && coneSize) {
2066       ++numLeaves;
2067     } else if (!supportSize && !coneSize) {
2068       /* Isolated points */
2069       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2070     }
2071   }
2072   if (numRoots + numLeaves == (pEnd - pStart)) {
2073     for (p = pStart; p < pEnd; ++p) {
2074       PetscInt coneSize, supportSize;
2075 
2076       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2077       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2078       if (!supportSize && coneSize) {
2079         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2080       }
2081     }
2082   } else {
2083     /* This might be slow since lookup is not fast */
2084     for (p = pStart; p < pEnd; ++p) {
2085       PetscInt depth;
2086 
2087       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2088     }
2089   }
2090   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2091   PetscFunctionReturn(0);
2092 }
2093 
2094 #undef __FUNCT__
2095 #define __FUNCT__ "DMPlexGetJoin"
2096 /*@C
2097   DMPlexGetJoin - Get an array for the join of the set of points
2098 
2099   Not Collective
2100 
2101   Input Parameters:
2102 + dm - The DMPlex object
2103 . numPoints - The number of input points for the join
2104 - points - The input points
2105 
2106   Output Parameters:
2107 + numCoveredPoints - The number of points in the join
2108 - coveredPoints - The points in the join
2109 
2110   Level: intermediate
2111 
2112   Note: Currently, this is restricted to a single level join
2113 
2114 .keywords: mesh
2115 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2116 @*/
2117 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2118 {
2119   DM_Plex       *mesh = (DM_Plex*) dm->data;
2120   PetscInt      *join[2];
2121   PetscInt       joinSize, i = 0;
2122   PetscInt       dof, off, p, c, m;
2123   PetscErrorCode ierr;
2124 
2125   PetscFunctionBegin;
2126   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2127   PetscValidPointer(points, 2);
2128   PetscValidPointer(numCoveredPoints, 3);
2129   PetscValidPointer(coveredPoints, 4);
2130   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2131   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2132   /* Copy in support of first point */
2133   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2134   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2135   for (joinSize = 0; joinSize < dof; ++joinSize) {
2136     join[i][joinSize] = mesh->supports[off+joinSize];
2137   }
2138   /* Check each successive support */
2139   for (p = 1; p < numPoints; ++p) {
2140     PetscInt newJoinSize = 0;
2141 
2142     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2143     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2144     for (c = 0; c < dof; ++c) {
2145       const PetscInt point = mesh->supports[off+c];
2146 
2147       for (m = 0; m < joinSize; ++m) {
2148         if (point == join[i][m]) {
2149           join[1-i][newJoinSize++] = point;
2150           break;
2151         }
2152       }
2153     }
2154     joinSize = newJoinSize;
2155     i        = 1-i;
2156   }
2157   *numCoveredPoints = joinSize;
2158   *coveredPoints    = join[i];
2159   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2160   PetscFunctionReturn(0);
2161 }
2162 
2163 #undef __FUNCT__
2164 #define __FUNCT__ "DMPlexRestoreJoin"
2165 /*@C
2166   DMPlexRestoreJoin - Restore an array for the join of the set of points
2167 
2168   Not Collective
2169 
2170   Input Parameters:
2171 + dm - The DMPlex object
2172 . numPoints - The number of input points for the join
2173 - points - The input points
2174 
2175   Output Parameters:
2176 + numCoveredPoints - The number of points in the join
2177 - coveredPoints - The points in the join
2178 
2179   Level: intermediate
2180 
2181 .keywords: mesh
2182 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2183 @*/
2184 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2185 {
2186   PetscErrorCode ierr;
2187 
2188   PetscFunctionBegin;
2189   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2190   PetscValidPointer(coveredPoints, 4);
2191   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2192   PetscFunctionReturn(0);
2193 }
2194 
2195 #undef __FUNCT__
2196 #define __FUNCT__ "DMPlexGetFullJoin"
2197 /*@C
2198   DMPlexGetFullJoin - Get an array for the join of the set of points
2199 
2200   Not Collective
2201 
2202   Input Parameters:
2203 + dm - The DMPlex object
2204 . numPoints - The number of input points for the join
2205 - points - The input points
2206 
2207   Output Parameters:
2208 + numCoveredPoints - The number of points in the join
2209 - coveredPoints - The points in the join
2210 
2211   Level: intermediate
2212 
2213 .keywords: mesh
2214 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2215 @*/
2216 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2217 {
2218   DM_Plex       *mesh = (DM_Plex*) dm->data;
2219   PetscInt      *offsets, **closures;
2220   PetscInt      *join[2];
2221   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2222   PetscInt       p, d, c, m;
2223   PetscErrorCode ierr;
2224 
2225   PetscFunctionBegin;
2226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2227   PetscValidPointer(points, 2);
2228   PetscValidPointer(numCoveredPoints, 3);
2229   PetscValidPointer(coveredPoints, 4);
2230 
2231   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2232   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2233   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2234   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2235   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2236   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2237   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2238 
2239   for (p = 0; p < numPoints; ++p) {
2240     PetscInt closureSize;
2241 
2242     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2243 
2244     offsets[p*(depth+2)+0] = 0;
2245     for (d = 0; d < depth+1; ++d) {
2246       PetscInt pStart, pEnd, i;
2247 
2248       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2249       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2250         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2251           offsets[p*(depth+2)+d+1] = i;
2252           break;
2253         }
2254       }
2255       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2256     }
2257     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);
2258   }
2259   for (d = 0; d < depth+1; ++d) {
2260     PetscInt dof;
2261 
2262     /* Copy in support of first point */
2263     dof = offsets[d+1] - offsets[d];
2264     for (joinSize = 0; joinSize < dof; ++joinSize) {
2265       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2266     }
2267     /* Check each successive cone */
2268     for (p = 1; p < numPoints && joinSize; ++p) {
2269       PetscInt newJoinSize = 0;
2270 
2271       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2272       for (c = 0; c < dof; ++c) {
2273         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2274 
2275         for (m = 0; m < joinSize; ++m) {
2276           if (point == join[i][m]) {
2277             join[1-i][newJoinSize++] = point;
2278             break;
2279           }
2280         }
2281       }
2282       joinSize = newJoinSize;
2283       i        = 1-i;
2284     }
2285     if (joinSize) break;
2286   }
2287   *numCoveredPoints = joinSize;
2288   *coveredPoints    = join[i];
2289   for (p = 0; p < numPoints; ++p) {
2290     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2291   }
2292   ierr = PetscFree(closures);CHKERRQ(ierr);
2293   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2294   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2295   PetscFunctionReturn(0);
2296 }
2297 
2298 #undef __FUNCT__
2299 #define __FUNCT__ "DMPlexGetMeet"
2300 /*@C
2301   DMPlexGetMeet - Get an array for the meet of the set of points
2302 
2303   Not Collective
2304 
2305   Input Parameters:
2306 + dm - The DMPlex object
2307 . numPoints - The number of input points for the meet
2308 - points - The input points
2309 
2310   Output Parameters:
2311 + numCoveredPoints - The number of points in the meet
2312 - coveredPoints - The points in the meet
2313 
2314   Level: intermediate
2315 
2316   Note: Currently, this is restricted to a single level meet
2317 
2318 .keywords: mesh
2319 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2320 @*/
2321 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2322 {
2323   DM_Plex       *mesh = (DM_Plex*) dm->data;
2324   PetscInt      *meet[2];
2325   PetscInt       meetSize, i = 0;
2326   PetscInt       dof, off, p, c, m;
2327   PetscErrorCode ierr;
2328 
2329   PetscFunctionBegin;
2330   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2331   PetscValidPointer(points, 2);
2332   PetscValidPointer(numCoveringPoints, 3);
2333   PetscValidPointer(coveringPoints, 4);
2334   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2335   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2336   /* Copy in cone of first point */
2337   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2338   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2339   for (meetSize = 0; meetSize < dof; ++meetSize) {
2340     meet[i][meetSize] = mesh->cones[off+meetSize];
2341   }
2342   /* Check each successive cone */
2343   for (p = 1; p < numPoints; ++p) {
2344     PetscInt newMeetSize = 0;
2345 
2346     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2347     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2348     for (c = 0; c < dof; ++c) {
2349       const PetscInt point = mesh->cones[off+c];
2350 
2351       for (m = 0; m < meetSize; ++m) {
2352         if (point == meet[i][m]) {
2353           meet[1-i][newMeetSize++] = point;
2354           break;
2355         }
2356       }
2357     }
2358     meetSize = newMeetSize;
2359     i        = 1-i;
2360   }
2361   *numCoveringPoints = meetSize;
2362   *coveringPoints    = meet[i];
2363   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2364   PetscFunctionReturn(0);
2365 }
2366 
2367 #undef __FUNCT__
2368 #define __FUNCT__ "DMPlexRestoreMeet"
2369 /*@C
2370   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2371 
2372   Not Collective
2373 
2374   Input Parameters:
2375 + dm - The DMPlex object
2376 . numPoints - The number of input points for the meet
2377 - points - The input points
2378 
2379   Output Parameters:
2380 + numCoveredPoints - The number of points in the meet
2381 - coveredPoints - The points in the meet
2382 
2383   Level: intermediate
2384 
2385 .keywords: mesh
2386 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2387 @*/
2388 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2389 {
2390   PetscErrorCode ierr;
2391 
2392   PetscFunctionBegin;
2393   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2394   PetscValidPointer(coveredPoints, 4);
2395   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2396   PetscFunctionReturn(0);
2397 }
2398 
2399 #undef __FUNCT__
2400 #define __FUNCT__ "DMPlexGetFullMeet"
2401 /*@C
2402   DMPlexGetFullMeet - Get an array for the meet of the set of points
2403 
2404   Not Collective
2405 
2406   Input Parameters:
2407 + dm - The DMPlex object
2408 . numPoints - The number of input points for the meet
2409 - points - The input points
2410 
2411   Output Parameters:
2412 + numCoveredPoints - The number of points in the meet
2413 - coveredPoints - The points in the meet
2414 
2415   Level: intermediate
2416 
2417 .keywords: mesh
2418 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2419 @*/
2420 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2421 {
2422   DM_Plex       *mesh = (DM_Plex*) dm->data;
2423   PetscInt      *offsets, **closures;
2424   PetscInt      *meet[2];
2425   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2426   PetscInt       p, h, c, m;
2427   PetscErrorCode ierr;
2428 
2429   PetscFunctionBegin;
2430   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2431   PetscValidPointer(points, 2);
2432   PetscValidPointer(numCoveredPoints, 3);
2433   PetscValidPointer(coveredPoints, 4);
2434 
2435   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2436   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2437   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2438   maxSize = PetscPowInt(mesh->maxConeSize,height);
2439   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2440   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2441 
2442   for (p = 0; p < numPoints; ++p) {
2443     PetscInt closureSize;
2444 
2445     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2446 
2447     offsets[p*(height+2)+0] = 0;
2448     for (h = 0; h < height+1; ++h) {
2449       PetscInt pStart, pEnd, i;
2450 
2451       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2452       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2453         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2454           offsets[p*(height+2)+h+1] = i;
2455           break;
2456         }
2457       }
2458       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2459     }
2460     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);
2461   }
2462   for (h = 0; h < height+1; ++h) {
2463     PetscInt dof;
2464 
2465     /* Copy in cone of first point */
2466     dof = offsets[h+1] - offsets[h];
2467     for (meetSize = 0; meetSize < dof; ++meetSize) {
2468       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2469     }
2470     /* Check each successive cone */
2471     for (p = 1; p < numPoints && meetSize; ++p) {
2472       PetscInt newMeetSize = 0;
2473 
2474       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2475       for (c = 0; c < dof; ++c) {
2476         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2477 
2478         for (m = 0; m < meetSize; ++m) {
2479           if (point == meet[i][m]) {
2480             meet[1-i][newMeetSize++] = point;
2481             break;
2482           }
2483         }
2484       }
2485       meetSize = newMeetSize;
2486       i        = 1-i;
2487     }
2488     if (meetSize) break;
2489   }
2490   *numCoveredPoints = meetSize;
2491   *coveredPoints    = meet[i];
2492   for (p = 0; p < numPoints; ++p) {
2493     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2494   }
2495   ierr = PetscFree(closures);CHKERRQ(ierr);
2496   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2497   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2498   PetscFunctionReturn(0);
2499 }
2500 
2501 #undef __FUNCT__
2502 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2503 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2504 {
2505   MPI_Comm       comm = ((PetscObject) dm)->comm;
2506   PetscInt       cellDim;
2507   PetscErrorCode ierr;
2508 
2509   PetscFunctionBegin;
2510   PetscValidPointer(numFaceVertices,3);
2511   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2512   switch (cellDim) {
2513   case 0:
2514     *numFaceVertices = 0;
2515     break;
2516   case 1:
2517     *numFaceVertices = 1;
2518     break;
2519   case 2:
2520     switch (numCorners) {
2521     case 3: /* triangle */
2522       *numFaceVertices = 2; /* Edge has 2 vertices */
2523       break;
2524     case 4: /* quadrilateral */
2525       *numFaceVertices = 2; /* Edge has 2 vertices */
2526       break;
2527     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2528       *numFaceVertices = 3; /* Edge has 3 vertices */
2529       break;
2530     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2531       *numFaceVertices = 3; /* Edge has 3 vertices */
2532       break;
2533     default:
2534       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2535     }
2536     break;
2537   case 3:
2538     switch (numCorners) {
2539     case 4: /* tetradehdron */
2540       *numFaceVertices = 3; /* Face has 3 vertices */
2541       break;
2542     case 6: /* tet cohesive cells */
2543       *numFaceVertices = 4; /* Face has 4 vertices */
2544       break;
2545     case 8: /* hexahedron */
2546       *numFaceVertices = 4; /* Face has 4 vertices */
2547       break;
2548     case 9: /* tet cohesive Lagrange cells */
2549       *numFaceVertices = 6; /* Face has 6 vertices */
2550       break;
2551     case 10: /* quadratic tetrahedron */
2552       *numFaceVertices = 6; /* Face has 6 vertices */
2553       break;
2554     case 12: /* hex cohesive Lagrange cells */
2555       *numFaceVertices = 6; /* Face has 6 vertices */
2556       break;
2557     case 18: /* quadratic tet cohesive Lagrange cells */
2558       *numFaceVertices = 6; /* Face has 6 vertices */
2559       break;
2560     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2561       *numFaceVertices = 9; /* Face has 9 vertices */
2562       break;
2563     default:
2564       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2565     }
2566     break;
2567   default:
2568     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2569   }
2570   PetscFunctionReturn(0);
2571 }
2572 
2573 #undef __FUNCT__
2574 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2575 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2576 {
2577   const PetscInt maxFaceCases = 30;
2578   PetscInt       numFaceCases = 0;
2579   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2580   PetscInt      *off, *adj;
2581   PetscInt      *neighborCells, *tmpClosure;
2582   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2583   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2584   PetscErrorCode ierr;
2585 
2586   PetscFunctionBegin;
2587   /* For parallel partitioning, I think you have to communicate supports */
2588   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2589   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2590   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2591   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2592   if (cEnd - cStart == 0) {
2593     if (numVertices) *numVertices = 0;
2594     if (offsets)   *offsets   = NULL;
2595     if (adjacency) *adjacency = NULL;
2596     PetscFunctionReturn(0);
2597   }
2598   numCells = cEnd - cStart;
2599   /* Setup face recognition */
2600   if (depth == 1) {
2601     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 */
2602 
2603     for (c = cStart; c < cEnd; ++c) {
2604       PetscInt corners;
2605 
2606       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2607       if (!cornersSeen[corners]) {
2608         PetscInt nFV;
2609 
2610         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2611         cornersSeen[corners] = 1;
2612 
2613         ierr = DMPlexGetNumFaceVertices_Internal(dm, corners, &nFV);CHKERRQ(ierr);
2614 
2615         numFaceVertices[numFaceCases++] = nFV;
2616       }
2617     }
2618   }
2619   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2620   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2621   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2622   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2623   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2624   /* Count neighboring cells */
2625   for (cell = cStart; cell < cEnd; ++cell) {
2626     PetscInt numNeighbors = maxNeighbors, n;
2627 
2628     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2629     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2630     for (n = 0; n < numNeighbors; ++n) {
2631       PetscInt        cellPair[2];
2632       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2633       PetscInt        meetSize = 0;
2634       const PetscInt *meet    = NULL;
2635 
2636       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2637       if (cellPair[0] == cellPair[1]) continue;
2638       if (!found) {
2639         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2640         if (meetSize) {
2641           PetscInt f;
2642 
2643           for (f = 0; f < numFaceCases; ++f) {
2644             if (numFaceVertices[f] == meetSize) {
2645               found = PETSC_TRUE;
2646               break;
2647             }
2648           }
2649         }
2650         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2651       }
2652       if (found) ++off[cell-cStart+1];
2653     }
2654   }
2655   /* Prefix sum */
2656   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2657 
2658   if (adjacency) {
2659     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2660     /* Get neighboring cells */
2661     for (cell = cStart; cell < cEnd; ++cell) {
2662       PetscInt numNeighbors = maxNeighbors, n;
2663       PetscInt cellOffset   = 0;
2664 
2665       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2666       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2667       for (n = 0; n < numNeighbors; ++n) {
2668         PetscInt        cellPair[2];
2669         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2670         PetscInt        meetSize = 0;
2671         const PetscInt *meet    = NULL;
2672 
2673         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2674         if (cellPair[0] == cellPair[1]) continue;
2675         if (!found) {
2676           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2677           if (meetSize) {
2678             PetscInt f;
2679 
2680             for (f = 0; f < numFaceCases; ++f) {
2681               if (numFaceVertices[f] == meetSize) {
2682                 found = PETSC_TRUE;
2683                 break;
2684               }
2685             }
2686           }
2687           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2688         }
2689         if (found) {
2690           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2691           ++cellOffset;
2692         }
2693       }
2694     }
2695   }
2696   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2697   if (numVertices) *numVertices = numCells;
2698   if (offsets)   *offsets   = off;
2699   if (adjacency) *adjacency = adj;
2700   PetscFunctionReturn(0);
2701 }
2702 
2703 #if defined(PETSC_HAVE_CHACO)
2704 #if defined(PETSC_HAVE_UNISTD_H)
2705 #include <unistd.h>
2706 #endif
2707 /* Chaco does not have an include file */
2708 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2709                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2710                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2711                        int mesh_dims[3], double *goal, int global_method, int local_method,
2712                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2713 
2714 extern int FREE_GRAPH;
2715 
2716 #undef __FUNCT__
2717 #define __FUNCT__ "DMPlexPartition_Chaco"
2718 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2719 {
2720   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2721   MPI_Comm       comm           = ((PetscObject) dm)->comm;
2722   int            nvtxs          = numVertices; /* number of vertices in full graph */
2723   int           *vwgts          = NULL;   /* weights for all vertices */
2724   float         *ewgts          = NULL;   /* weights for all edges */
2725   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2726   char          *outassignname  = NULL;   /*  name of assignment output file */
2727   char          *outfilename    = NULL;   /* output file name */
2728   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2729   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2730   int            mesh_dims[3];            /* dimensions of mesh of processors */
2731   double        *goal          = NULL;    /* desired set sizes for each set */
2732   int            global_method = 1;       /* global partitioning algorithm */
2733   int            local_method  = 1;       /* local partitioning algorithm */
2734   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2735   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2736   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2737   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2738   long           seed          = 123636512; /* for random graph mutations */
2739   short int     *assignment;              /* Output partition */
2740   int            fd_stdout, fd_pipe[2];
2741   PetscInt      *points;
2742   PetscMPIInt    commSize;
2743   int            i, v, p;
2744   PetscErrorCode ierr;
2745 
2746   PetscFunctionBegin;
2747   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2748   if (!numVertices) {
2749     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2750     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2751     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2752     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2753     PetscFunctionReturn(0);
2754   }
2755   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2756   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2757 
2758   if (global_method == INERTIAL_METHOD) {
2759     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2760     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2761   }
2762   mesh_dims[0] = commSize;
2763   mesh_dims[1] = 1;
2764   mesh_dims[2] = 1;
2765   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2766   /* Chaco outputs to stdout. We redirect this to a buffer. */
2767   /* TODO: check error codes for UNIX calls */
2768 #if defined(PETSC_HAVE_UNISTD_H)
2769   {
2770     int piperet;
2771     piperet = pipe(fd_pipe);
2772     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2773     fd_stdout = dup(1);
2774     close(1);
2775     dup2(fd_pipe[1], 1);
2776   }
2777 #endif
2778   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2779                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2780                    vmax, ndims, eigtol, seed);
2781 #if defined(PETSC_HAVE_UNISTD_H)
2782   {
2783     char msgLog[10000];
2784     int  count;
2785 
2786     fflush(stdout);
2787     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2788     if (count < 0) count = 0;
2789     msgLog[count] = 0;
2790     close(1);
2791     dup2(fd_stdout, 1);
2792     close(fd_stdout);
2793     close(fd_pipe[0]);
2794     close(fd_pipe[1]);
2795     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2796   }
2797 #endif
2798   /* Convert to PetscSection+IS */
2799   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2800   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2801   for (v = 0; v < nvtxs; ++v) {
2802     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2803   }
2804   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2805   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2806   for (p = 0, i = 0; p < commSize; ++p) {
2807     for (v = 0; v < nvtxs; ++v) {
2808       if (assignment[v] == p) points[i++] = v;
2809     }
2810   }
2811   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2812   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2813   if (global_method == INERTIAL_METHOD) {
2814     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2815   }
2816   ierr = PetscFree(assignment);CHKERRQ(ierr);
2817   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2818   PetscFunctionReturn(0);
2819 }
2820 #endif
2821 
2822 #if defined(PETSC_HAVE_PARMETIS)
2823 #undef __FUNCT__
2824 #define __FUNCT__ "DMPlexPartition_ParMetis"
2825 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2826 {
2827   PetscFunctionBegin;
2828   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2829   PetscFunctionReturn(0);
2830 }
2831 #endif
2832 
2833 #undef __FUNCT__
2834 #define __FUNCT__ "DMPlexEnlargePartition"
2835 /* Expand the partition by BFS on the adjacency graph */
2836 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2837 {
2838   PetscHashI      h;
2839   const PetscInt *points;
2840   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2841   PetscInt        pStart, pEnd, part, q;
2842   PetscErrorCode  ierr;
2843 
2844   PetscFunctionBegin;
2845   PetscHashICreate(h);
2846   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2847   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2848   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2849   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2850   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2851   for (part = pStart; part < pEnd; ++part) {
2852     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2853 
2854     PetscHashIClear(h);
2855     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2856     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2857     /* Add all existing points to h */
2858     for (p = 0; p < numPoints; ++p) {
2859       const PetscInt point = points[off+p];
2860       PetscHashIAdd(h, point, 1);
2861     }
2862     PetscHashISize(h, nP);
2863     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2864     /* Add all points in next BFS level */
2865     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2866     for (p = 0; p < numPoints; ++p) {
2867       const PetscInt point = points[off+p];
2868       PetscInt       s     = start[point], e = start[point+1], a;
2869 
2870       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2871     }
2872     PetscHashISize(h, numNewPoints);
2873     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2874     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2875     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2876     totPoints += numNewPoints;
2877   }
2878   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2879   PetscHashIDestroy(h);
2880   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2881   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2882   for (part = pStart, q = 0; part < pEnd; ++part) {
2883     PetscInt numPoints, p;
2884 
2885     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2886     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2887     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2888   }
2889   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2890   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2891   PetscFunctionReturn(0);
2892 }
2893 
2894 #undef __FUNCT__
2895 #define __FUNCT__ "DMPlexCreatePartition"
2896 /*
2897   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2898 
2899   Collective on DM
2900 
2901   Input Parameters:
2902   + dm - The DM
2903   . height - The height for points in the partition
2904   - enlarge - Expand each partition with neighbors
2905 
2906   Output Parameters:
2907   + partSection - The PetscSection giving the division of points by partition
2908   . partition - The list of points by partition
2909   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2910   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2911 
2912   Level: developer
2913 
2914 .seealso DMPlexDistribute()
2915 */
2916 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2917 {
2918   PetscMPIInt    size;
2919   PetscErrorCode ierr;
2920 
2921   PetscFunctionBegin;
2922   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2923 
2924   *origPartSection = NULL;
2925   *origPartition   = NULL;
2926   if (size == 1) {
2927     PetscInt *points;
2928     PetscInt  cStart, cEnd, c;
2929 
2930     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2931     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2932     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2933     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2934     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2935     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2936     for (c = cStart; c < cEnd; ++c) points[c] = c;
2937     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2938     PetscFunctionReturn(0);
2939   }
2940   if (height == 0) {
2941     PetscInt  numVertices;
2942     PetscInt *start     = NULL;
2943     PetscInt *adjacency = NULL;
2944 
2945     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2946     if (1) {
2947 #if defined(PETSC_HAVE_CHACO)
2948       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2949 #endif
2950     } else {
2951 #if defined(PETSC_HAVE_PARMETIS)
2952       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2953 #endif
2954     }
2955     if (enlarge) {
2956       *origPartSection = *partSection;
2957       *origPartition   = *partition;
2958 
2959       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2960     }
2961     ierr = PetscFree(start);CHKERRQ(ierr);
2962     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2963 # if 0
2964   } else if (height == 1) {
2965     /* Build the dual graph for faces and partition the hypergraph */
2966     PetscInt numEdges;
2967 
2968     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2969     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2970     destroyCSR(numEdges, start, adjacency);
2971 #endif
2972   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2973   PetscFunctionReturn(0);
2974 }
2975 
2976 #undef __FUNCT__
2977 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2978 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2979 {
2980   /* const PetscInt  height = 0; */
2981   const PetscInt *partArray;
2982   PetscInt       *allPoints, *partPoints = NULL;
2983   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2984   PetscErrorCode  ierr;
2985 
2986   PetscFunctionBegin;
2987   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2988   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2989   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2990   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2991   for (rank = rStart; rank < rEnd; ++rank) {
2992     PetscInt partSize = 0;
2993     PetscInt numPoints, offset, p;
2994 
2995     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2996     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2997     for (p = 0; p < numPoints; ++p) {
2998       PetscInt  point   = partArray[offset+p], closureSize, c;
2999       PetscInt *closure = NULL;
3000 
3001       /* TODO Include support for height > 0 case */
3002       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3003       /* Merge into existing points */
3004       if (partSize+closureSize > maxPartSize) {
3005         PetscInt *tmpPoints;
3006 
3007         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3008         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3009         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3010         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3011 
3012         partPoints = tmpPoints;
3013       }
3014       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3015       partSize += closureSize;
3016 
3017       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3018       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3019     }
3020     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3021   }
3022   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3023   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3024   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3025 
3026   for (rank = rStart; rank < rEnd; ++rank) {
3027     PetscInt partSize = 0, newOffset;
3028     PetscInt numPoints, offset, p;
3029 
3030     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3031     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3032     for (p = 0; p < numPoints; ++p) {
3033       PetscInt  point   = partArray[offset+p], closureSize, c;
3034       PetscInt *closure = NULL;
3035 
3036       /* TODO Include support for height > 0 case */
3037       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3038       /* Merge into existing points */
3039       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3040       partSize += closureSize;
3041 
3042       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3043       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3044     }
3045     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3046     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3047   }
3048   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3049   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3050   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3051   PetscFunctionReturn(0);
3052 }
3053 
3054 #undef __FUNCT__
3055 #define __FUNCT__ "DMPlexDistributeField"
3056 /*
3057   Input Parameters:
3058 . originalSection
3059 , originalVec
3060 
3061   Output Parameters:
3062 . newSection
3063 . newVec
3064 */
3065 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3066 {
3067   PetscSF        fieldSF;
3068   PetscInt      *remoteOffsets, fieldSize;
3069   PetscScalar   *originalValues, *newValues;
3070   PetscErrorCode ierr;
3071 
3072   PetscFunctionBegin;
3073   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3074 
3075   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3076   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3077   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3078 
3079   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3080   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3081   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3082   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3083   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3084   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3085   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3086   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3087   PetscFunctionReturn(0);
3088 }
3089 
3090 #undef __FUNCT__
3091 #define __FUNCT__ "DMPlexDistribute"
3092 /*@C
3093   DMPlexDistribute - Distributes the mesh and any associated sections.
3094 
3095   Not Collective
3096 
3097   Input Parameter:
3098 + dm  - The original DMPlex object
3099 . partitioner - The partitioning package, or NULL for the default
3100 - overlap - The overlap of partitions, 0 is the default
3101 
3102   Output Parameter:
3103 . parallelMesh - The distributed DMPlex object, or NULL
3104 
3105   Note: If the mesh was not distributed, the return value is NULL
3106 
3107   Level: intermediate
3108 
3109 .keywords: mesh, elements
3110 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3111 @*/
3112 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3113 {
3114   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3115   MPI_Comm               comm   = ((PetscObject) dm)->comm;
3116   const PetscInt         height = 0;
3117   PetscInt               dim, numRemoteRanks;
3118   IS                     origCellPart,        cellPart,        part;
3119   PetscSection           origCellPartSection, cellPartSection, partSection;
3120   PetscSFNode           *remoteRanks;
3121   PetscSF                partSF, pointSF, coneSF;
3122   ISLocalToGlobalMapping renumbering;
3123   PetscSection           originalConeSection, newConeSection;
3124   PetscInt              *remoteOffsets;
3125   PetscInt              *cones, *newCones, newConesSize;
3126   PetscBool              flg;
3127   PetscMPIInt            rank, numProcs, p;
3128   PetscErrorCode         ierr;
3129 
3130   PetscFunctionBegin;
3131   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3132   PetscValidPointer(dmParallel,4);
3133 
3134   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3135   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3136   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3137 
3138   *dmParallel = NULL;
3139   if (numProcs == 1) PetscFunctionReturn(0);
3140 
3141   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3142   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3143   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3144   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3145   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3146   if (!rank) numRemoteRanks = numProcs;
3147   else       numRemoteRanks = 0;
3148   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3149   for (p = 0; p < numRemoteRanks; ++p) {
3150     remoteRanks[p].rank  = p;
3151     remoteRanks[p].index = 0;
3152   }
3153   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3154   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3155   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3156   if (flg) {
3157     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3158     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3159     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3160     if (origCellPart) {
3161       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3162       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3163       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3164     }
3165     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3166   }
3167   /* Close the partition over the mesh */
3168   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3169   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3170   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3171   /* Create new mesh */
3172   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3173   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3174   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3175   pmesh = (DM_Plex*) (*dmParallel)->data;
3176   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3177   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3178   if (flg) {
3179     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3180     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3181     ierr = ISView(part, NULL);CHKERRQ(ierr);
3182     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3183     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3184     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3185   }
3186   /* Distribute cone section */
3187   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3188   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3189   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3190   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3191   {
3192     PetscInt pStart, pEnd, p;
3193 
3194     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3195     for (p = pStart; p < pEnd; ++p) {
3196       PetscInt coneSize;
3197       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3198       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3199     }
3200   }
3201   /* Communicate and renumber cones */
3202   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3203   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3204   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3205   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3206   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3207   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3208   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3209   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3210   if (flg) {
3211     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3212     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3213     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3214     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3215     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3216   }
3217   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3218   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3219   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3220   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3221   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3222   /* Create supports and stratify sieve */
3223   {
3224     PetscInt pStart, pEnd;
3225 
3226     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3227     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3228   }
3229   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3230   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3231   /* Distribute Coordinates */
3232   {
3233     PetscSection originalCoordSection, newCoordSection;
3234     Vec          originalCoordinates, newCoordinates;
3235     const char  *name;
3236 
3237     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3238     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3239     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3240     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3241     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3242     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3243 
3244     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3245     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3246     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3247   }
3248   /* Distribute labels */
3249   {
3250     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3251     PetscInt numLabels = 0, l;
3252 
3253     /* Bcast number of labels */
3254     while (next) {
3255       ++numLabels; next = next->next;
3256     }
3257     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3258     next = mesh->labels;
3259     for (l = 0; l < numLabels; ++l) {
3260       DMLabel         newLabel;
3261       const PetscInt *partArray;
3262       char           *name;
3263       PetscInt       *stratumSizes = NULL, *points = NULL;
3264       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3265       PetscInt        nameSize, s, p;
3266       PetscBool       isdepth;
3267       size_t          len = 0;
3268 
3269       /* Bcast name (could filter for no points) */
3270       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3271       nameSize = len;
3272       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3273       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3274       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3275       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3276       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3277       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3278       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3279       newLabel->name = name;
3280       /* Bcast numStrata (could filter for no points in stratum) */
3281       if (!rank) newLabel->numStrata = next->numStrata;
3282       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3283       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3284                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3285                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3286       /* Bcast stratumValues (could filter for no points in stratum) */
3287       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3288       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3289       /* Find size on each process and Scatter */
3290       if (!rank) {
3291         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3292         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3293         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3294         for (s = 0; s < next->numStrata; ++s) {
3295           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3296             const PetscInt point = next->points[p];
3297             PetscInt       proc;
3298 
3299             for (proc = 0; proc < numProcs; ++proc) {
3300               PetscInt dof, off, pPart;
3301 
3302               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3303               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3304               for (pPart = off; pPart < off+dof; ++pPart) {
3305                 if (partArray[pPart] == point) {
3306                   ++stratumSizes[proc*next->numStrata+s];
3307                   break;
3308                 }
3309               }
3310             }
3311           }
3312         }
3313         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3314       }
3315       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3316       /* Calculate stratumOffsets */
3317       newLabel->stratumOffsets[0] = 0;
3318       for (s = 0; s < newLabel->numStrata; ++s) {
3319         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3320       }
3321       /* Pack points and Scatter */
3322       if (!rank) {
3323         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3324         displs[0] = 0;
3325         for (p = 0; p < numProcs; ++p) {
3326           sendcnts[p] = 0;
3327           for (s = 0; s < next->numStrata; ++s) {
3328             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3329           }
3330           offsets[p]  = displs[p];
3331           displs[p+1] = displs[p] + sendcnts[p];
3332         }
3333         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3334         for (s = 0; s < next->numStrata; ++s) {
3335           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3336             const PetscInt point = next->points[p];
3337             PetscInt       proc;
3338 
3339             for (proc = 0; proc < numProcs; ++proc) {
3340               PetscInt dof, off, pPart;
3341 
3342               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3343               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3344               for (pPart = off; pPart < off+dof; ++pPart) {
3345                 if (partArray[pPart] == point) {
3346                   points[offsets[proc]++] = point;
3347                   break;
3348                 }
3349               }
3350             }
3351           }
3352         }
3353       }
3354       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3355       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3356       ierr = PetscFree(points);CHKERRQ(ierr);
3357       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3358       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3359       /* Renumber points */
3360       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3361       /* Sort points */
3362       for (s = 0; s < newLabel->numStrata; ++s) {
3363         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3364       }
3365       /* Insert into list */
3366       if (newNext) newNext->next = newLabel;
3367       else pmesh->labels = newLabel;
3368       newNext = newLabel;
3369       if (!rank) next = next->next;
3370     }
3371   }
3372   /* Cleanup Partition */
3373   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3374   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3375   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3376   ierr = ISDestroy(&part);CHKERRQ(ierr);
3377   /* Create point SF for parallel mesh */
3378   {
3379     const PetscInt *leaves;
3380     PetscSFNode    *remotePoints, *rowners, *lowners;
3381     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3382     PetscInt        pStart, pEnd;
3383 
3384     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3385     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3386     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3387     for (p=0; p<numRoots; p++) {
3388       rowners[p].rank  = -1;
3389       rowners[p].index = -1;
3390     }
3391     if (origCellPart) {
3392       /* Make sure cells in the original partition are not assigned to other procs */
3393       const PetscInt *origCells;
3394 
3395       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3396       for (p = 0; p < numProcs; ++p) {
3397         PetscInt dof, off, d;
3398 
3399         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3400         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3401         for (d = off; d < off+dof; ++d) {
3402           rowners[origCells[d]].rank = p;
3403         }
3404       }
3405       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3406     }
3407     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3408     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3409 
3410     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3411     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3412     for (p = 0; p < numLeaves; ++p) {
3413       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3414         lowners[p].rank  = rank;
3415         lowners[p].index = leaves ? leaves[p] : p;
3416       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3417         lowners[p].rank  = -2;
3418         lowners[p].index = -2;
3419       }
3420     }
3421     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3422       rowners[p].rank  = -3;
3423       rowners[p].index = -3;
3424     }
3425     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3426     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3427     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3428     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3429     for (p = 0; p < numLeaves; ++p) {
3430       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3431       if (lowners[p].rank != rank) ++numGhostPoints;
3432     }
3433     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3434     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3435     for (p = 0, gp = 0; p < numLeaves; ++p) {
3436       if (lowners[p].rank != rank) {
3437         ghostPoints[gp]        = leaves ? leaves[p] : p;
3438         remotePoints[gp].rank  = lowners[p].rank;
3439         remotePoints[gp].index = lowners[p].index;
3440         ++gp;
3441       }
3442     }
3443     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3444     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3445     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3446   }
3447   /* Cleanup */
3448   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3449   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3450   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3451   PetscFunctionReturn(0);
3452 }
3453 
3454 #undef __FUNCT__
3455 #define __FUNCT__ "DMPlexRenumber_Private"
3456 /*
3457   Reasons to renumber:
3458 
3459   1) Permute points, e.g. bandwidth reduction (Renumber)
3460 
3461     a) Must not mix strata
3462 
3463   2) Shift numbers for point insertion (Shift)
3464 
3465     a) Want operation brken into parts so that insertion can be interleaved
3466 
3467   renumbering - An IS which provides the new numbering
3468 */
3469 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3470 {
3471   PetscFunctionBegin;
3472   PetscFunctionReturn(0);
3473 }
3474 
3475 #undef __FUNCT__
3476 #define __FUNCT__ "DMPlexShiftPoint_Private"
3477 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3478 {
3479   if (depth < 0) return p;
3480   /* Cells    */ if (p < depthEnd[depth])   return p;
3481   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3482   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3483   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3484 }
3485 
3486 #undef __FUNCT__
3487 #define __FUNCT__ "DMPlexShiftSizes_Private"
3488 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3489 {
3490   PetscInt      *depthEnd;
3491   PetscInt       depth = 0, d, pStart, pEnd, p;
3492   PetscErrorCode ierr;
3493 
3494   PetscFunctionBegin;
3495   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3496   if (depth < 0) PetscFunctionReturn(0);
3497   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3498   /* Step 1: Expand chart */
3499   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3500   for (d = 0; d <= depth; ++d) {
3501     pEnd += depthShift[d];
3502     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3503   }
3504   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3505   /* Step 2: Set cone and support sizes */
3506   for (d = 0; d <= depth; ++d) {
3507     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3508     for (p = pStart; p < pEnd; ++p) {
3509       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3510       PetscInt size;
3511 
3512       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3513       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3514       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3515       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3516     }
3517   }
3518   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3519   PetscFunctionReturn(0);
3520 }
3521 
3522 #undef __FUNCT__
3523 #define __FUNCT__ "DMPlexShiftPoints_Private"
3524 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3525 {
3526   PetscInt      *depthEnd, *newpoints;
3527   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3528   PetscErrorCode ierr;
3529 
3530   PetscFunctionBegin;
3531   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3532   if (depth < 0) PetscFunctionReturn(0);
3533   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3534   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3535   for (d = 0; d <= depth; ++d) {
3536     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3537   }
3538   /* Step 5: Set cones and supports */
3539   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3540   for (p = pStart; p < pEnd; ++p) {
3541     const PetscInt *points = NULL, *orientations = NULL;
3542     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3543 
3544     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3545     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3546     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3547     for (i = 0; i < size; ++i) {
3548       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3549     }
3550     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3551     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3552     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3553     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3554     for (i = 0; i < size; ++i) {
3555       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3556     }
3557     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3558   }
3559   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3560   PetscFunctionReturn(0);
3561 }
3562 
3563 #undef __FUNCT__
3564 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3565 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3566 {
3567   PetscSection   coordSection, newCoordSection;
3568   Vec            coordinates, newCoordinates;
3569   PetscScalar   *coords, *newCoords;
3570   PetscInt      *depthEnd, coordSize;
3571   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3572   PetscErrorCode ierr;
3573 
3574   PetscFunctionBegin;
3575   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3576   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3577   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3578   for (d = 0; d <= depth; ++d) {
3579     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3580   }
3581   /* Step 8: Convert coordinates */
3582   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3583   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3584   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3585   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3586   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3587   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3588   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3589   for (v = vStartNew; v < vEndNew; ++v) {
3590     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3591     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3592   }
3593   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3594   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3595   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3596   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3597   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3598   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3599   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3600   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3601   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3602   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3603   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3604   for (v = vStart; v < vEnd; ++v) {
3605     PetscInt dof, off, noff, d;
3606 
3607     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3608     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3609     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3610     for (d = 0; d < dof; ++d) {
3611       newCoords[noff+d] = coords[off+d];
3612     }
3613   }
3614   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3615   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3616   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3617   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3618   PetscFunctionReturn(0);
3619 }
3620 
3621 #undef __FUNCT__
3622 #define __FUNCT__ "DMPlexShiftSF_Private"
3623 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3624 {
3625   PetscInt          *depthEnd;
3626   PetscInt           depth = 0, d;
3627   PetscSF            sfPoint, sfPointNew;
3628   const PetscSFNode *remotePoints;
3629   PetscSFNode       *gremotePoints;
3630   const PetscInt    *localPoints;
3631   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3632   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3633   PetscMPIInt        numProcs;
3634   PetscErrorCode     ierr;
3635 
3636   PetscFunctionBegin;
3637   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3638   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3639   for (d = 0; d <= depth; ++d) {
3640     totShift += depthShift[d];
3641     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3642   }
3643   /* Step 9: Convert pointSF */
3644   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3645   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3646   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3647   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3648   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3649   if (numRoots >= 0) {
3650     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3651     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3652     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3653     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3654     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3655     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3656     for (l = 0; l < numLeaves; ++l) {
3657       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3658       gremotePoints[l].rank  = remotePoints[l].rank;
3659       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3660     }
3661     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3662     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3663   }
3664   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3665   PetscFunctionReturn(0);
3666 }
3667 
3668 #undef __FUNCT__
3669 #define __FUNCT__ "DMPlexShiftLabels_Private"
3670 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3671 {
3672   PetscSF            sfPoint;
3673   DMLabel            vtkLabel, ghostLabel;
3674   PetscInt          *depthEnd;
3675   const PetscSFNode *leafRemote;
3676   const PetscInt    *leafLocal;
3677   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3678   PetscMPIInt        rank;
3679   PetscErrorCode     ierr;
3680 
3681   PetscFunctionBegin;
3682   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3683   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3684   for (d = 0; d <= depth; ++d) {
3685     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3686   }
3687   /* Step 10: Convert labels */
3688   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3689   for (l = 0; l < numLabels; ++l) {
3690     DMLabel         label, newlabel;
3691     const char     *lname;
3692     PetscBool       isDepth;
3693     IS              valueIS;
3694     const PetscInt *values;
3695     PetscInt        numValues, val;
3696 
3697     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3698     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3699     if (isDepth) continue;
3700     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3701     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3702     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3703     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3704     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3705     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3706     for (val = 0; val < numValues; ++val) {
3707       IS              pointIS;
3708       const PetscInt *points;
3709       PetscInt        numPoints, p;
3710 
3711       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3712       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3713       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3714       for (p = 0; p < numPoints; ++p) {
3715         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3716 
3717         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3718       }
3719       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3720       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3721     }
3722     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3723     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3724   }
3725   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3726   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3727   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3728   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3729   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3730   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3731   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3732   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3733   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3734   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3735   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3736     for (; c < leafLocal[l] && c < cEnd; ++c) {
3737       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3738     }
3739     if (leafLocal[l] >= cEnd) break;
3740     if (leafRemote[l].rank == rank) {
3741       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3742     } else {
3743       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3744     }
3745   }
3746   for (; c < cEnd; ++c) {
3747     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3748   }
3749   if (0) {
3750     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3751     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3752     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3753   }
3754   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3755   for (f = fStart; f < fEnd; ++f) {
3756     PetscInt numCells;
3757 
3758     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3759     if (numCells < 2) {
3760       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3761     } else {
3762       const PetscInt *cells = NULL;
3763       PetscInt        vA, vB;
3764 
3765       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3766       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3767       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3768       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3769     }
3770   }
3771   if (0) {
3772     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3773     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3774     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3775   }
3776   PetscFunctionReturn(0);
3777 }
3778 
3779 #undef __FUNCT__
3780 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3781 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3782 {
3783   DMLabel         label;
3784   IS              valueIS;
3785   const PetscInt *values;
3786   PetscInt       *depthShift;
3787   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3788   PetscErrorCode  ierr;
3789 
3790   PetscFunctionBegin;
3791   /* Count ghost cells */
3792   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3793   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3794   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3795   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3796 
3797   *numGhostCells = 0;
3798   for (fs = 0; fs < numFS; ++fs) {
3799     PetscInt numBdFaces;
3800 
3801     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3802 
3803     *numGhostCells += numBdFaces;
3804   }
3805   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3806   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3807   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3808   if (depth >= 0) depthShift[depth] = *numGhostCells;
3809   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3810   /* Step 3: Set cone/support sizes for new points */
3811   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3812   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3813     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3814   }
3815   for (fs = 0; fs < numFS; ++fs) {
3816     IS              faceIS;
3817     const PetscInt *faces;
3818     PetscInt        numFaces, f;
3819 
3820     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3821     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3822     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3823     for (f = 0; f < numFaces; ++f) {
3824       PetscInt size;
3825 
3826       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3827       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3828       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3829     }
3830     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3831     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3832   }
3833   /* Step 4: Setup ghosted DM */
3834   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3835   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3836   /* Step 6: Set cones and supports for new points */
3837   ghostCell = cEnd;
3838   for (fs = 0; fs < numFS; ++fs) {
3839     IS              faceIS;
3840     const PetscInt *faces;
3841     PetscInt        numFaces, f;
3842 
3843     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3844     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3845     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3846     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3847       PetscInt newFace = faces[f] + *numGhostCells;
3848 
3849       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3850       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3851     }
3852     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3853     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3854   }
3855   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3856   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3857   /* Step 7: Stratify */
3858   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3859   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3860   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3861   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3862   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3863   PetscFunctionReturn(0);
3864 }
3865 
3866 #undef __FUNCT__
3867 #define __FUNCT__ "DMPlexConstructGhostCells"
3868 /*@C
3869   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3870 
3871   Collective on dm
3872 
3873   Input Parameters:
3874 + dm - The original DM
3875 - labelName - The label specifying the boundary faces (this could be auto-generated)
3876 
3877   Output Parameters:
3878 + numGhostCells - The number of ghost cells added to the DM
3879 - dmGhosted - The new DM
3880 
3881   Level: developer
3882 
3883 .seealso: DMCreate()
3884 */
3885 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3886 {
3887   DM             gdm;
3888   PetscInt       dim;
3889   PetscErrorCode ierr;
3890 
3891   PetscFunctionBegin;
3892   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3893   PetscValidPointer(numGhostCells, 3);
3894   PetscValidPointer(dmGhosted, 4);
3895   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3896   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3897   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3898   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3899   switch (dim) {
3900   case 2:
3901     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3902     break;
3903   default:
3904     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3905   }
3906   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3907   *dmGhosted = gdm;
3908   PetscFunctionReturn(0);
3909 }
3910 
3911 #undef __FUNCT__
3912 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3913 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3914 {
3915   MPI_Comm        comm = ((PetscObject) dm)->comm;
3916   IS              valueIS, *pointIS;
3917   const PetscInt *values, **splitPoints;
3918   PetscSection    coordSection;
3919   Vec             coordinates;
3920   PetscScalar    *coords;
3921   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3922   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3923   PetscErrorCode  ierr;
3924 
3925   PetscFunctionBegin;
3926   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3927   /* Count split points and add cohesive cells */
3928   if (label) {
3929     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3930     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3931     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
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 = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3937   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3938   for (d = 0; d <= depth; ++d) {
3939     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3940     numSplitPoints[d] = 0;
3941     splitPoints[d]    = NULL;
3942     pointIS[d]        = NULL;
3943   }
3944   for (sp = 0; sp < numSP; ++sp) {
3945     const PetscInt dep = values[sp];
3946 
3947     if ((dep < 0) || (dep > depth)) continue;
3948     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3949     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3950     if (pointIS[dep]) {
3951       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3952       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3953     }
3954   }
3955   if (depth >= 0) {
3956     /* Calculate number of additional points */
3957     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3958     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3959     /* Calculate hybrid bound for each dimension */
3960     pMaxNew[0] += depthShift[depth];
3961     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3962     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3963 
3964     /* Calculate point offset for each dimension */
3965     depthOffset[depth] = 0;
3966     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3967     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3968     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3969   }
3970   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3971   /* Step 3: Set cone/support sizes for new points */
3972   for (dep = 0; dep <= depth; ++dep) {
3973     for (p = 0; p < numSplitPoints[dep]; ++p) {
3974       const PetscInt  oldp   = splitPoints[dep][p];
3975       const PetscInt  newp   = depthOffset[dep] + oldp;
3976       const PetscInt  splitp = pMaxNew[dep] + p;
3977       const PetscInt *support;
3978       PetscInt        coneSize, supportSize, q, e;
3979 
3980       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3981       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3982       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3983       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3984       if (dep == depth-1) {
3985         const PetscInt ccell = pMaxNew[depth] + p;
3986         /* Add cohesive cells, they are prisms */
3987         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3988       } else if (dep == 0) {
3989         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3990 
3991         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3992         /* Split old vertex: Edges in old split faces and new cohesive edge */
3993         for (e = 0, q = 0; e < supportSize; ++e) {
3994           PetscInt val;
3995 
3996           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3997           if ((val == 1) || (val == (shift + 1))) ++q;
3998         }
3999         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
4000         /* Split new vertex: Edges in new split faces and new cohesive edge */
4001         for (e = 0, q = 0; e < supportSize; ++e) {
4002           PetscInt val;
4003 
4004           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4005           if ((val == 1) || (val == -(shift + 1))) ++q;
4006         }
4007         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4008         /* Add cohesive edges */
4009         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4010         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4011       } else if (dep == dim-2) {
4012         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4013         /* Split old edge: Faces in positive side cells and old split faces */
4014         for (e = 0, q = 0; e < supportSize; ++e) {
4015           PetscInt val;
4016 
4017           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4018           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4019         }
4020         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4021         /* Split new edge: Faces in negative side cells and new split faces */
4022         for (e = 0, q = 0; e < supportSize; ++e) {
4023           PetscInt val;
4024 
4025           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4026           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4027         }
4028         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4029       }
4030     }
4031   }
4032   /* Step 4: Setup split DM */
4033   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4034   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4035   /* Step 6: Set cones and supports for new points */
4036   for (dep = 0; dep <= depth; ++dep) {
4037     for (p = 0; p < numSplitPoints[dep]; ++p) {
4038       const PetscInt  oldp   = splitPoints[dep][p];
4039       const PetscInt  newp   = depthOffset[dep] + oldp;
4040       const PetscInt  splitp = pMaxNew[dep] + p;
4041       const PetscInt *cone, *support, *ornt;
4042       PetscInt        coneSize, supportSize, q, v, e, s;
4043 
4044       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4045       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4046       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4047       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4048       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4049       if (dep == depth-1) {
4050         const PetscInt  ccell = pMaxNew[depth] + p;
4051         const PetscInt *supportF;
4052 
4053         /* Split face:       copy in old face to new face to start */
4054         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4055         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4056         /* Split old face:   old vertices/edges in cone so no change */
4057         /* Split new face:   new vertices/edges in cone */
4058         for (q = 0; q < coneSize; ++q) {
4059           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4060 
4061           coneNew[2+q] = pMaxNew[dim-2] + v;
4062         }
4063         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4064         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4065         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4066         coneNew[0] = newp;
4067         coneNew[1] = splitp;
4068         for (q = 0; q < coneSize; ++q) {
4069           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4070         }
4071         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4072 
4073 
4074         for (s = 0; s < supportSize; ++s) {
4075           PetscInt val;
4076 
4077           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4078           if (val < 0) {
4079             /* Split old face:   Replace negative side cell with cohesive cell */
4080             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4081           } else {
4082             /* Split new face:   Replace positive side cell with cohesive cell */
4083             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4084           }
4085         }
4086       } else if (dep == 0) {
4087         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4088 
4089         /* Split old vertex: Edges in old split faces and new cohesive edge */
4090         for (e = 0, q = 0; e < supportSize; ++e) {
4091           PetscInt val;
4092 
4093           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4094           if ((val == 1) || (val == (shift + 1))) {
4095             supportNew[q++] = depthOffset[1] + support[e];
4096           }
4097         }
4098         supportNew[q] = cedge;
4099 
4100         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4101         /* Split new vertex: Edges in new split faces and new cohesive edge */
4102         for (e = 0, q = 0; e < supportSize; ++e) {
4103           PetscInt val, edge;
4104 
4105           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4106           if (val == 1) {
4107             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4108             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4109             supportNew[q++] = pMaxNew[1] + edge;
4110           } else if (val == -(shift + 1)) {
4111             supportNew[q++] = depthOffset[1] + support[e];
4112           }
4113         }
4114         supportNew[q] = cedge;
4115         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4116         /* Cohesive edge:    Old and new split vertex, punting on support */
4117         coneNew[0] = newp;
4118         coneNew[1] = splitp;
4119         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4120       } else if (dep == dim-2) {
4121         /* Split old edge:   old vertices in cone so no change */
4122         /* Split new edge:   new vertices in cone */
4123         for (q = 0; q < coneSize; ++q) {
4124           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4125 
4126           coneNew[q] = pMaxNew[dim-3] + v;
4127         }
4128         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4129         /* Split old edge: Faces in positive side cells and old split faces */
4130         for (e = 0, q = 0; e < supportSize; ++e) {
4131           PetscInt val;
4132 
4133           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4134           if ((val == dim-1) || (val == (shift + dim-1))) {
4135             supportNew[q++] = depthOffset[dim-1] + support[e];
4136           }
4137         }
4138         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4139         /* Split new edge: Faces in negative side cells and new split faces */
4140         for (e = 0, q = 0; e < supportSize; ++e) {
4141           PetscInt val, face;
4142 
4143           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4144           if (val == dim-1) {
4145             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4146             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4147             supportNew[q++] = pMaxNew[dim-1] + face;
4148           } else if (val == -(shift + dim-1)) {
4149             supportNew[q++] = depthOffset[dim-1] + support[e];
4150           }
4151         }
4152         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4153       }
4154     }
4155   }
4156   /* Step 6b: Replace split points in negative side cones */
4157   for (sp = 0; sp < numSP; ++sp) {
4158     PetscInt        dep = values[sp];
4159     IS              pIS;
4160     PetscInt        numPoints;
4161     const PetscInt *points;
4162 
4163     if (dep >= 0) continue;
4164     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4165     if (!pIS) continue;
4166     dep  = -dep - shift;
4167     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4168     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4169     for (p = 0; p < numPoints; ++p) {
4170       const PetscInt  oldp = points[p];
4171       const PetscInt  newp = depthOffset[dep] + oldp;
4172       const PetscInt *cone;
4173       PetscInt        coneSize, c;
4174       PetscBool       replaced = PETSC_FALSE;
4175 
4176       /* Negative edge: replace split vertex */
4177       /* Negative cell: replace split face */
4178       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4179       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4180       for (c = 0; c < coneSize; ++c) {
4181         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4182         PetscInt       csplitp, cp, val;
4183 
4184         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4185         if (val == dep-1) {
4186           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4187           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4188           csplitp  = pMaxNew[dep-1] + cp;
4189           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4190           replaced = PETSC_TRUE;
4191         }
4192       }
4193       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4194     }
4195     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4196     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4197   }
4198   /* Step 7: Stratify */
4199   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4200   /* Step 8: Coordinates */
4201   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4202   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4203   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4204   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4205   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4206     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4207     const PetscInt splitp = pMaxNew[0] + v;
4208     PetscInt       dof, off, soff, d;
4209 
4210     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4211     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4212     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4213     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4214   }
4215   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4216   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4217   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4218   /* Step 10: Labels */
4219   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4220   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4221   for (dep = 0; dep <= depth; ++dep) {
4222     for (p = 0; p < numSplitPoints[dep]; ++p) {
4223       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4224       const PetscInt splitp = pMaxNew[dep] + p;
4225       PetscInt       l;
4226 
4227       for (l = 0; l < numLabels; ++l) {
4228         DMLabel     mlabel;
4229         const char *lname;
4230         PetscInt    val;
4231 
4232         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4233         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4234         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4235         if (val >= 0) {
4236           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4237           if (dep == 0) {
4238             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4239             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4240           }
4241         }
4242       }
4243     }
4244   }
4245   for (sp = 0; sp < numSP; ++sp) {
4246     const PetscInt dep = values[sp];
4247 
4248     if ((dep < 0) || (dep > depth)) continue;
4249     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4250     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4251   }
4252   if (label) {
4253     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4254     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4255   }
4256   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4257   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4258   PetscFunctionReturn(0);
4259 }
4260 
4261 #undef __FUNCT__
4262 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4263 /*@C
4264   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4265 
4266   Collective on dm
4267 
4268   Input Parameters:
4269 + dm - The original DM
4270 - labelName - The label specifying the boundary faces (this could be auto-generated)
4271 
4272   Output Parameters:
4273 - dmSplit - The new DM
4274 
4275   Level: developer
4276 
4277 .seealso: DMCreate()
4278 */
4279 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4280 {
4281   DM             sdm;
4282   PetscInt       dim;
4283   PetscErrorCode ierr;
4284 
4285   PetscFunctionBegin;
4286   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4287   PetscValidPointer(dmSplit, 4);
4288   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4289   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4290   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4291   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4292   switch (dim) {
4293   case 2:
4294   case 3:
4295     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4296     break;
4297   default:
4298     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4299   }
4300   *dmSplit = sdm;
4301   PetscFunctionReturn(0);
4302 }
4303 
4304 #undef __FUNCT__
4305 #define __FUNCT__ "DMLabelCohesiveComplete"
4306 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4307 {
4308   IS              dimIS;
4309   const PetscInt *points;
4310   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4311   PetscErrorCode  ierr;
4312 
4313   PetscFunctionBegin;
4314   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4315   /* Cell orientation for face gives the side of the fault */
4316   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4317   if (!dimIS) PetscFunctionReturn(0);
4318   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4319   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4320   for (p = 0; p < numPoints; ++p) {
4321     const PetscInt *support;
4322     PetscInt        supportSize, s;
4323 
4324     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4325     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4326     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4327     for (s = 0; s < supportSize; ++s) {
4328       const PetscInt *cone, *ornt;
4329       PetscInt        coneSize, c;
4330       PetscBool       pos = PETSC_TRUE;
4331 
4332       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4333       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4334       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4335       for (c = 0; c < coneSize; ++c) {
4336         if (cone[c] == points[p]) {
4337           if (ornt[c] >= 0) {
4338             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4339           } else {
4340             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4341             pos  = PETSC_FALSE;
4342           }
4343           break;
4344         }
4345       }
4346       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]);
4347       /* Put faces touching the fault in the label */
4348       for (c = 0; c < coneSize; ++c) {
4349         const PetscInt point = cone[c];
4350 
4351         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4352         if (val == -1) {
4353           PetscInt *closure = NULL;
4354           PetscInt  closureSize, cl;
4355 
4356           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4357           for (cl = 0; cl < closureSize*2; cl += 2) {
4358             const PetscInt clp = closure[cl];
4359 
4360             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4361             if ((val >= 0) && (val < dim-1)) {
4362               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4363               break;
4364             }
4365           }
4366           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4367         }
4368       }
4369     }
4370   }
4371   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4372   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4373   /* Search for other cells/faces/edges connected to the fault by a vertex */
4374   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4375   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4376   if (!dimIS) PetscFunctionReturn(0);
4377   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4378   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4379   for (p = 0; p < numPoints; ++p) {
4380     PetscInt *star = NULL;
4381     PetscInt  starSize, s;
4382     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4383 
4384     /* First mark cells connected to the fault */
4385     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4386     while (again) {
4387       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4388       again = 0;
4389       for (s = 0; s < starSize*2; s += 2) {
4390         const PetscInt  point = star[s];
4391         const PetscInt *cone;
4392         PetscInt        coneSize, c;
4393 
4394         if ((point < cStart) || (point >= cEnd)) continue;
4395         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4396         if (val != -1) continue;
4397         again = 2;
4398         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4399         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4400         for (c = 0; c < coneSize; ++c) {
4401           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4402           if (val != -1) {
4403             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);
4404             if (val > 0) {
4405               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4406             } else {
4407               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4408             }
4409             again = 1;
4410             break;
4411           }
4412         }
4413       }
4414     }
4415     /* Classify the rest by cell membership */
4416     for (s = 0; s < starSize*2; s += 2) {
4417       const PetscInt point = star[s];
4418 
4419       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4420       if (val == -1) {
4421         PetscInt  *sstar = NULL;
4422         PetscInt   sstarSize, ss;
4423         PetscBool  marked = PETSC_FALSE;
4424 
4425         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4426         for (ss = 0; ss < sstarSize*2; ss += 2) {
4427           const PetscInt spoint = sstar[ss];
4428 
4429           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4430           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4431           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4432           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4433           if (val > 0) {
4434             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4435           } else {
4436             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4437           }
4438           marked = PETSC_TRUE;
4439           break;
4440         }
4441         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4442         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4443       }
4444     }
4445     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4446   }
4447   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4448   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4449   PetscFunctionReturn(0);
4450 }
4451 
4452 #undef __FUNCT__
4453 #define __FUNCT__ "DMPlexInterpolate_2D"
4454 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4455 {
4456   DM             idm;
4457   DM_Plex       *mesh;
4458   PetscHashIJ    edgeTable;
4459   PetscInt      *off;
4460   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4461   PetscInt       numEdges, firstEdge, edge, e;
4462   PetscErrorCode ierr;
4463 
4464   PetscFunctionBegin;
4465   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4466   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4467   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4468   numCells    = cEnd - cStart;
4469   numVertices = vEnd - vStart;
4470   firstEdge   = numCells + numVertices;
4471   numEdges    = 0;
4472   /* Count edges using algorithm from CreateNeighborCSR */
4473   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4474   if (off) {
4475     PetscInt numCorners = 0;
4476 
4477     numEdges = off[numCells]/2;
4478 #if 0
4479     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4480     numEdges += 3*numCells - off[numCells];
4481 #else
4482     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4483     for (c = cStart; c < cEnd; ++c) {
4484       PetscInt coneSize;
4485 
4486       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4487       numCorners += coneSize;
4488     }
4489     numEdges += numCorners - off[numCells];
4490 #endif
4491   }
4492 #if 0
4493   /* Check Euler characteristic V - E + F = 1 */
4494   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4495 #endif
4496   /* Create interpolated mesh */
4497   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4498   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4499   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4500   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4501   for (c = 0; c < numCells; ++c) {
4502     PetscInt numCorners;
4503 
4504     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4505     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4506   }
4507   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4508     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4509   }
4510   ierr = DMSetUp(idm);CHKERRQ(ierr);
4511   /* Get edge cones from subsets of cell vertices */
4512   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4513   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4514 
4515   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4516     const PetscInt *cellFaces;
4517     PetscInt        numCellFaces, faceSize, cf;
4518 
4519     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4520     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4521     for (cf = 0; cf < numCellFaces; ++cf) {
4522 #if 1
4523       PetscHashIJKey key;
4524 
4525       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4526       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4527       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4528       if (e < 0) {
4529         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4530         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4531         e    = edge++;
4532       }
4533 #else
4534       PetscBool found = PETSC_FALSE;
4535 
4536       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4537       for (e = firstEdge; e < edge; ++e) {
4538         const PetscInt *cone;
4539 
4540         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4541         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4542             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4543           found = PETSC_TRUE;
4544           break;
4545         }
4546       }
4547       if (!found) {
4548         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4549         ++edge;
4550       }
4551 #endif
4552       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4553     }
4554   }
4555   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4556   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4557   ierr = PetscFree(off);CHKERRQ(ierr);
4558   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4559   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4560   mesh = (DM_Plex*) (idm)->data;
4561   /* Orient edges */
4562   for (c = 0; c < numCells; ++c) {
4563     const PetscInt *cone = NULL, *cellFaces;
4564     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4565 
4566     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4567     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4568     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4569     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4570     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4571     for (cf = 0; cf < numCellFaces; ++cf) {
4572       const PetscInt *econe = NULL;
4573       PetscInt        esize;
4574 
4575       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4576       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4577       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]);
4578       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4579         /* Correctly oriented */
4580         mesh->coneOrientations[coff+cf] = 0;
4581       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4582         /* Start at index 1, and reverse orientation */
4583         mesh->coneOrientations[coff+cf] = -(1+1);
4584       }
4585     }
4586   }
4587   *dmInt = idm;
4588   PetscFunctionReturn(0);
4589 }
4590 
4591 #undef __FUNCT__
4592 #define __FUNCT__ "DMPlexInterpolate_3D"
4593 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4594 {
4595   DM             idm, fdm;
4596   DM_Plex       *mesh;
4597   PetscInt      *off;
4598   const PetscInt numCorners = 4;
4599   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4600   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4601   PetscErrorCode ierr;
4602 
4603   PetscFunctionBegin;
4604   {
4605     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4606     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4607     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4608   }
4609   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4610   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4611   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4612   numCells    = cEnd - cStart;
4613   numVertices = vEnd - vStart;
4614   firstFace   = numCells + numVertices;
4615   numFaces    = 0;
4616   /* Count faces using algorithm from CreateNeighborCSR */
4617   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4618   if (off) {
4619     numFaces = off[numCells]/2;
4620     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4621     numFaces += 4*numCells - off[numCells];
4622   }
4623   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4624   firstEdge = firstFace + numFaces;
4625   numEdges  = numVertices + numFaces - numCells - 1;
4626   /* Create interpolated mesh */
4627   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4628   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4629   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4630   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4631   for (c = 0; c < numCells; ++c) {
4632     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4633   }
4634   for (f = firstFace; f < firstFace+numFaces; ++f) {
4635     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4636   }
4637   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4638     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4639   }
4640   ierr = DMSetUp(idm);CHKERRQ(ierr);
4641   /* Get face cones from subsets of cell vertices */
4642   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4643   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4644   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4645   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4646   for (f = firstFace; f < firstFace+numFaces; ++f) {
4647     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4648   }
4649   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4650   for (c = 0, face = firstFace; c < numCells; ++c) {
4651     const PetscInt *cellFaces;
4652     PetscInt        numCellFaces, faceSize, cf;
4653 
4654     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4655     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4656     for (cf = 0; cf < numCellFaces; ++cf) {
4657       PetscBool found = PETSC_FALSE;
4658 
4659       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4660       for (f = firstFace; f < face; ++f) {
4661         const PetscInt *cone = NULL;
4662 
4663         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4664         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4665             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4666             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4667             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4668             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4669             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4670           found = PETSC_TRUE;
4671           break;
4672         }
4673       }
4674       if (!found) {
4675         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4676         /* Save the vertices for orientation calculation */
4677         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4678         ++face;
4679       }
4680       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4681     }
4682   }
4683   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4684   /* Get edge cones from subsets of face vertices */
4685   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4686     const PetscInt *cellFaces;
4687     PetscInt        numCellFaces, faceSize, cf;
4688 
4689     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4690     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4691     for (cf = 0; cf < numCellFaces; ++cf) {
4692       PetscBool found = PETSC_FALSE;
4693 
4694       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4695       for (e = firstEdge; e < edge; ++e) {
4696         const PetscInt *cone = NULL;
4697 
4698         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4699         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4700             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4701           found = PETSC_TRUE;
4702           break;
4703         }
4704       }
4705       if (!found) {
4706         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4707         ++edge;
4708       }
4709       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4710     }
4711   }
4712   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4713   ierr = PetscFree(off);CHKERRQ(ierr);
4714   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4715   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4716   mesh = (DM_Plex*) (idm)->data;
4717   /* Orient edges */
4718   for (f = firstFace; f < firstFace+numFaces; ++f) {
4719     const PetscInt *cone, *cellFaces;
4720     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4721 
4722     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4723     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4724     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4725     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4726     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4727     for (cf = 0; cf < numCellFaces; ++cf) {
4728       const PetscInt *econe;
4729       PetscInt        esize;
4730 
4731       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4732       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4733       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]);
4734       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4735         /* Correctly oriented */
4736         mesh->coneOrientations[coff+cf] = 0;
4737       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4738         /* Start at index 1, and reverse orientation */
4739         mesh->coneOrientations[coff+cf] = -(1+1);
4740       }
4741     }
4742   }
4743   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4744   /* Orient faces */
4745   for (c = 0; c < numCells; ++c) {
4746     const PetscInt *cone, *cellFaces;
4747     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4748 
4749     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4750     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4751     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4752     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4753     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4754     for (cf = 0; cf < numCellFaces; ++cf) {
4755       PetscInt *origClosure = NULL, *closure;
4756       PetscInt closureSize, i;
4757 
4758       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4759       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4760       for (i = 4; i < 7; ++i) {
4761         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);
4762       }
4763       closure = &origClosure[4*2];
4764       /* Remember that this is the orientation for edges, not vertices */
4765       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4766         /* Correctly oriented */
4767         mesh->coneOrientations[coff+cf] = 0;
4768       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4769         /* Shifted by 1 */
4770         mesh->coneOrientations[coff+cf] = 1;
4771       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4772         /* Shifted by 2 */
4773         mesh->coneOrientations[coff+cf] = 2;
4774       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4775         /* Start at edge 1, and reverse orientation */
4776         mesh->coneOrientations[coff+cf] = -(1+1);
4777       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4778         /* Start at index 0, and reverse orientation */
4779         mesh->coneOrientations[coff+cf] = -(0+1);
4780       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4781         /* Start at index 2, and reverse orientation */
4782         mesh->coneOrientations[coff+cf] = -(2+1);
4783       } 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);
4784       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4785     }
4786   }
4787   {
4788     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4789     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4790     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4791   }
4792   *dmInt = idm;
4793   PetscFunctionReturn(0);
4794 }
4795 
4796 #undef __FUNCT__
4797 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4798 /*
4799   This takes as input the common mesh generator output, a list of the vertices for each cell
4800 */
4801 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4802 {
4803   PetscInt      *cone, c, p;
4804   PetscErrorCode ierr;
4805 
4806   PetscFunctionBegin;
4807   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4808   for (c = 0; c < numCells; ++c) {
4809     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4810   }
4811   ierr = DMSetUp(dm);CHKERRQ(ierr);
4812   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4813   for (c = 0; c < numCells; ++c) {
4814     for (p = 0; p < numCorners; ++p) {
4815       cone[p] = cells[c*numCorners+p]+numCells;
4816     }
4817     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4818   }
4819   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4820   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4821   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4822   PetscFunctionReturn(0);
4823 }
4824 
4825 #undef __FUNCT__
4826 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4827 /*
4828   This takes as input the coordinates for each vertex
4829 */
4830 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4831 {
4832   PetscSection   coordSection;
4833   Vec            coordinates;
4834   PetscScalar   *coords;
4835   PetscInt       coordSize, v, d;
4836   PetscErrorCode ierr;
4837 
4838   PetscFunctionBegin;
4839   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4840   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4841   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4842   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4843   for (v = numCells; v < numCells+numVertices; ++v) {
4844     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4845     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4846   }
4847   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4848   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4849   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4850   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4851   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4852   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4853   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4854   for (v = 0; v < numVertices; ++v) {
4855     for (d = 0; d < spaceDim; ++d) {
4856       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4857     }
4858   }
4859   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4860   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4861   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4862   PetscFunctionReturn(0);
4863 }
4864 
4865 #undef __FUNCT__
4866 #define __FUNCT__ "DMPlexCreateFromCellList"
4867 /*
4868   This takes as input the common mesh generator output, a list of the vertices for each cell
4869 */
4870 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4871 {
4872   PetscErrorCode ierr;
4873 
4874   PetscFunctionBegin;
4875   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4876   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4877   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4878   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4879   if (interpolate) {
4880     DM idm;
4881 
4882     switch (dim) {
4883     case 2:
4884       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4885     case 3:
4886       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4887     default:
4888       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4889     }
4890     ierr = DMDestroy(dm);CHKERRQ(ierr);
4891     *dm  = idm;
4892   }
4893   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4894   PetscFunctionReturn(0);
4895 }
4896 
4897 #if defined(PETSC_HAVE_TRIANGLE)
4898 #include <triangle.h>
4899 
4900 #undef __FUNCT__
4901 #define __FUNCT__ "InitInput_Triangle"
4902 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4903 {
4904   PetscFunctionBegin;
4905   inputCtx->numberofpoints             = 0;
4906   inputCtx->numberofpointattributes    = 0;
4907   inputCtx->pointlist                  = NULL;
4908   inputCtx->pointattributelist         = NULL;
4909   inputCtx->pointmarkerlist            = NULL;
4910   inputCtx->numberofsegments           = 0;
4911   inputCtx->segmentlist                = NULL;
4912   inputCtx->segmentmarkerlist          = NULL;
4913   inputCtx->numberoftriangleattributes = 0;
4914   inputCtx->trianglelist               = NULL;
4915   inputCtx->numberofholes              = 0;
4916   inputCtx->holelist                   = NULL;
4917   inputCtx->numberofregions            = 0;
4918   inputCtx->regionlist                 = NULL;
4919   PetscFunctionReturn(0);
4920 }
4921 
4922 #undef __FUNCT__
4923 #define __FUNCT__ "InitOutput_Triangle"
4924 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4925 {
4926   PetscFunctionBegin;
4927   outputCtx->numberofpoints        = 0;
4928   outputCtx->pointlist             = NULL;
4929   outputCtx->pointattributelist    = NULL;
4930   outputCtx->pointmarkerlist       = NULL;
4931   outputCtx->numberoftriangles     = 0;
4932   outputCtx->trianglelist          = NULL;
4933   outputCtx->triangleattributelist = NULL;
4934   outputCtx->neighborlist          = NULL;
4935   outputCtx->segmentlist           = NULL;
4936   outputCtx->segmentmarkerlist     = NULL;
4937   outputCtx->numberofedges         = 0;
4938   outputCtx->edgelist              = NULL;
4939   outputCtx->edgemarkerlist        = NULL;
4940   PetscFunctionReturn(0);
4941 }
4942 
4943 #undef __FUNCT__
4944 #define __FUNCT__ "FiniOutput_Triangle"
4945 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4946 {
4947   PetscFunctionBegin;
4948   free(outputCtx->pointmarkerlist);
4949   free(outputCtx->edgelist);
4950   free(outputCtx->edgemarkerlist);
4951   free(outputCtx->trianglelist);
4952   free(outputCtx->neighborlist);
4953   PetscFunctionReturn(0);
4954 }
4955 
4956 #undef __FUNCT__
4957 #define __FUNCT__ "DMPlexGenerate_Triangle"
4958 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4959 {
4960   MPI_Comm             comm             = ((PetscObject) boundary)->comm;
4961   PetscInt             dim              = 2;
4962   const PetscBool      createConvexHull = PETSC_FALSE;
4963   const PetscBool      constrained      = PETSC_FALSE;
4964   struct triangulateio in;
4965   struct triangulateio out;
4966   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4967   PetscMPIInt          rank;
4968   PetscErrorCode       ierr;
4969 
4970   PetscFunctionBegin;
4971   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4972   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4973   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4974   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4975 
4976   in.numberofpoints = vEnd - vStart;
4977   if (in.numberofpoints > 0) {
4978     PetscSection coordSection;
4979     Vec          coordinates;
4980     PetscScalar *array;
4981 
4982     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4983     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4984     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4985     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4986     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4987     for (v = vStart; v < vEnd; ++v) {
4988       const PetscInt idx = v - vStart;
4989       PetscInt       off, d;
4990 
4991       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4992       for (d = 0; d < dim; ++d) {
4993         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4994       }
4995       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4996     }
4997     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4998   }
4999   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
5000   in.numberofsegments = eEnd - eStart;
5001   if (in.numberofsegments > 0) {
5002     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
5003     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
5004     for (e = eStart; e < eEnd; ++e) {
5005       const PetscInt  idx = e - eStart;
5006       const PetscInt *cone;
5007 
5008       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
5009 
5010       in.segmentlist[idx*2+0] = cone[0] - vStart;
5011       in.segmentlist[idx*2+1] = cone[1] - vStart;
5012 
5013       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5014     }
5015   }
5016 #if 0 /* Do not currently support holes */
5017   PetscReal *holeCoords;
5018   PetscInt   h, d;
5019 
5020   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5021   if (in.numberofholes > 0) {
5022     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5023     for (h = 0; h < in.numberofholes; ++h) {
5024       for (d = 0; d < dim; ++d) {
5025         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5026       }
5027     }
5028   }
5029 #endif
5030   if (!rank) {
5031     char args[32];
5032 
5033     /* Take away 'Q' for verbose output */
5034     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5035     if (createConvexHull) {
5036       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5037     }
5038     if (constrained) {
5039       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5040     }
5041     triangulate(args, &in, &out, NULL);
5042   }
5043   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5044   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5045   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5046   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5047   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5048 
5049   {
5050     const PetscInt numCorners  = 3;
5051     const PetscInt numCells    = out.numberoftriangles;
5052     const PetscInt numVertices = out.numberofpoints;
5053     const int     *cells      = out.trianglelist;
5054     const double  *meshCoords = out.pointlist;
5055 
5056     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5057     /* Set labels */
5058     for (v = 0; v < numVertices; ++v) {
5059       if (out.pointmarkerlist[v]) {
5060         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5061       }
5062     }
5063     if (interpolate) {
5064       for (e = 0; e < out.numberofedges; e++) {
5065         if (out.edgemarkerlist[e]) {
5066           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5067           const PetscInt *edges;
5068           PetscInt        numEdges;
5069 
5070           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5071           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5072           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5073           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5074         }
5075       }
5076     }
5077     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5078   }
5079 #if 0 /* Do not currently support holes */
5080   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5081 #endif
5082   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5083   PetscFunctionReturn(0);
5084 }
5085 
5086 #undef __FUNCT__
5087 #define __FUNCT__ "DMPlexRefine_Triangle"
5088 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5089 {
5090   MPI_Comm             comm = ((PetscObject) dm)->comm;
5091   PetscInt             dim  = 2;
5092   struct triangulateio in;
5093   struct triangulateio out;
5094   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5095   PetscMPIInt          rank;
5096   PetscErrorCode       ierr;
5097 
5098   PetscFunctionBegin;
5099   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5100   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5101   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5102   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5103   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5104   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5105 
5106   in.numberofpoints = vEnd - vStart;
5107   if (in.numberofpoints > 0) {
5108     PetscSection coordSection;
5109     Vec          coordinates;
5110     PetscScalar *array;
5111 
5112     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5113     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5114     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5115     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5116     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5117     for (v = vStart; v < vEnd; ++v) {
5118       const PetscInt idx = v - vStart;
5119       PetscInt       off, d;
5120 
5121       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5122       for (d = 0; d < dim; ++d) {
5123         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5124       }
5125       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5126     }
5127     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5128   }
5129   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5130 
5131   in.numberofcorners   = 3;
5132   in.numberoftriangles = cEnd - cStart;
5133 
5134   in.trianglearealist  = (double*) maxVolumes;
5135   if (in.numberoftriangles > 0) {
5136     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5137     for (c = cStart; c < cEnd; ++c) {
5138       const PetscInt idx      = c - cStart;
5139       PetscInt      *closure = NULL;
5140       PetscInt       closureSize;
5141 
5142       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5143       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5144       for (v = 0; v < 3; ++v) {
5145         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5146       }
5147       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5148     }
5149   }
5150   /* TODO: Segment markers are missing on input */
5151 #if 0 /* Do not currently support holes */
5152   PetscReal *holeCoords;
5153   PetscInt   h, d;
5154 
5155   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5156   if (in.numberofholes > 0) {
5157     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5158     for (h = 0; h < in.numberofholes; ++h) {
5159       for (d = 0; d < dim; ++d) {
5160         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5161       }
5162     }
5163   }
5164 #endif
5165   if (!rank) {
5166     char args[32];
5167 
5168     /* Take away 'Q' for verbose output */
5169     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5170     triangulate(args, &in, &out, NULL);
5171   }
5172   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5173   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5174   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5175   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5176   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5177 
5178   {
5179     const PetscInt numCorners  = 3;
5180     const PetscInt numCells    = out.numberoftriangles;
5181     const PetscInt numVertices = out.numberofpoints;
5182     const int     *cells      = out.trianglelist;
5183     const double  *meshCoords = out.pointlist;
5184     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5185 
5186     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5187     /* Set labels */
5188     for (v = 0; v < numVertices; ++v) {
5189       if (out.pointmarkerlist[v]) {
5190         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5191       }
5192     }
5193     if (interpolate) {
5194       PetscInt e;
5195 
5196       for (e = 0; e < out.numberofedges; e++) {
5197         if (out.edgemarkerlist[e]) {
5198           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5199           const PetscInt *edges;
5200           PetscInt        numEdges;
5201 
5202           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5203           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5204           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5205           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5206         }
5207       }
5208     }
5209     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5210   }
5211 #if 0 /* Do not currently support holes */
5212   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5213 #endif
5214   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5215   PetscFunctionReturn(0);
5216 }
5217 #endif
5218 
5219 #if defined(PETSC_HAVE_TETGEN)
5220 #include <tetgen.h>
5221 #undef __FUNCT__
5222 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5223 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5224 {
5225   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5226   const PetscInt dim  = 3;
5227   ::tetgenio     in;
5228   ::tetgenio     out;
5229   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5230   PetscMPIInt    rank;
5231   PetscErrorCode ierr;
5232 
5233   PetscFunctionBegin;
5234   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5235   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5236   in.numberofpoints = vEnd - vStart;
5237   if (in.numberofpoints > 0) {
5238     PetscSection coordSection;
5239     Vec          coordinates;
5240     PetscScalar *array;
5241 
5242     in.pointlist       = new double[in.numberofpoints*dim];
5243     in.pointmarkerlist = new int[in.numberofpoints];
5244 
5245     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5246     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5247     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5248     for (v = vStart; v < vEnd; ++v) {
5249       const PetscInt idx = v - vStart;
5250       PetscInt       off, d;
5251 
5252       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5253       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5254       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5255     }
5256     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5257   }
5258   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5259 
5260   in.numberoffacets = fEnd - fStart;
5261   if (in.numberoffacets > 0) {
5262     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5263     in.facetmarkerlist = new int[in.numberoffacets];
5264     for (f = fStart; f < fEnd; ++f) {
5265       const PetscInt idx     = f - fStart;
5266       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
5267 
5268       in.facetlist[idx].numberofpolygons = 1;
5269       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5270       in.facetlist[idx].numberofholes    = 0;
5271       in.facetlist[idx].holelist         = NULL;
5272 
5273       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5274       for (p = 0; p < numPoints*2; p += 2) {
5275         const PetscInt point = points[p];
5276         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5277       }
5278 
5279       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5280       poly->numberofvertices = numVertices;
5281       poly->vertexlist       = new int[poly->numberofvertices];
5282       for (v = 0; v < numVertices; ++v) {
5283         const PetscInt vIdx = points[v] - vStart;
5284         poly->vertexlist[v] = vIdx;
5285       }
5286       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5287       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5288     }
5289   }
5290   if (!rank) {
5291     char args[32];
5292 
5293     /* Take away 'Q' for verbose output */
5294     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5295     ::tetrahedralize(args, &in, &out);
5296   }
5297   {
5298     const PetscInt numCorners  = 4;
5299     const PetscInt numCells    = out.numberoftetrahedra;
5300     const PetscInt numVertices = out.numberofpoints;
5301     const int     *cells      = out.tetrahedronlist;
5302     const double  *meshCoords = out.pointlist;
5303 
5304     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5305     /* Set labels */
5306     for (v = 0; v < numVertices; ++v) {
5307       if (out.pointmarkerlist[v]) {
5308         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5309       }
5310     }
5311     if (interpolate) {
5312       PetscInt e;
5313 
5314       for (e = 0; e < out.numberofedges; e++) {
5315         if (out.edgemarkerlist[e]) {
5316           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5317           const PetscInt *edges;
5318           PetscInt        numEdges;
5319 
5320           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5321           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5322           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5323           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5324         }
5325       }
5326       for (f = 0; f < out.numberoftrifaces; f++) {
5327         if (out.trifacemarkerlist[f]) {
5328           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5329           const PetscInt *faces;
5330           PetscInt        numFaces;
5331 
5332           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5333           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5334           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5335           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5336         }
5337       }
5338     }
5339     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5340   }
5341   PetscFunctionReturn(0);
5342 }
5343 
5344 #undef __FUNCT__
5345 #define __FUNCT__ "DMPlexRefine_Tetgen"
5346 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5347 {
5348   MPI_Comm       comm = ((PetscObject) dm)->comm;
5349   const PetscInt dim  = 3;
5350   ::tetgenio     in;
5351   ::tetgenio     out;
5352   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5353   PetscMPIInt    rank;
5354   PetscErrorCode ierr;
5355 
5356   PetscFunctionBegin;
5357   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5358   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5359   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5360   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5361 
5362   in.numberofpoints = vEnd - vStart;
5363   if (in.numberofpoints > 0) {
5364     PetscSection coordSection;
5365     Vec          coordinates;
5366     PetscScalar *array;
5367 
5368     in.pointlist       = new double[in.numberofpoints*dim];
5369     in.pointmarkerlist = new int[in.numberofpoints];
5370 
5371     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5372     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5373     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5374     for (v = vStart; v < vEnd; ++v) {
5375       const PetscInt idx = v - vStart;
5376       PetscInt       off, d;
5377 
5378       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5379       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5380       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5381     }
5382     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5383   }
5384   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5385 
5386   in.numberofcorners       = 4;
5387   in.numberoftetrahedra    = cEnd - cStart;
5388   in.tetrahedronvolumelist = (double*) maxVolumes;
5389   if (in.numberoftetrahedra > 0) {
5390     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5391     for (c = cStart; c < cEnd; ++c) {
5392       const PetscInt idx      = c - cStart;
5393       PetscInt      *closure = NULL;
5394       PetscInt       closureSize;
5395 
5396       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5397       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5398       for (v = 0; v < 4; ++v) {
5399         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5400       }
5401       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5402     }
5403   }
5404   /* TODO: Put in boundary faces with markers */
5405   if (!rank) {
5406     char args[32];
5407 
5408     /* Take away 'Q' for verbose output */
5409     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5410     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5411     ::tetrahedralize(args, &in, &out);
5412   }
5413   in.tetrahedronvolumelist = NULL;
5414 
5415   {
5416     const PetscInt numCorners  = 4;
5417     const PetscInt numCells    = out.numberoftetrahedra;
5418     const PetscInt numVertices = out.numberofpoints;
5419     const int     *cells      = out.tetrahedronlist;
5420     const double  *meshCoords = out.pointlist;
5421     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5422 
5423     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5424     /* Set labels */
5425     for (v = 0; v < numVertices; ++v) {
5426       if (out.pointmarkerlist[v]) {
5427         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5428       }
5429     }
5430     if (interpolate) {
5431       PetscInt e, f;
5432 
5433       for (e = 0; e < out.numberofedges; e++) {
5434         if (out.edgemarkerlist[e]) {
5435           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5436           const PetscInt *edges;
5437           PetscInt        numEdges;
5438 
5439           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5440           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5441           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5442           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5443         }
5444       }
5445       for (f = 0; f < out.numberoftrifaces; f++) {
5446         if (out.trifacemarkerlist[f]) {
5447           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5448           const PetscInt *faces;
5449           PetscInt        numFaces;
5450 
5451           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5452           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5453           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5454           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5455         }
5456       }
5457     }
5458     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5459   }
5460   PetscFunctionReturn(0);
5461 }
5462 #endif
5463 
5464 #if defined(PETSC_HAVE_CTETGEN)
5465 #include "ctetgen.h"
5466 
5467 #undef __FUNCT__
5468 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5469 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5470 {
5471   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5472   const PetscInt dim  = 3;
5473   PLC           *in, *out;
5474   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5475   PetscMPIInt    rank;
5476   PetscErrorCode ierr;
5477 
5478   PetscFunctionBegin;
5479   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5480   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5481   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5482   ierr = PLCCreate(&in);CHKERRQ(ierr);
5483   ierr = PLCCreate(&out);CHKERRQ(ierr);
5484 
5485   in->numberofpoints = vEnd - vStart;
5486   if (in->numberofpoints > 0) {
5487     PetscSection coordSection;
5488     Vec          coordinates;
5489     PetscScalar *array;
5490 
5491     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5492     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5493     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5494     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5495     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5496     for (v = vStart; v < vEnd; ++v) {
5497       const PetscInt idx = v - vStart;
5498       PetscInt       off, d, m;
5499 
5500       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5501       for (d = 0; d < dim; ++d) {
5502         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5503       }
5504       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5505 
5506       in->pointmarkerlist[idx] = (int) m;
5507     }
5508     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5509   }
5510   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5511 
5512   in->numberoffacets = fEnd - fStart;
5513   if (in->numberoffacets > 0) {
5514     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5515     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5516     for (f = fStart; f < fEnd; ++f) {
5517       const PetscInt idx     = f - fStart;
5518       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5519       polygon       *poly;
5520 
5521       in->facetlist[idx].numberofpolygons = 1;
5522 
5523       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5524 
5525       in->facetlist[idx].numberofholes    = 0;
5526       in->facetlist[idx].holelist         = NULL;
5527 
5528       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5529       for (p = 0; p < numPoints*2; p += 2) {
5530         const PetscInt point = points[p];
5531         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5532       }
5533 
5534       poly                   = in->facetlist[idx].polygonlist;
5535       poly->numberofvertices = numVertices;
5536       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5537       for (v = 0; v < numVertices; ++v) {
5538         const PetscInt vIdx = points[v] - vStart;
5539         poly->vertexlist[v] = vIdx;
5540       }
5541       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5542       in->facetmarkerlist[idx] = (int) m;
5543       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5544     }
5545   }
5546   if (!rank) {
5547     TetGenOpts t;
5548 
5549     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5550     t.in        = boundary; /* Should go away */
5551     t.plc       = 1;
5552     t.quality   = 1;
5553     t.edgesout  = 1;
5554     t.zeroindex = 1;
5555     t.quiet     = 1;
5556     t.verbose   = verbose;
5557     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5558     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5559   }
5560   {
5561     const PetscInt numCorners  = 4;
5562     const PetscInt numCells    = out->numberoftetrahedra;
5563     const PetscInt numVertices = out->numberofpoints;
5564     const int     *cells      = out->tetrahedronlist;
5565     const double  *meshCoords = out->pointlist;
5566 
5567     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5568     /* Set labels */
5569     for (v = 0; v < numVertices; ++v) {
5570       if (out->pointmarkerlist[v]) {
5571         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5572       }
5573     }
5574     if (interpolate) {
5575       PetscInt e;
5576 
5577       for (e = 0; e < out->numberofedges; e++) {
5578         if (out->edgemarkerlist[e]) {
5579           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5580           const PetscInt *edges;
5581           PetscInt        numEdges;
5582 
5583           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5584           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5585           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5586           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5587         }
5588       }
5589       for (f = 0; f < out->numberoftrifaces; f++) {
5590         if (out->trifacemarkerlist[f]) {
5591           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5592           const PetscInt *faces;
5593           PetscInt        numFaces;
5594 
5595           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5596           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5597           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5598           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5599         }
5600       }
5601     }
5602     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5603   }
5604 
5605   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5606   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5607   PetscFunctionReturn(0);
5608 }
5609 
5610 #undef __FUNCT__
5611 #define __FUNCT__ "DMPlexRefine_CTetgen"
5612 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5613 {
5614   MPI_Comm       comm = ((PetscObject) dm)->comm;
5615   const PetscInt dim  = 3;
5616   PLC           *in, *out;
5617   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5618   PetscMPIInt    rank;
5619   PetscErrorCode ierr;
5620 
5621   PetscFunctionBegin;
5622   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5623   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5624   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5625   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5626   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5627   ierr = PLCCreate(&in);CHKERRQ(ierr);
5628   ierr = PLCCreate(&out);CHKERRQ(ierr);
5629 
5630   in->numberofpoints = vEnd - vStart;
5631   if (in->numberofpoints > 0) {
5632     PetscSection coordSection;
5633     Vec          coordinates;
5634     PetscScalar *array;
5635 
5636     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5637     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5638     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5639     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5640     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5641     for (v = vStart; v < vEnd; ++v) {
5642       const PetscInt idx = v - vStart;
5643       PetscInt       off, d, m;
5644 
5645       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5646       for (d = 0; d < dim; ++d) {
5647         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5648       }
5649       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5650 
5651       in->pointmarkerlist[idx] = (int) m;
5652     }
5653     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5654   }
5655   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5656 
5657   in->numberofcorners       = 4;
5658   in->numberoftetrahedra    = cEnd - cStart;
5659   in->tetrahedronvolumelist = maxVolumes;
5660   if (in->numberoftetrahedra > 0) {
5661     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5662     for (c = cStart; c < cEnd; ++c) {
5663       const PetscInt idx      = c - cStart;
5664       PetscInt      *closure = NULL;
5665       PetscInt       closureSize;
5666 
5667       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5668       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5669       for (v = 0; v < 4; ++v) {
5670         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5671       }
5672       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5673     }
5674   }
5675   if (!rank) {
5676     TetGenOpts t;
5677 
5678     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5679 
5680     t.in        = dm; /* Should go away */
5681     t.refine    = 1;
5682     t.varvolume = 1;
5683     t.quality   = 1;
5684     t.edgesout  = 1;
5685     t.zeroindex = 1;
5686     t.quiet     = 1;
5687     t.verbose   = verbose; /* Change this */
5688 
5689     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5690     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5691   }
5692   {
5693     const PetscInt numCorners  = 4;
5694     const PetscInt numCells    = out->numberoftetrahedra;
5695     const PetscInt numVertices = out->numberofpoints;
5696     const int     *cells       = out->tetrahedronlist;
5697     const double  *meshCoords  = out->pointlist;
5698     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5699 
5700     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5701     /* Set labels */
5702     for (v = 0; v < numVertices; ++v) {
5703       if (out->pointmarkerlist[v]) {
5704         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5705       }
5706     }
5707     if (interpolate) {
5708       PetscInt e, f;
5709 
5710       for (e = 0; e < out->numberofedges; e++) {
5711         if (out->edgemarkerlist[e]) {
5712           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5713           const PetscInt *edges;
5714           PetscInt        numEdges;
5715 
5716           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5717           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5718           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5719           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5720         }
5721       }
5722       for (f = 0; f < out->numberoftrifaces; f++) {
5723         if (out->trifacemarkerlist[f]) {
5724           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5725           const PetscInt *faces;
5726           PetscInt        numFaces;
5727 
5728           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5729           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5730           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5731           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5732         }
5733       }
5734     }
5735     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5736   }
5737   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5738   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5739   PetscFunctionReturn(0);
5740 }
5741 #endif
5742 
5743 #undef __FUNCT__
5744 #define __FUNCT__ "DMPlexGenerate"
5745 /*@C
5746   DMPlexGenerate - Generates a mesh.
5747 
5748   Not Collective
5749 
5750   Input Parameters:
5751 + boundary - The DMPlex boundary object
5752 . name - The mesh generation package name
5753 - interpolate - Flag to create intermediate mesh elements
5754 
5755   Output Parameter:
5756 . mesh - The DMPlex object
5757 
5758   Level: intermediate
5759 
5760 .keywords: mesh, elements
5761 .seealso: DMPlexCreate(), DMRefine()
5762 @*/
5763 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5764 {
5765   PetscInt       dim;
5766   char           genname[1024];
5767   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5768   PetscErrorCode ierr;
5769 
5770   PetscFunctionBegin;
5771   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5772   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5773   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5774   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5775   if (flg) name = genname;
5776   if (name) {
5777     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5778     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5779     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5780   }
5781   switch (dim) {
5782   case 1:
5783     if (!name || isTriangle) {
5784 #if defined(PETSC_HAVE_TRIANGLE)
5785       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5786 #else
5787       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5788 #endif
5789     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5790     break;
5791   case 2:
5792     if (!name || isCTetgen) {
5793 #if defined(PETSC_HAVE_CTETGEN)
5794       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5795 #else
5796       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5797 #endif
5798     } else if (isTetgen) {
5799 #if defined(PETSC_HAVE_TETGEN)
5800       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5801 #else
5802       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5803 #endif
5804     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5805     break;
5806   default:
5807     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5808   }
5809   PetscFunctionReturn(0);
5810 }
5811 
5812 typedef PetscInt CellRefiner;
5813 
5814 #undef __FUNCT__
5815 #define __FUNCT__ "GetDepthStart_Private"
5816 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5817 {
5818   PetscFunctionBegin;
5819   if (cStart) *cStart = 0;
5820   if (vStart) *vStart = depthSize[depth];
5821   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5822   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5823   PetscFunctionReturn(0);
5824 }
5825 
5826 #undef __FUNCT__
5827 #define __FUNCT__ "GetDepthEnd_Private"
5828 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5829 {
5830   PetscFunctionBegin;
5831   if (cEnd) *cEnd = depthSize[depth];
5832   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5833   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5834   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5835   PetscFunctionReturn(0);
5836 }
5837 
5838 #undef __FUNCT__
5839 #define __FUNCT__ "CellRefinerGetSizes"
5840 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5841 {
5842   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5843   PetscErrorCode ierr;
5844 
5845   PetscFunctionBegin;
5846   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5847   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5848   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5849   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5850   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5851   switch (refiner) {
5852   case 1:
5853     /* Simplicial 2D */
5854     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5855     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5856     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5857     break;
5858   case 3:
5859     /* Hybrid 2D */
5860     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5861     cMax = PetscMin(cEnd, cMax);
5862     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5863     fMax         = PetscMin(fEnd, fMax);
5864     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5865     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 */
5866     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5867     break;
5868   case 2:
5869     /* Hex 2D */
5870     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5871     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5872     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5873     break;
5874   default:
5875     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5876   }
5877   PetscFunctionReturn(0);
5878 }
5879 
5880 #undef __FUNCT__
5881 #define __FUNCT__ "CellRefinerSetConeSizes"
5882 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5883 {
5884   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5885   PetscErrorCode ierr;
5886 
5887   PetscFunctionBegin;
5888   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5889   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5890   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5891   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5892   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5893   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5894   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5895   switch (refiner) {
5896   case 1:
5897     /* Simplicial 2D */
5898     /* All cells have 3 faces */
5899     for (c = cStart; c < cEnd; ++c) {
5900       for (r = 0; r < 4; ++r) {
5901         const PetscInt newp = (c - cStart)*4 + r;
5902 
5903         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5904       }
5905     }
5906     /* Split faces have 2 vertices and the same cells as the parent */
5907     for (f = fStart; f < fEnd; ++f) {
5908       for (r = 0; r < 2; ++r) {
5909         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5910         PetscInt       size;
5911 
5912         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5913         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5914         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5915       }
5916     }
5917     /* Interior faces have 2 vertices and 2 cells */
5918     for (c = cStart; c < cEnd; ++c) {
5919       for (r = 0; r < 3; ++r) {
5920         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5921 
5922         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5923         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5924       }
5925     }
5926     /* Old vertices have identical supports */
5927     for (v = vStart; v < vEnd; ++v) {
5928       const PetscInt newp = vStartNew + (v - vStart);
5929       PetscInt       size;
5930 
5931       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5932       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5933     }
5934     /* Face vertices have 2 + cells*2 supports */
5935     for (f = fStart; f < fEnd; ++f) {
5936       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5937       PetscInt       size;
5938 
5939       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5940       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5941     }
5942     break;
5943   case 2:
5944     /* Hex 2D */
5945     /* All cells have 4 faces */
5946     for (c = cStart; c < cEnd; ++c) {
5947       for (r = 0; r < 4; ++r) {
5948         const PetscInt newp = (c - cStart)*4 + r;
5949 
5950         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5951       }
5952     }
5953     /* Split faces have 2 vertices and the same cells as the parent */
5954     for (f = fStart; f < fEnd; ++f) {
5955       for (r = 0; r < 2; ++r) {
5956         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5957         PetscInt       size;
5958 
5959         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5960         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5961         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5962       }
5963     }
5964     /* Interior faces have 2 vertices and 2 cells */
5965     for (c = cStart; c < cEnd; ++c) {
5966       for (r = 0; r < 4; ++r) {
5967         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5968 
5969         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5970         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5971       }
5972     }
5973     /* Old vertices have identical supports */
5974     for (v = vStart; v < vEnd; ++v) {
5975       const PetscInt newp = vStartNew + (v - vStart);
5976       PetscInt       size;
5977 
5978       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5979       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5980     }
5981     /* Face vertices have 2 + cells supports */
5982     for (f = fStart; f < fEnd; ++f) {
5983       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5984       PetscInt       size;
5985 
5986       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5987       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5988     }
5989     /* Cell vertices have 4 supports */
5990     for (c = cStart; c < cEnd; ++c) {
5991       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5992 
5993       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5994     }
5995     break;
5996   case 3:
5997     /* Hybrid 2D */
5998     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5999     cMax = PetscMin(cEnd, cMax);
6000     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6001     fMax = PetscMin(fEnd, fMax);
6002     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6003     /* Interior cells have 3 faces */
6004     for (c = cStart; c < cMax; ++c) {
6005       for (r = 0; r < 4; ++r) {
6006         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
6007 
6008         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
6009       }
6010     }
6011     /* Hybrid cells have 4 faces */
6012     for (c = cMax; c < cEnd; ++c) {
6013       for (r = 0; r < 2; ++r) {
6014         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6015 
6016         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6017       }
6018     }
6019     /* Interior split faces have 2 vertices and the same cells as the parent */
6020     for (f = fStart; f < fMax; ++f) {
6021       for (r = 0; r < 2; ++r) {
6022         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6023         PetscInt       size;
6024 
6025         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6026         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6027         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6028       }
6029     }
6030     /* Interior cell faces have 2 vertices and 2 cells */
6031     for (c = cStart; c < cMax; ++c) {
6032       for (r = 0; r < 3; ++r) {
6033         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6034 
6035         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6036         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6037       }
6038     }
6039     /* Hybrid faces have 2 vertices and the same cells */
6040     for (f = fMax; f < fEnd; ++f) {
6041       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6042       PetscInt       size;
6043 
6044       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6045       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6046       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6047     }
6048     /* Hybrid cell faces have 2 vertices and 2 cells */
6049     for (c = cMax; c < cEnd; ++c) {
6050       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6051 
6052       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6053       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6054     }
6055     /* Old vertices have identical supports */
6056     for (v = vStart; v < vEnd; ++v) {
6057       const PetscInt newp = vStartNew + (v - vStart);
6058       PetscInt       size;
6059 
6060       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6061       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6062     }
6063     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6064     for (f = fStart; f < fMax; ++f) {
6065       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6066       const PetscInt *support;
6067       PetscInt       size, newSize = 2, s;
6068 
6069       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6070       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6071       for (s = 0; s < size; ++s) {
6072         if (support[s] >= cMax) newSize += 1;
6073         else newSize += 2;
6074       }
6075       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6076     }
6077     break;
6078   default:
6079     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6080   }
6081   PetscFunctionReturn(0);
6082 }
6083 
6084 #undef __FUNCT__
6085 #define __FUNCT__ "CellRefinerSetCones"
6086 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6087 {
6088   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;
6089   PetscInt       maxSupportSize, *supportRef;
6090   PetscErrorCode ierr;
6091 
6092   PetscFunctionBegin;
6093   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6094   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6095   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6096   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6097   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6098   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6099   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6100   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6101   switch (refiner) {
6102   case 1:
6103     /* Simplicial 2D */
6104     /*
6105      2
6106      |\
6107      | \
6108      |  \
6109      |   \
6110      | C  \
6111      |     \
6112      |      \
6113      2---1---1
6114      |\  D  / \
6115      | 2   0   \
6116      |A \ /  B  \
6117      0---0-------1
6118      */
6119     /* All cells have 3 faces */
6120     for (c = cStart; c < cEnd; ++c) {
6121       const PetscInt  newp = cStartNew + (c - cStart)*4;
6122       const PetscInt *cone, *ornt;
6123       PetscInt        coneNew[3], orntNew[3];
6124 
6125       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6126       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6127       /* A triangle */
6128       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6129       orntNew[0] = ornt[0];
6130       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6131       orntNew[1] = -2;
6132       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6133       orntNew[2] = ornt[2];
6134       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6135       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6136 #if 1
6137       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);
6138       for (p = 0; p < 3; ++p) {
6139         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);
6140       }
6141 #endif
6142       /* B triangle */
6143       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6144       orntNew[0] = ornt[0];
6145       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6146       orntNew[1] = ornt[1];
6147       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6148       orntNew[2] = -2;
6149       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6150       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6151 #if 1
6152       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);
6153       for (p = 0; p < 3; ++p) {
6154         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);
6155       }
6156 #endif
6157       /* C triangle */
6158       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6159       orntNew[0] = -2;
6160       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6161       orntNew[1] = ornt[1];
6162       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6163       orntNew[2] = ornt[2];
6164       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6165       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6166 #if 1
6167       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);
6168       for (p = 0; p < 3; ++p) {
6169         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);
6170       }
6171 #endif
6172       /* D triangle */
6173       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6174       orntNew[0] = 0;
6175       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6176       orntNew[1] = 0;
6177       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6178       orntNew[2] = 0;
6179       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6180       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6181 #if 1
6182       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);
6183       for (p = 0; p < 3; ++p) {
6184         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);
6185       }
6186 #endif
6187     }
6188     /* Split faces have 2 vertices and the same cells as the parent */
6189     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6190     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6191     for (f = fStart; f < fEnd; ++f) {
6192       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6193 
6194       for (r = 0; r < 2; ++r) {
6195         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6196         const PetscInt *cone, *support;
6197         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6198 
6199         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6200         coneNew[0]       = vStartNew + (cone[0] - vStart);
6201         coneNew[1]       = vStartNew + (cone[1] - vStart);
6202         coneNew[(r+1)%2] = newv;
6203         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6204 #if 1
6205         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6206         for (p = 0; p < 2; ++p) {
6207           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);
6208         }
6209 #endif
6210         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6211         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6212         for (s = 0; s < supportSize; ++s) {
6213           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6214           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6215           for (c = 0; c < coneSize; ++c) {
6216             if (cone[c] == f) break;
6217           }
6218           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6219         }
6220         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6221 #if 1
6222         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6223         for (p = 0; p < supportSize; ++p) {
6224           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);
6225         }
6226 #endif
6227       }
6228     }
6229     /* Interior faces have 2 vertices and 2 cells */
6230     for (c = cStart; c < cEnd; ++c) {
6231       const PetscInt *cone;
6232 
6233       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6234       for (r = 0; r < 3; ++r) {
6235         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6236         PetscInt       coneNew[2];
6237         PetscInt       supportNew[2];
6238 
6239         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6240         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6241         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6242 #if 1
6243         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6244         for (p = 0; p < 2; ++p) {
6245           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);
6246         }
6247 #endif
6248         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6249         supportNew[1] = (c - cStart)*4 + 3;
6250         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6251 #if 1
6252         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6253         for (p = 0; p < 2; ++p) {
6254           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);
6255         }
6256 #endif
6257       }
6258     }
6259     /* Old vertices have identical supports */
6260     for (v = vStart; v < vEnd; ++v) {
6261       const PetscInt  newp = vStartNew + (v - vStart);
6262       const PetscInt *support, *cone;
6263       PetscInt        size, s;
6264 
6265       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6266       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6267       for (s = 0; s < size; ++s) {
6268         PetscInt r = 0;
6269 
6270         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6271         if (cone[1] == v) r = 1;
6272         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6273       }
6274       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6275 #if 1
6276       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6277       for (p = 0; p < size; ++p) {
6278         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);
6279       }
6280 #endif
6281     }
6282     /* Face vertices have 2 + cells*2 supports */
6283     for (f = fStart; f < fEnd; ++f) {
6284       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6285       const PetscInt *cone, *support;
6286       PetscInt        size, s;
6287 
6288       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6289       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6290       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6291       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6292       for (s = 0; s < size; ++s) {
6293         PetscInt r = 0;
6294 
6295         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6296         if      (cone[1] == f) r = 1;
6297         else if (cone[2] == f) r = 2;
6298         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6299         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6300       }
6301       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6302 #if 1
6303       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6304       for (p = 0; p < 2+size*2; ++p) {
6305         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);
6306       }
6307 #endif
6308     }
6309     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6310     break;
6311   case 2:
6312     /* Hex 2D */
6313     /*
6314      3---------2---------2
6315      |         |         |
6316      |    D    2    C    |
6317      |         |         |
6318      3----3----0----1----1
6319      |         |         |
6320      |    A    0    B    |
6321      |         |         |
6322      0---------0---------1
6323      */
6324     /* All cells have 4 faces */
6325     for (c = cStart; c < cEnd; ++c) {
6326       const PetscInt  newp = (c - cStart)*4;
6327       const PetscInt *cone, *ornt;
6328       PetscInt        coneNew[4], orntNew[4];
6329 
6330       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6331       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6332       /* A quad */
6333       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6334       orntNew[0] = ornt[0];
6335       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6336       orntNew[1] = 0;
6337       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6338       orntNew[2] = -2;
6339       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6340       orntNew[3] = ornt[3];
6341       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6342       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6343 #if 1
6344       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);
6345       for (p = 0; p < 4; ++p) {
6346         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);
6347       }
6348 #endif
6349       /* B quad */
6350       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6351       orntNew[0] = ornt[0];
6352       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6353       orntNew[1] = ornt[1];
6354       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6355       orntNew[2] = 0;
6356       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6357       orntNew[3] = -2;
6358       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6359       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6360 #if 1
6361       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);
6362       for (p = 0; p < 4; ++p) {
6363         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);
6364       }
6365 #endif
6366       /* C quad */
6367       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6368       orntNew[0] = -2;
6369       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6370       orntNew[1] = ornt[1];
6371       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6372       orntNew[2] = ornt[2];
6373       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6374       orntNew[3] = 0;
6375       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6376       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6377 #if 1
6378       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);
6379       for (p = 0; p < 4; ++p) {
6380         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);
6381       }
6382 #endif
6383       /* D quad */
6384       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6385       orntNew[0] = 0;
6386       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6387       orntNew[1] = -2;
6388       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6389       orntNew[2] = ornt[2];
6390       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6391       orntNew[3] = ornt[3];
6392       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6393       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6394 #if 1
6395       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);
6396       for (p = 0; p < 4; ++p) {
6397         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);
6398       }
6399 #endif
6400     }
6401     /* Split faces have 2 vertices and the same cells as the parent */
6402     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6403     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6404     for (f = fStart; f < fEnd; ++f) {
6405       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6406 
6407       for (r = 0; r < 2; ++r) {
6408         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6409         const PetscInt *cone, *support;
6410         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6411 
6412         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6413         coneNew[0]       = vStartNew + (cone[0] - vStart);
6414         coneNew[1]       = vStartNew + (cone[1] - vStart);
6415         coneNew[(r+1)%2] = newv;
6416         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6417 #if 1
6418         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6419         for (p = 0; p < 2; ++p) {
6420           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);
6421         }
6422 #endif
6423         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6424         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6425         for (s = 0; s < supportSize; ++s) {
6426           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6427           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6428           for (c = 0; c < coneSize; ++c) {
6429             if (cone[c] == f) break;
6430           }
6431           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6432         }
6433         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6434 #if 1
6435         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6436         for (p = 0; p < supportSize; ++p) {
6437           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);
6438         }
6439 #endif
6440       }
6441     }
6442     /* Interior faces have 2 vertices and 2 cells */
6443     for (c = cStart; c < cEnd; ++c) {
6444       const PetscInt *cone;
6445       PetscInt        coneNew[2], supportNew[2];
6446 
6447       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6448       for (r = 0; r < 4; ++r) {
6449         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6450 
6451         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6452         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6453         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6454 #if 1
6455         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6456         for (p = 0; p < 2; ++p) {
6457           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);
6458         }
6459 #endif
6460         supportNew[0] = (c - cStart)*4 + r;
6461         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6462         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6463 #if 1
6464         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6465         for (p = 0; p < 2; ++p) {
6466           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);
6467         }
6468 #endif
6469       }
6470     }
6471     /* Old vertices have identical supports */
6472     for (v = vStart; v < vEnd; ++v) {
6473       const PetscInt  newp = vStartNew + (v - vStart);
6474       const PetscInt *support, *cone;
6475       PetscInt        size, s;
6476 
6477       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6478       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6479       for (s = 0; s < size; ++s) {
6480         PetscInt r = 0;
6481 
6482         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6483         if (cone[1] == v) r = 1;
6484         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6485       }
6486       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6487 #if 1
6488       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6489       for (p = 0; p < size; ++p) {
6490         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);
6491       }
6492 #endif
6493     }
6494     /* Face vertices have 2 + cells supports */
6495     for (f = fStart; f < fEnd; ++f) {
6496       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6497       const PetscInt *cone, *support;
6498       PetscInt        size, s;
6499 
6500       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6501       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6502       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6503       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6504       for (s = 0; s < size; ++s) {
6505         PetscInt r = 0;
6506 
6507         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6508         if      (cone[1] == f) r = 1;
6509         else if (cone[2] == f) r = 2;
6510         else if (cone[3] == f) r = 3;
6511         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6512       }
6513       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6514 #if 1
6515       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6516       for (p = 0; p < 2+size; ++p) {
6517         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);
6518       }
6519 #endif
6520     }
6521     /* Cell vertices have 4 supports */
6522     for (c = cStart; c < cEnd; ++c) {
6523       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6524       PetscInt       supportNew[4];
6525 
6526       for (r = 0; r < 4; ++r) {
6527         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6528       }
6529       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6530     }
6531     break;
6532   case 3:
6533     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6534     cMax = PetscMin(cEnd, cMax);
6535     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6536     fMax = PetscMin(fEnd, fMax);
6537     /* Interior cells have 3 faces */
6538     for (c = cStart; c < cMax; ++c) {
6539       const PetscInt  newp = cStartNew + (c - cStart)*4;
6540       const PetscInt *cone, *ornt;
6541       PetscInt        coneNew[3], orntNew[3];
6542 
6543       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6544       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6545       /* A triangle */
6546       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6547       orntNew[0] = ornt[0];
6548       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6549       orntNew[1] = -2;
6550       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6551       orntNew[2] = ornt[2];
6552       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6553       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6554 #if 1
6555       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);
6556       for (p = 0; p < 3; ++p) {
6557         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);
6558       }
6559 #endif
6560       /* B triangle */
6561       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6562       orntNew[0] = ornt[0];
6563       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6564       orntNew[1] = ornt[1];
6565       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6566       orntNew[2] = -2;
6567       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6568       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6569 #if 1
6570       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);
6571       for (p = 0; p < 3; ++p) {
6572         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);
6573       }
6574 #endif
6575       /* C triangle */
6576       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6577       orntNew[0] = -2;
6578       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6579       orntNew[1] = ornt[1];
6580       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6581       orntNew[2] = ornt[2];
6582       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6583       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6584 #if 1
6585       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);
6586       for (p = 0; p < 3; ++p) {
6587         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);
6588       }
6589 #endif
6590       /* D triangle */
6591       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6592       orntNew[0] = 0;
6593       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6594       orntNew[1] = 0;
6595       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6596       orntNew[2] = 0;
6597       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6598       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6599 #if 1
6600       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);
6601       for (p = 0; p < 3; ++p) {
6602         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);
6603       }
6604 #endif
6605     }
6606     /*
6607      2----3----3
6608      |         |
6609      |    B    |
6610      |         |
6611      0----4--- 1
6612      |         |
6613      |    A    |
6614      |         |
6615      0----2----1
6616      */
6617     /* Hybrid cells have 4 faces */
6618     for (c = cMax; c < cEnd; ++c) {
6619       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6620       const PetscInt *cone, *ornt;
6621       PetscInt        coneNew[4], orntNew[4];
6622 
6623       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6624       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6625       /* A quad */
6626       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6627       orntNew[0] = ornt[0];
6628       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6629       orntNew[1] = ornt[1];
6630       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6631       orntNew[2] = 0;
6632       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6633       orntNew[3] = 0;
6634       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6635       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6636 #if 1
6637       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);
6638       for (p = 0; p < 4; ++p) {
6639         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);
6640       }
6641 #endif
6642       /* B quad */
6643       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6644       orntNew[0] = ornt[0];
6645       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6646       orntNew[1] = ornt[1];
6647       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6648       orntNew[2] = 0;
6649       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6650       orntNew[3] = 0;
6651       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6652       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6653 #if 1
6654       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);
6655       for (p = 0; p < 4; ++p) {
6656         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);
6657       }
6658 #endif
6659     }
6660     /* Interior split faces have 2 vertices and the same cells as the parent */
6661     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6662     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6663     for (f = fStart; f < fMax; ++f) {
6664       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6665 
6666       for (r = 0; r < 2; ++r) {
6667         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6668         const PetscInt *cone, *support;
6669         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6670 
6671         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6672         coneNew[0]       = vStartNew + (cone[0] - vStart);
6673         coneNew[1]       = vStartNew + (cone[1] - vStart);
6674         coneNew[(r+1)%2] = newv;
6675         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6676 #if 1
6677         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6678         for (p = 0; p < 2; ++p) {
6679           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);
6680         }
6681 #endif
6682         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6683         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6684         for (s = 0; s < supportSize; ++s) {
6685           if (support[s] >= cMax) {
6686             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6687           } else {
6688             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6689             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6690             for (c = 0; c < coneSize; ++c) {
6691               if (cone[c] == f) break;
6692             }
6693             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6694           }
6695         }
6696         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6697 #if 1
6698         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6699         for (p = 0; p < supportSize; ++p) {
6700           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);
6701         }
6702 #endif
6703       }
6704     }
6705     /* Interior cell faces have 2 vertices and 2 cells */
6706     for (c = cStart; c < cMax; ++c) {
6707       const PetscInt *cone;
6708 
6709       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6710       for (r = 0; r < 3; ++r) {
6711         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6712         PetscInt       coneNew[2];
6713         PetscInt       supportNew[2];
6714 
6715         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6716         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6717         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6718 #if 1
6719         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6720         for (p = 0; p < 2; ++p) {
6721           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);
6722         }
6723 #endif
6724         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6725         supportNew[1] = (c - cStart)*4 + 3;
6726         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6727 #if 1
6728         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6729         for (p = 0; p < 2; ++p) {
6730           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);
6731         }
6732 #endif
6733       }
6734     }
6735     /* Interior hybrid faces have 2 vertices and the same cells */
6736     for (f = fMax; f < fEnd; ++f) {
6737       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6738       const PetscInt *cone;
6739       const PetscInt *support;
6740       PetscInt        coneNew[2];
6741       PetscInt        supportNew[2];
6742       PetscInt        size, s, r;
6743 
6744       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6745       coneNew[0] = vStartNew + (cone[0] - vStart);
6746       coneNew[1] = vStartNew + (cone[1] - vStart);
6747       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6748 #if 1
6749       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6750       for (p = 0; p < 2; ++p) {
6751         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);
6752       }
6753 #endif
6754       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6755       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6756       for (s = 0; s < size; ++s) {
6757         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6758         for (r = 0; r < 2; ++r) {
6759           if (cone[r+2] == f) break;
6760         }
6761         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6762       }
6763       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6764 #if 1
6765       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6766       for (p = 0; p < size; ++p) {
6767         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);
6768       }
6769 #endif
6770     }
6771     /* Cell hybrid faces have 2 vertices and 2 cells */
6772     for (c = cMax; c < cEnd; ++c) {
6773       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6774       const PetscInt *cone;
6775       PetscInt        coneNew[2];
6776       PetscInt        supportNew[2];
6777 
6778       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6779       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6780       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6781       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6782 #if 1
6783       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6784       for (p = 0; p < 2; ++p) {
6785         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);
6786       }
6787 #endif
6788       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6789       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6790       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6791 #if 1
6792       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6793       for (p = 0; p < 2; ++p) {
6794         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);
6795       }
6796 #endif
6797     }
6798     /* Old vertices have identical supports */
6799     for (v = vStart; v < vEnd; ++v) {
6800       const PetscInt  newp = vStartNew + (v - vStart);
6801       const PetscInt *support, *cone;
6802       PetscInt        size, s;
6803 
6804       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6805       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6806       for (s = 0; s < size; ++s) {
6807         if (support[s] >= fMax) {
6808           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6809         } else {
6810           PetscInt r = 0;
6811 
6812           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6813           if (cone[1] == v) r = 1;
6814           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6815         }
6816       }
6817       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6818 #if 1
6819       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6820       for (p = 0; p < size; ++p) {
6821         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);
6822       }
6823 #endif
6824     }
6825     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6826     for (f = fStart; f < fMax; ++f) {
6827       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6828       const PetscInt *cone, *support;
6829       PetscInt        size, newSize = 2, s;
6830 
6831       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6832       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6833       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6834       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6835       for (s = 0; s < size; ++s) {
6836         PetscInt r = 0;
6837 
6838         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6839         if (support[s] >= cMax) {
6840           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6841 
6842           newSize += 1;
6843         } else {
6844           if      (cone[1] == f) r = 1;
6845           else if (cone[2] == f) r = 2;
6846           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6847           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6848 
6849           newSize += 2;
6850         }
6851       }
6852       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6853 #if 1
6854       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6855       for (p = 0; p < newSize; ++p) {
6856         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);
6857       }
6858 #endif
6859     }
6860     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6861     break;
6862   default:
6863     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6864   }
6865   PetscFunctionReturn(0);
6866 }
6867 
6868 #undef __FUNCT__
6869 #define __FUNCT__ "CellRefinerSetCoordinates"
6870 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6871 {
6872   PetscSection   coordSection, coordSectionNew;
6873   Vec            coordinates, coordinatesNew;
6874   PetscScalar   *coords, *coordsNew;
6875   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6876   PetscErrorCode ierr;
6877 
6878   PetscFunctionBegin;
6879   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6880   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6881   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6882   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6883   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6884   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6885   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6886   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6887   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6888   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6889   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6890   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6891   if (fMax < 0) fMax = fEnd;
6892   switch (refiner) {
6893   case 1:
6894   case 2:
6895   case 3:
6896     /* Simplicial and Hex 2D */
6897     /* All vertices have the dim coordinates */
6898     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6899       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6900       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6901     }
6902     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6903     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6904     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6905     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6906     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6907     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6908     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6909     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6910     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6911     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6912     /* Old vertices have the same coordinates */
6913     for (v = vStart; v < vEnd; ++v) {
6914       const PetscInt newv = vStartNew + (v - vStart);
6915       PetscInt       off, offnew, d;
6916 
6917       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6918       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6919       for (d = 0; d < dim; ++d) {
6920         coordsNew[offnew+d] = coords[off+d];
6921       }
6922     }
6923     /* Face vertices have the average of endpoint coordinates */
6924     for (f = fStart; f < fMax; ++f) {
6925       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6926       const PetscInt *cone;
6927       PetscInt        coneSize, offA, offB, offnew, d;
6928 
6929       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6930       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6931       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6932       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6933       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6934       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6935       for (d = 0; d < dim; ++d) {
6936         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6937       }
6938     }
6939     /* Just Hex 2D */
6940     if (refiner == 2) {
6941       /* Cell vertices have the average of corner coordinates */
6942       for (c = cStart; c < cEnd; ++c) {
6943         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6944         PetscInt      *cone = NULL;
6945         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6946 
6947         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6948         for (p = 0; p < closureSize*2; p += 2) {
6949           const PetscInt point = cone[p];
6950           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6951         }
6952         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6953         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6954         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6955         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6956         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6957         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6958         for (d = 0; d < dim; ++d) {
6959           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6960         }
6961         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6962       }
6963     }
6964     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6965     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6966     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6967     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6968     break;
6969   default:
6970     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6971   }
6972   PetscFunctionReturn(0);
6973 }
6974 
6975 #undef __FUNCT__
6976 #define __FUNCT__ "DMPlexCreateProcessSF"
6977 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6978 {
6979   PetscInt           numRoots, numLeaves, l;
6980   const PetscInt    *localPoints;
6981   const PetscSFNode *remotePoints;
6982   PetscInt          *localPointsNew;
6983   PetscSFNode       *remotePointsNew;
6984   PetscInt          *ranks, *ranksNew;
6985   PetscErrorCode     ierr;
6986 
6987   PetscFunctionBegin;
6988   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6989   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6990   for (l = 0; l < numLeaves; ++l) {
6991     ranks[l] = remotePoints[l].rank;
6992   }
6993   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6994   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6995   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6996   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6997   for (l = 0; l < numLeaves; ++l) {
6998     ranksNew[l]              = ranks[l];
6999     localPointsNew[l]        = l;
7000     remotePointsNew[l].index = 0;
7001     remotePointsNew[l].rank  = ranksNew[l];
7002   }
7003   ierr = PetscFree(ranks);CHKERRQ(ierr);
7004   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
7005   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
7006   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7007   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7008   PetscFunctionReturn(0);
7009 }
7010 
7011 #undef __FUNCT__
7012 #define __FUNCT__ "CellRefinerCreateSF"
7013 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7014 {
7015   PetscSF            sf, sfNew, sfProcess;
7016   IS                 processRanks;
7017   MPI_Datatype       depthType;
7018   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7019   const PetscInt    *localPoints, *neighbors;
7020   const PetscSFNode *remotePoints;
7021   PetscInt          *localPointsNew;
7022   PetscSFNode       *remotePointsNew;
7023   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7024   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7025   PetscErrorCode     ierr;
7026 
7027   PetscFunctionBegin;
7028   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7029   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7030   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7031   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7032   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7033   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7034   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7035   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7036   switch (refiner) {
7037   case 3:
7038     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7039     cMax = PetscMin(cEnd, cMax);
7040     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7041     fMax = PetscMin(fEnd, fMax);
7042   }
7043   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7044   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7045   /* Caculate size of new SF */
7046   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7047   if (numRoots < 0) PetscFunctionReturn(0);
7048   for (l = 0; l < numLeaves; ++l) {
7049     const PetscInt p = localPoints[l];
7050 
7051     switch (refiner) {
7052     case 1:
7053       /* Simplicial 2D */
7054       if ((p >= vStart) && (p < vEnd)) {
7055         /* Old vertices stay the same */
7056         ++numLeavesNew;
7057       } else if ((p >= fStart) && (p < fEnd)) {
7058         /* Old faces add new faces and vertex */
7059         numLeavesNew += 1 + 2;
7060       } else if ((p >= cStart) && (p < cEnd)) {
7061         /* Old cells add new cells and interior faces */
7062         numLeavesNew += 4 + 3;
7063       }
7064       break;
7065     case 2:
7066       /* Hex 2D */
7067       if ((p >= vStart) && (p < vEnd)) {
7068         /* Old vertices stay the same */
7069         ++numLeavesNew;
7070       } else if ((p >= fStart) && (p < fEnd)) {
7071         /* Old faces add new faces and vertex */
7072         numLeavesNew += 1 + 2;
7073       } else if ((p >= cStart) && (p < cEnd)) {
7074         /* Old cells add new cells and interior faces */
7075         numLeavesNew += 4 + 4;
7076       }
7077       break;
7078     default:
7079       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7080     }
7081   }
7082   /* Communicate depthSizes for each remote rank */
7083   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7084   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7085   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7086   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);
7087   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7088   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7089   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7090   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7091   for (n = 0; n < numNeighbors; ++n) {
7092     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7093   }
7094   depthSizeOld[depth]   = cMax;
7095   depthSizeOld[0]       = vMax;
7096   depthSizeOld[depth-1] = fMax;
7097   depthSizeOld[1]       = eMax;
7098 
7099   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7100   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7101 
7102   depthSizeOld[depth]   = cEnd - cStart;
7103   depthSizeOld[0]       = vEnd - vStart;
7104   depthSizeOld[depth-1] = fEnd - fStart;
7105   depthSizeOld[1]       = eEnd - eStart;
7106 
7107   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7108   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7109   for (n = 0; n < numNeighbors; ++n) {
7110     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7111   }
7112   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7113   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7114   /* Calculate new point SF */
7115   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7116   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7117   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7118   for (l = 0, m = 0; l < numLeaves; ++l) {
7119     PetscInt    p     = localPoints[l];
7120     PetscInt    rp    = remotePoints[l].index, n;
7121     PetscMPIInt rrank = remotePoints[l].rank;
7122 
7123     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7124     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7125     switch (refiner) {
7126     case 1:
7127       /* Simplicial 2D */
7128       if ((p >= vStart) && (p < vEnd)) {
7129         /* Old vertices stay the same */
7130         localPointsNew[m]        = vStartNew     + (p  - vStart);
7131         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7132         remotePointsNew[m].rank  = rrank;
7133         ++m;
7134       } else if ((p >= fStart) && (p < fEnd)) {
7135         /* Old faces add new faces and vertex */
7136         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7137         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7138         remotePointsNew[m].rank  = rrank;
7139         ++m;
7140         for (r = 0; r < 2; ++r, ++m) {
7141           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7142           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7143           remotePointsNew[m].rank  = rrank;
7144         }
7145       } else if ((p >= cStart) && (p < cEnd)) {
7146         /* Old cells add new cells and interior faces */
7147         for (r = 0; r < 4; ++r, ++m) {
7148           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7149           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7150           remotePointsNew[m].rank  = rrank;
7151         }
7152         for (r = 0; r < 3; ++r, ++m) {
7153           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7154           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7155           remotePointsNew[m].rank  = rrank;
7156         }
7157       }
7158       break;
7159     case 2:
7160       /* Hex 2D */
7161       if ((p >= vStart) && (p < vEnd)) {
7162         /* Old vertices stay the same */
7163         localPointsNew[m]        = vStartNew     + (p  - vStart);
7164         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7165         remotePointsNew[m].rank  = rrank;
7166         ++m;
7167       } else if ((p >= fStart) && (p < fEnd)) {
7168         /* Old faces add new faces and vertex */
7169         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7170         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7171         remotePointsNew[m].rank  = rrank;
7172         ++m;
7173         for (r = 0; r < 2; ++r, ++m) {
7174           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7175           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7176           remotePointsNew[m].rank  = rrank;
7177         }
7178       } else if ((p >= cStart) && (p < cEnd)) {
7179         /* Old cells add new cells and interior faces */
7180         for (r = 0; r < 4; ++r, ++m) {
7181           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7182           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7183           remotePointsNew[m].rank  = rrank;
7184         }
7185         for (r = 0; r < 4; ++r, ++m) {
7186           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7187           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7188           remotePointsNew[m].rank  = rrank;
7189         }
7190       }
7191       break;
7192     case 3:
7193       /* Hybrid simplicial 2D */
7194       if ((p >= vStart) && (p < vEnd)) {
7195         /* Old vertices stay the same */
7196         localPointsNew[m]        = vStartNew     + (p  - vStart);
7197         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7198         remotePointsNew[m].rank  = rrank;
7199         ++m;
7200       } else if ((p >= fStart) && (p < fMax)) {
7201         /* Old interior faces add new faces and vertex */
7202         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7203         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7204         remotePointsNew[m].rank  = rrank;
7205         ++m;
7206         for (r = 0; r < 2; ++r, ++m) {
7207           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7208           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7209           remotePointsNew[m].rank  = rrank;
7210         }
7211       } else if ((p >= fMax) && (p < fEnd)) {
7212         /* Old hybrid faces stay the same */
7213         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7214         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7215         remotePointsNew[m].rank  = rrank;
7216         ++m;
7217       } else if ((p >= cStart) && (p < cMax)) {
7218         /* Old interior cells add new cells and interior faces */
7219         for (r = 0; r < 4; ++r, ++m) {
7220           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7221           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7222           remotePointsNew[m].rank  = rrank;
7223         }
7224         for (r = 0; r < 3; ++r, ++m) {
7225           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7226           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7227           remotePointsNew[m].rank  = rrank;
7228         }
7229       } else if ((p >= cStart) && (p < cMax)) {
7230         /* Old hybrid cells add new cells and hybrid face */
7231         for (r = 0; r < 2; ++r, ++m) {
7232           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7233           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7234           remotePointsNew[m].rank  = rrank;
7235         }
7236         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7237         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]);
7238         remotePointsNew[m].rank  = rrank;
7239         ++m;
7240       }
7241       break;
7242     default:
7243       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7244     }
7245   }
7246   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7247   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7248   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7249   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7250   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7251   PetscFunctionReturn(0);
7252 }
7253 
7254 #undef __FUNCT__
7255 #define __FUNCT__ "CellRefinerCreateLabels"
7256 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7257 {
7258   PetscInt       numLabels, l;
7259   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7260   PetscErrorCode ierr;
7261 
7262   PetscFunctionBegin;
7263   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7264   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7265   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7266   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7267 
7268   cStartNew = 0;
7269   vStartNew = depthSize[2];
7270   fStartNew = depthSize[2] + depthSize[0];
7271 
7272   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7273   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7274   switch (refiner) {
7275   case 3:
7276     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7277     cMax = PetscMin(cEnd, cMax);
7278     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7279     fMax = PetscMin(fEnd, fMax);
7280   }
7281   for (l = 0; l < numLabels; ++l) {
7282     DMLabel         label, labelNew;
7283     const char     *lname;
7284     PetscBool       isDepth;
7285     IS              valueIS;
7286     const PetscInt *values;
7287     PetscInt        numValues, val;
7288 
7289     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7290     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7291     if (isDepth) continue;
7292     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7293     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7294     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7295     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7296     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7297     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7298     for (val = 0; val < numValues; ++val) {
7299       IS              pointIS;
7300       const PetscInt *points;
7301       PetscInt        numPoints, n;
7302 
7303       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7304       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7305       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7306       for (n = 0; n < numPoints; ++n) {
7307         const PetscInt p = points[n];
7308         switch (refiner) {
7309         case 1:
7310           /* Simplicial 2D */
7311           if ((p >= vStart) && (p < vEnd)) {
7312             /* Old vertices stay the same */
7313             newp = vStartNew + (p - vStart);
7314             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7315           } else if ((p >= fStart) && (p < fEnd)) {
7316             /* Old faces add new faces and vertex */
7317             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7318             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7319             for (r = 0; r < 2; ++r) {
7320               newp = fStartNew + (p - fStart)*2 + r;
7321               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7322             }
7323           } else if ((p >= cStart) && (p < cEnd)) {
7324             /* Old cells add new cells and interior faces */
7325             for (r = 0; r < 4; ++r) {
7326               newp = cStartNew + (p - cStart)*4 + r;
7327               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7328             }
7329             for (r = 0; r < 3; ++r) {
7330               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7331               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7332             }
7333           }
7334           break;
7335         case 2:
7336           /* Hex 2D */
7337           if ((p >= vStart) && (p < vEnd)) {
7338             /* Old vertices stay the same */
7339             newp = vStartNew + (p - vStart);
7340             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7341           } else if ((p >= fStart) && (p < fEnd)) {
7342             /* Old faces add new faces and vertex */
7343             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7344             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7345             for (r = 0; r < 2; ++r) {
7346               newp = fStartNew + (p - fStart)*2 + r;
7347               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7348             }
7349           } else if ((p >= cStart) && (p < cEnd)) {
7350             /* Old cells add new cells and interior faces and vertex */
7351             for (r = 0; r < 4; ++r) {
7352               newp = cStartNew + (p - cStart)*4 + r;
7353               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7354             }
7355             for (r = 0; r < 4; ++r) {
7356               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7357               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7358             }
7359             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7360             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7361           }
7362           break;
7363         case 3:
7364           /* Hybrid simplicial 2D */
7365           if ((p >= vStart) && (p < vEnd)) {
7366             /* Old vertices stay the same */
7367             newp = vStartNew + (p - vStart);
7368             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7369           } else if ((p >= fStart) && (p < fMax)) {
7370             /* Old interior faces add new faces and vertex */
7371             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7372             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7373             for (r = 0; r < 2; ++r) {
7374               newp = fStartNew + (p - fStart)*2 + r;
7375               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7376             }
7377           } else if ((p >= fMax) && (p < fEnd)) {
7378             /* Old hybrid faces stay the same */
7379             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7380             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7381           } else if ((p >= cStart) && (p < cMax)) {
7382             /* Old interior cells add new cells and interior faces */
7383             for (r = 0; r < 4; ++r) {
7384               newp = cStartNew + (p - cStart)*4 + r;
7385               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7386             }
7387             for (r = 0; r < 3; ++r) {
7388               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7389               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7390             }
7391           } else if ((p >= cMax) && (p < cEnd)) {
7392             /* Old hybrid cells add new cells and hybrid face */
7393             for (r = 0; r < 2; ++r) {
7394               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7395               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7396             }
7397             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7398             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7399           }
7400           break;
7401         default:
7402           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7403         }
7404       }
7405       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7406       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7407     }
7408     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7409     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7410     if (0) {
7411       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7412       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7413       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7414     }
7415   }
7416   PetscFunctionReturn(0);
7417 }
7418 
7419 #undef __FUNCT__
7420 #define __FUNCT__ "DMPlexRefine_Uniform"
7421 /* This will only work for interpolated meshes */
7422 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7423 {
7424   DM             rdm;
7425   PetscInt      *depthSize;
7426   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7427   PetscErrorCode ierr;
7428 
7429   PetscFunctionBegin;
7430   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7431   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7432   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7433   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7434   /* Calculate number of new points of each depth */
7435   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7436   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7437   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7438   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7439   /* Step 1: Set chart */
7440   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7441   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7442   /* Step 2: Set cone/support sizes */
7443   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7444   /* Step 3: Setup refined DM */
7445   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7446   /* Step 4: Set cones and supports */
7447   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7448   /* Step 5: Stratify */
7449   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7450   /* Step 6: Set coordinates for vertices */
7451   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7452   /* Step 7: Create pointSF */
7453   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7454   /* Step 8: Create labels */
7455   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7456   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7457 
7458   *dmRefined = rdm;
7459   PetscFunctionReturn(0);
7460 }
7461 
7462 #undef __FUNCT__
7463 #define __FUNCT__ "DMPlexSetRefinementUniform"
7464 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7465 {
7466   DM_Plex *mesh = (DM_Plex*) dm->data;
7467 
7468   PetscFunctionBegin;
7469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7470   mesh->refinementUniform = refinementUniform;
7471   PetscFunctionReturn(0);
7472 }
7473 
7474 #undef __FUNCT__
7475 #define __FUNCT__ "DMPlexGetRefinementUniform"
7476 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7477 {
7478   DM_Plex *mesh = (DM_Plex*) dm->data;
7479 
7480   PetscFunctionBegin;
7481   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7482   PetscValidPointer(refinementUniform,  2);
7483   *refinementUniform = mesh->refinementUniform;
7484   PetscFunctionReturn(0);
7485 }
7486 
7487 #undef __FUNCT__
7488 #define __FUNCT__ "DMPlexSetRefinementLimit"
7489 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7490 {
7491   DM_Plex *mesh = (DM_Plex*) dm->data;
7492 
7493   PetscFunctionBegin;
7494   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7495   mesh->refinementLimit = refinementLimit;
7496   PetscFunctionReturn(0);
7497 }
7498 
7499 #undef __FUNCT__
7500 #define __FUNCT__ "DMPlexGetRefinementLimit"
7501 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7502 {
7503   DM_Plex *mesh = (DM_Plex*) dm->data;
7504 
7505   PetscFunctionBegin;
7506   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7507   PetscValidPointer(refinementLimit,  2);
7508   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7509   *refinementLimit = mesh->refinementLimit;
7510   PetscFunctionReturn(0);
7511 }
7512 
7513 #undef __FUNCT__
7514 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7515 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7516 {
7517   PetscInt       dim, cStart, coneSize, cMax;
7518   PetscErrorCode ierr;
7519 
7520   PetscFunctionBegin;
7521   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7522   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7523   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7524   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7525   switch (dim) {
7526   case 2:
7527     switch (coneSize) {
7528     case 3:
7529       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7530       else *cellRefiner = 1; /* Triangular */
7531       break;
7532     case 4:
7533       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7534       else *cellRefiner = 2; /* Quadrilateral */
7535       break;
7536     default:
7537       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7538     }
7539     break;
7540   default:
7541     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7542   }
7543   PetscFunctionReturn(0);
7544 }
7545 
7546 #undef __FUNCT__
7547 #define __FUNCT__ "DMRefine_Plex"
7548 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7549 {
7550   PetscReal      refinementLimit;
7551   PetscInt       dim, cStart, cEnd;
7552   char           genname[1024], *name = NULL;
7553   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7554   PetscErrorCode ierr;
7555 
7556   PetscFunctionBegin;
7557   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7558   if (isUniform) {
7559     CellRefiner cellRefiner;
7560 
7561     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7562     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7563     PetscFunctionReturn(0);
7564   }
7565   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7566   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7567   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7568   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7569   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7570   if (flg) name = genname;
7571   if (name) {
7572     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7573     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7574     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7575   }
7576   switch (dim) {
7577   case 2:
7578     if (!name || isTriangle) {
7579 #if defined(PETSC_HAVE_TRIANGLE)
7580       double  *maxVolumes;
7581       PetscInt c;
7582 
7583       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7584       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7585       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7586 #else
7587       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7588 #endif
7589     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7590     break;
7591   case 3:
7592     if (!name || isCTetgen) {
7593 #if defined(PETSC_HAVE_CTETGEN)
7594       PetscReal *maxVolumes;
7595       PetscInt   c;
7596 
7597       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7598       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7599       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7600 #else
7601       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7602 #endif
7603     } else if (isTetgen) {
7604 #if defined(PETSC_HAVE_TETGEN)
7605       double  *maxVolumes;
7606       PetscInt c;
7607 
7608       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7609       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7610       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7611 #else
7612       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7613 #endif
7614     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7615     break;
7616   default:
7617     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7618   }
7619   PetscFunctionReturn(0);
7620 }
7621 
7622 #undef __FUNCT__
7623 #define __FUNCT__ "DMPlexGetDepth"
7624 /*@
7625   DMPlexGetDepth - get the number of strata
7626 
7627   Not Collective
7628 
7629   Input Parameters:
7630 . dm           - The DMPlex object
7631 
7632   Output Parameters:
7633 . depth - number of strata
7634 
7635   Level: developer
7636 
7637   Notes:
7638   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7639 
7640 .keywords: mesh, points
7641 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7642 @*/
7643 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7644 {
7645   PetscInt       d;
7646   PetscErrorCode ierr;
7647 
7648   PetscFunctionBegin;
7649   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7650   PetscValidPointer(depth, 2);
7651   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7652   *depth = d-1;
7653   PetscFunctionReturn(0);
7654 }
7655 
7656 #undef __FUNCT__
7657 #define __FUNCT__ "DMPlexGetDepthStratum"
7658 /*@
7659   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7660 
7661   Not Collective
7662 
7663   Input Parameters:
7664 + dm           - The DMPlex object
7665 - stratumValue - The requested depth
7666 
7667   Output Parameters:
7668 + start - The first point at this depth
7669 - end   - One beyond the last point at this depth
7670 
7671   Level: developer
7672 
7673 .keywords: mesh, points
7674 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7675 @*/
7676 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7677 {
7678   DM_Plex       *mesh = (DM_Plex*) dm->data;
7679   DMLabel        next  = mesh->labels;
7680   PetscBool      flg   = PETSC_FALSE;
7681   PetscInt       depth;
7682   PetscErrorCode ierr;
7683 
7684   PetscFunctionBegin;
7685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7686   if (stratumValue < 0) {
7687     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7688     PetscFunctionReturn(0);
7689   } else {
7690     PetscInt pStart, pEnd;
7691 
7692     if (start) *start = 0;
7693     if (end)   *end   = 0;
7694     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7695     if (pStart == pEnd) PetscFunctionReturn(0);
7696   }
7697   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7698   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7699   /* We should have a generic GetLabel() and a Label class */
7700   while (next) {
7701     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7702     if (flg) break;
7703     next = next->next;
7704   }
7705   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7706   depth = stratumValue;
7707   if ((depth < 0) || (depth >= next->numStrata)) {
7708     if (start) *start = 0;
7709     if (end)   *end   = 0;
7710   } else {
7711     if (start) *start = next->points[next->stratumOffsets[depth]];
7712     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7713   }
7714   PetscFunctionReturn(0);
7715 }
7716 
7717 #undef __FUNCT__
7718 #define __FUNCT__ "DMPlexGetHeightStratum"
7719 /*@
7720   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7721 
7722   Not Collective
7723 
7724   Input Parameters:
7725 + dm           - The DMPlex object
7726 - stratumValue - The requested height
7727 
7728   Output Parameters:
7729 + start - The first point at this height
7730 - end   - One beyond the last point at this height
7731 
7732   Level: developer
7733 
7734 .keywords: mesh, points
7735 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7736 @*/
7737 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7738 {
7739   DM_Plex       *mesh = (DM_Plex*) dm->data;
7740   DMLabel        next  = mesh->labels;
7741   PetscBool      flg   = PETSC_FALSE;
7742   PetscInt       depth;
7743   PetscErrorCode ierr;
7744 
7745   PetscFunctionBegin;
7746   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7747   if (stratumValue < 0) {
7748     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7749   } else {
7750     PetscInt pStart, pEnd;
7751 
7752     if (start) *start = 0;
7753     if (end)   *end   = 0;
7754     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7755     if (pStart == pEnd) PetscFunctionReturn(0);
7756   }
7757   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7758   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7759   /* We should have a generic GetLabel() and a Label class */
7760   while (next) {
7761     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7762     if (flg) break;
7763     next = next->next;
7764   }
7765   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7766   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7767   if ((depth < 0) || (depth >= next->numStrata)) {
7768     if (start) *start = 0;
7769     if (end)   *end   = 0;
7770   } else {
7771     if (start) *start = next->points[next->stratumOffsets[depth]];
7772     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7773   }
7774   PetscFunctionReturn(0);
7775 }
7776 
7777 #undef __FUNCT__
7778 #define __FUNCT__ "DMPlexCreateSectionInitial"
7779 /* Set the number of dof on each point and separate by fields */
7780 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7781 {
7782   PetscInt      *numDofTot;
7783   PetscInt       pStart = 0, pEnd = 0;
7784   PetscInt       p, d, f;
7785   PetscErrorCode ierr;
7786 
7787   PetscFunctionBegin;
7788   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7789   for (d = 0; d <= dim; ++d) {
7790     numDofTot[d] = 0;
7791     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7792   }
7793   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7794   if (numFields > 0) {
7795     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7796     if (numComp) {
7797       for (f = 0; f < numFields; ++f) {
7798         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7799       }
7800     }
7801   }
7802   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7803   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7804   for (d = 0; d <= dim; ++d) {
7805     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7806     for (p = pStart; p < pEnd; ++p) {
7807       for (f = 0; f < numFields; ++f) {
7808         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7809       }
7810       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7811     }
7812   }
7813   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7814   PetscFunctionReturn(0);
7815 }
7816 
7817 #undef __FUNCT__
7818 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7819 /* Set the number of dof on each point and separate by fields
7820    If constDof is PETSC_DETERMINE, constrain every dof on the point
7821 */
7822 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7823 {
7824   PetscInt       numFields;
7825   PetscInt       bc;
7826   PetscErrorCode ierr;
7827 
7828   PetscFunctionBegin;
7829   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7830   for (bc = 0; bc < numBC; ++bc) {
7831     PetscInt        field = 0;
7832     const PetscInt *idx;
7833     PetscInt        n, i;
7834 
7835     if (numFields) field = bcField[bc];
7836     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7837     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7838     for (i = 0; i < n; ++i) {
7839       const PetscInt p        = idx[i];
7840       PetscInt       numConst = constDof;
7841 
7842       /* Constrain every dof on the point */
7843       if (numConst < 0) {
7844         if (numFields) {
7845           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7846         } else {
7847           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7848         }
7849       }
7850       if (numFields) {
7851         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7852       }
7853       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7854     }
7855     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7856   }
7857   PetscFunctionReturn(0);
7858 }
7859 
7860 #undef __FUNCT__
7861 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7862 /* Set the constrained indices on each point and separate by fields */
7863 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7864 {
7865   PetscInt      *maxConstraints;
7866   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7867   PetscErrorCode ierr;
7868 
7869   PetscFunctionBegin;
7870   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7871   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7872   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7873   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7874   for (p = pStart; p < pEnd; ++p) {
7875     PetscInt cdof;
7876 
7877     if (numFields) {
7878       for (f = 0; f < numFields; ++f) {
7879         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7880         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7881       }
7882     } else {
7883       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7884       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7885     }
7886   }
7887   for (f = 0; f < numFields; ++f) {
7888     maxConstraints[numFields] += maxConstraints[f];
7889   }
7890   if (maxConstraints[numFields]) {
7891     PetscInt *indices;
7892 
7893     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7894     for (p = pStart; p < pEnd; ++p) {
7895       PetscInt cdof, d;
7896 
7897       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7898       if (cdof) {
7899         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7900         if (numFields) {
7901           PetscInt numConst = 0, foff = 0;
7902 
7903           for (f = 0; f < numFields; ++f) {
7904             PetscInt cfdof, fdof;
7905 
7906             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7907             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7908             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7909             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7910             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7911             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7912             numConst += cfdof;
7913             foff     += fdof;
7914           }
7915           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7916         } else {
7917           for (d = 0; d < cdof; ++d) indices[d] = d;
7918         }
7919         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7920       }
7921     }
7922     ierr = PetscFree(indices);CHKERRQ(ierr);
7923   }
7924   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7925   PetscFunctionReturn(0);
7926 }
7927 
7928 #undef __FUNCT__
7929 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7930 /* Set the constrained field indices on each point */
7931 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7932 {
7933   const PetscInt *points, *indices;
7934   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7935   PetscErrorCode  ierr;
7936 
7937   PetscFunctionBegin;
7938   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7939   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7940 
7941   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7942   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7943   if (!constraintIndices) {
7944     PetscInt *idx, i;
7945 
7946     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7947     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7948     for (i = 0; i < maxDof; ++i) idx[i] = i;
7949     for (p = 0; p < numPoints; ++p) {
7950       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7951     }
7952     ierr = PetscFree(idx);CHKERRQ(ierr);
7953   } else {
7954     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7955     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7956     for (p = 0; p < numPoints; ++p) {
7957       PetscInt fcdof;
7958 
7959       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7960       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);
7961       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7962     }
7963     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7964   }
7965   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7966   PetscFunctionReturn(0);
7967 }
7968 
7969 #undef __FUNCT__
7970 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7971 /* Set the constrained indices on each point and separate by fields */
7972 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7973 {
7974   PetscInt      *indices;
7975   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7976   PetscErrorCode ierr;
7977 
7978   PetscFunctionBegin;
7979   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7980   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7981   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7982   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7983   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7984   for (p = pStart; p < pEnd; ++p) {
7985     PetscInt cdof, d;
7986 
7987     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7988     if (cdof) {
7989       PetscInt numConst = 0, foff = 0;
7990 
7991       for (f = 0; f < numFields; ++f) {
7992         const PetscInt *fcind;
7993         PetscInt        fdof, fcdof;
7994 
7995         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7996         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7997         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7998         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7999         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
8000         foff     += fdof;
8001         numConst += fcdof;
8002       }
8003       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8004       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8005     }
8006   }
8007   ierr = PetscFree(indices);CHKERRQ(ierr);
8008   PetscFunctionReturn(0);
8009 }
8010 
8011 #undef __FUNCT__
8012 #define __FUNCT__ "DMPlexCreateSection"
8013 /*@C
8014   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8015 
8016   Not Collective
8017 
8018   Input Parameters:
8019 + dm        - The DMPlex object
8020 . dim       - The spatial dimension of the problem
8021 . numFields - The number of fields in the problem
8022 . numComp   - An array of size numFields that holds the number of components for each field
8023 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8024 . numBC     - The number of boundary conditions
8025 . bcField   - An array of size numBC giving the field number for each boundry condition
8026 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8027 
8028   Output Parameter:
8029 . section - The PetscSection object
8030 
8031   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
8032   nubmer of dof for field 0 on each edge.
8033 
8034   Level: developer
8035 
8036 .keywords: mesh, elements
8037 .seealso: DMPlexCreate(), PetscSectionCreate()
8038 @*/
8039 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8040 {
8041   PetscErrorCode ierr;
8042 
8043   PetscFunctionBegin;
8044   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8045   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8046   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8047   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8048   {
8049     PetscBool view = PETSC_FALSE;
8050 
8051     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8052     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8053   }
8054   PetscFunctionReturn(0);
8055 }
8056 
8057 #undef __FUNCT__
8058 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8059 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8060 {
8061   PetscSection   section;
8062   PetscErrorCode ierr;
8063 
8064   PetscFunctionBegin;
8065   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8066   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8067   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8068   PetscFunctionReturn(0);
8069 }
8070 
8071 #undef __FUNCT__
8072 #define __FUNCT__ "DMPlexGetCoordinateSection"
8073 /*@
8074   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8075 
8076   Not Collective
8077 
8078   Input Parameter:
8079 . dm - The DMPlex object
8080 
8081   Output Parameter:
8082 . section - The PetscSection object
8083 
8084   Level: intermediate
8085 
8086 .keywords: mesh, coordinates
8087 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8088 @*/
8089 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8090 {
8091   DM             cdm;
8092   PetscErrorCode ierr;
8093 
8094   PetscFunctionBegin;
8095   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8096   PetscValidPointer(section, 2);
8097   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8098   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8099   PetscFunctionReturn(0);
8100 }
8101 
8102 #undef __FUNCT__
8103 #define __FUNCT__ "DMPlexSetCoordinateSection"
8104 /*@
8105   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8106 
8107   Not Collective
8108 
8109   Input Parameters:
8110 + dm      - The DMPlex object
8111 - section - The PetscSection object
8112 
8113   Level: intermediate
8114 
8115 .keywords: mesh, coordinates
8116 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8117 @*/
8118 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8119 {
8120   DM             cdm;
8121   PetscErrorCode ierr;
8122 
8123   PetscFunctionBegin;
8124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8125   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8126   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8127   PetscFunctionReturn(0);
8128 }
8129 
8130 #undef __FUNCT__
8131 #define __FUNCT__ "DMPlexGetConeSection"
8132 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8133 {
8134   DM_Plex *mesh = (DM_Plex*) dm->data;
8135 
8136   PetscFunctionBegin;
8137   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8138   if (section) *section = mesh->coneSection;
8139   PetscFunctionReturn(0);
8140 }
8141 
8142 #undef __FUNCT__
8143 #define __FUNCT__ "DMPlexGetCones"
8144 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8145 {
8146   DM_Plex *mesh = (DM_Plex*) dm->data;
8147 
8148   PetscFunctionBegin;
8149   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8150   if (cones) *cones = mesh->cones;
8151   PetscFunctionReturn(0);
8152 }
8153 
8154 #undef __FUNCT__
8155 #define __FUNCT__ "DMPlexGetConeOrientations"
8156 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8157 {
8158   DM_Plex *mesh = (DM_Plex*) dm->data;
8159 
8160   PetscFunctionBegin;
8161   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8162   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8163   PetscFunctionReturn(0);
8164 }
8165 
8166 #undef __FUNCT__
8167 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8168 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8169 {
8170   const PetscInt embedDim = 2;
8171   PetscReal      x        = PetscRealPart(point[0]);
8172   PetscReal      y        = PetscRealPart(point[1]);
8173   PetscReal      v0[2], J[4], invJ[4], detJ;
8174   PetscReal      xi, eta;
8175   PetscErrorCode ierr;
8176 
8177   PetscFunctionBegin;
8178   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8179   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8180   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8181 
8182   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8183   else *cell = -1;
8184   PetscFunctionReturn(0);
8185 }
8186 
8187 #undef __FUNCT__
8188 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8189 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8190 {
8191   PetscSection       coordSection;
8192   Vec                coordsLocal;
8193   const PetscScalar *coords;
8194   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8195   PetscReal          x         = PetscRealPart(point[0]);
8196   PetscReal          y         = PetscRealPart(point[1]);
8197   PetscInt           crossings = 0, f;
8198   PetscErrorCode     ierr;
8199 
8200   PetscFunctionBegin;
8201   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8202   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8203   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8204   for (f = 0; f < 4; ++f) {
8205     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8206     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8207     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8208     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8209     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8210     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8211     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8212     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8213     if ((cond1 || cond2)  && above) ++crossings;
8214   }
8215   if (crossings % 2) *cell = c;
8216   else *cell = -1;
8217   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8218   PetscFunctionReturn(0);
8219 }
8220 
8221 #undef __FUNCT__
8222 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8223 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8224 {
8225   const PetscInt embedDim = 3;
8226   PetscReal      v0[3], J[9], invJ[9], detJ;
8227   PetscReal      x = PetscRealPart(point[0]);
8228   PetscReal      y = PetscRealPart(point[1]);
8229   PetscReal      z = PetscRealPart(point[2]);
8230   PetscReal      xi, eta, zeta;
8231   PetscErrorCode ierr;
8232 
8233   PetscFunctionBegin;
8234   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8235   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8236   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8237   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8238 
8239   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8240   else *cell = -1;
8241   PetscFunctionReturn(0);
8242 }
8243 
8244 #undef __FUNCT__
8245 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8246 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8247 {
8248   PetscSection       coordSection;
8249   Vec                coordsLocal;
8250   const PetscScalar *coords;
8251   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8252                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8253   PetscBool          found = PETSC_TRUE;
8254   PetscInt           f;
8255   PetscErrorCode     ierr;
8256 
8257   PetscFunctionBegin;
8258   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8259   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8260   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8261   for (f = 0; f < 6; ++f) {
8262     /* Check the point is under plane */
8263     /*   Get face normal */
8264     PetscReal v_i[3];
8265     PetscReal v_j[3];
8266     PetscReal normal[3];
8267     PetscReal pp[3];
8268     PetscReal dot;
8269 
8270     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8271     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8272     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8273     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8274     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8275     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8276     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8277     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8278     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8279     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8280     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8281     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8282     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8283 
8284     /* Check that projected point is in face (2D location problem) */
8285     if (dot < 0.0) {
8286       found = PETSC_FALSE;
8287       break;
8288     }
8289   }
8290   if (found) *cell = c;
8291   else *cell = -1;
8292   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8293   PetscFunctionReturn(0);
8294 }
8295 
8296 #undef __FUNCT__
8297 #define __FUNCT__ "DMLocatePoints_Plex"
8298 /*
8299  Need to implement using the guess
8300 */
8301 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8302 {
8303   PetscInt       cell = -1 /*, guess = -1*/;
8304   PetscInt       bs, numPoints, p;
8305   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8306   PetscInt      *cells;
8307   PetscScalar   *a;
8308   PetscErrorCode ierr;
8309 
8310   PetscFunctionBegin;
8311   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8312   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8313   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8314   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8315   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8316   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8317   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8318   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);
8319   numPoints /= bs;
8320   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8321   for (p = 0; p < numPoints; ++p) {
8322     const PetscScalar *point = &a[p*bs];
8323 
8324     switch (dim) {
8325     case 2:
8326       for (c = cStart; c < cEnd; ++c) {
8327         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8328         switch (coneSize) {
8329         case 3:
8330           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8331           break;
8332         case 4:
8333           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8334           break;
8335         default:
8336           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8337         }
8338         if (cell >= 0) break;
8339       }
8340       break;
8341     case 3:
8342       for (c = cStart; c < cEnd; ++c) {
8343         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8344         switch (coneSize) {
8345         case 4:
8346           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8347           break;
8348         case 8:
8349           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8350           break;
8351         default:
8352           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8353         }
8354         if (cell >= 0) break;
8355       }
8356       break;
8357     default:
8358       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8359     }
8360     cells[p] = cell;
8361   }
8362   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8363   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8364   PetscFunctionReturn(0);
8365 }
8366 
8367 /******************************** FEM Support **********************************/
8368 
8369 #undef __FUNCT__
8370 #define __FUNCT__ "DMPlexVecGetClosure"
8371 /*@C
8372   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8373 
8374   Not collective
8375 
8376   Input Parameters:
8377 + dm - The DM
8378 . section - The section describing the layout in v, or NULL to use the default section
8379 . v - The local vector
8380 - point - The sieve point in the DM
8381 
8382   Output Parameters:
8383 + csize - The number of values in the closure, or NULL
8384 - values - The array of values, which is a borrowed array and should not be freed
8385 
8386   Level: intermediate
8387 
8388 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8389 @*/
8390 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8391 {
8392   PetscScalar   *array, *vArray;
8393   PetscInt      *points = NULL;
8394   PetscInt       offsets[32];
8395   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8396   PetscErrorCode ierr;
8397 
8398   PetscFunctionBegin;
8399   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8400   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8401   if (!section) {
8402     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8403   }
8404   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8405   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8406   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8407   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8408   /* Compress out points not in the section */
8409   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8410   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8411     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8412       points[q*2]   = points[p];
8413       points[q*2+1] = points[p+1];
8414       ++q;
8415     }
8416   }
8417   numPoints = q;
8418   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8419     PetscInt dof, fdof;
8420 
8421     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8422     for (f = 0; f < numFields; ++f) {
8423       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8424       offsets[f+1] += fdof;
8425     }
8426     size += dof;
8427   }
8428   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8429   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8430   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8431   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8432   for (p = 0; p < numPoints*2; p += 2) {
8433     PetscInt     o = points[p+1];
8434     PetscInt     dof, off, d;
8435     PetscScalar *varr;
8436 
8437     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8438     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8439     varr = &vArray[off];
8440     if (numFields) {
8441       PetscInt fdof, foff, fcomp, f, c;
8442 
8443       for (f = 0, foff = 0; f < numFields; ++f) {
8444         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8445         if (o >= 0) {
8446           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8447             array[offsets[f]] = varr[foff+d];
8448           }
8449         } else {
8450           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8451           for (d = fdof/fcomp-1; d >= 0; --d) {
8452             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8453               array[offsets[f]] = varr[foff+d*fcomp+c];
8454             }
8455           }
8456         }
8457         foff += fdof;
8458       }
8459     } else {
8460       if (o >= 0) {
8461         for (d = 0; d < dof; ++d, ++offsets[0]) {
8462           array[offsets[0]] = varr[d];
8463         }
8464       } else {
8465         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8466           array[offsets[0]] = varr[d];
8467         }
8468       }
8469     }
8470   }
8471   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8472   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8473   if (csize) *csize = size;
8474   *values = array;
8475   PetscFunctionReturn(0);
8476 }
8477 
8478 #undef __FUNCT__
8479 #define __FUNCT__ "DMPlexVecRestoreClosure"
8480 /*@C
8481   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8482 
8483   Not collective
8484 
8485   Input Parameters:
8486 + dm - The DM
8487 . section - The section describing the layout in v, or NULL to use the default section
8488 . v - The local vector
8489 . point - The sieve point in the DM
8490 . csize - The number of values in the closure, or NULL
8491 - values - The array of values, which is a borrowed array and should not be freed
8492 
8493   Level: intermediate
8494 
8495 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8496 @*/
8497 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8498 {
8499   PetscInt       size = 0;
8500   PetscErrorCode ierr;
8501 
8502   PetscFunctionBegin;
8503   /* Should work without recalculating size */
8504   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8505   PetscFunctionReturn(0);
8506 }
8507 
8508 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8509 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8510 
8511 #undef __FUNCT__
8512 #define __FUNCT__ "updatePoint_private"
8513 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8514 {
8515   PetscInt        cdof;   /* The number of constraints on this point */
8516   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8517   PetscScalar    *a;
8518   PetscInt        off, cind = 0, k;
8519   PetscErrorCode  ierr;
8520 
8521   PetscFunctionBegin;
8522   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8523   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8524   a    = &array[off];
8525   if (!cdof || setBC) {
8526     if (orientation >= 0) {
8527       for (k = 0; k < dof; ++k) {
8528         fuse(&a[k], values[k]);
8529       }
8530     } else {
8531       for (k = 0; k < dof; ++k) {
8532         fuse(&a[k], values[dof-k-1]);
8533       }
8534     }
8535   } else {
8536     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8537     if (orientation >= 0) {
8538       for (k = 0; k < dof; ++k) {
8539         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8540         fuse(&a[k], values[k]);
8541       }
8542     } else {
8543       for (k = 0; k < dof; ++k) {
8544         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8545         fuse(&a[k], values[dof-k-1]);
8546       }
8547     }
8548   }
8549   PetscFunctionReturn(0);
8550 }
8551 
8552 #undef __FUNCT__
8553 #define __FUNCT__ "updatePointFields_private"
8554 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8555 {
8556   PetscScalar   *a;
8557   PetscInt       numFields, off, foff, f;
8558   PetscErrorCode ierr;
8559 
8560   PetscFunctionBegin;
8561   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8562   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8563   a    = &array[off];
8564   for (f = 0, foff = 0; f < numFields; ++f) {
8565     PetscInt        fdof, fcomp, fcdof;
8566     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8567     PetscInt        cind = 0, k, c;
8568 
8569     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8570     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8571     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8572     if (!fcdof || setBC) {
8573       if (orientation >= 0) {
8574         for (k = 0; k < fdof; ++k) {
8575           fuse(&a[foff+k], values[foffs[f]+k]);
8576         }
8577       } else {
8578         for (k = fdof/fcomp-1; k >= 0; --k) {
8579           for (c = 0; c < fcomp; ++c) {
8580             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8581           }
8582         }
8583       }
8584     } else {
8585       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8586       if (orientation >= 0) {
8587         for (k = 0; k < fdof; ++k) {
8588           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8589           fuse(&a[foff+k], values[foffs[f]+k]);
8590         }
8591       } else {
8592         for (k = fdof/fcomp-1; k >= 0; --k) {
8593           for (c = 0; c < fcomp; ++c) {
8594             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8595             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8596           }
8597         }
8598       }
8599     }
8600     foff     += fdof;
8601     foffs[f] += fdof;
8602   }
8603   PetscFunctionReturn(0);
8604 }
8605 
8606 #undef __FUNCT__
8607 #define __FUNCT__ "DMPlexVecSetClosure"
8608 /*@C
8609   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8610 
8611   Not collective
8612 
8613   Input Parameters:
8614 + dm - The DM
8615 . section - The section describing the layout in v, or NULL to use the default sectionw
8616 . v - The local vector
8617 . point - The sieve point in the DM
8618 . values - The array of values, which is a borrowed array and should not be freed
8619 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8620 
8621   Level: intermediate
8622 
8623 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8624 @*/
8625 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8626 {
8627   PetscScalar   *array;
8628   PetscInt      *points = NULL;
8629   PetscInt       offsets[32];
8630   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8631   PetscErrorCode ierr;
8632 
8633   PetscFunctionBegin;
8634   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8635   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8636   if (!section) {
8637     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8638   }
8639   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8640   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8641   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8642   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8643   /* Compress out points not in the section */
8644   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8645   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8646     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8647       points[q*2]   = points[p];
8648       points[q*2+1] = points[p+1];
8649       ++q;
8650     }
8651   }
8652   numPoints = q;
8653   for (p = 0; p < numPoints*2; p += 2) {
8654     PetscInt fdof;
8655 
8656     for (f = 0; f < numFields; ++f) {
8657       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8658       offsets[f+1] += fdof;
8659     }
8660   }
8661   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8662   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8663   if (numFields) {
8664     switch (mode) {
8665     case INSERT_VALUES:
8666       for (p = 0; p < numPoints*2; p += 2) {
8667         PetscInt o = points[p+1];
8668         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8669       } break;
8670     case INSERT_ALL_VALUES:
8671       for (p = 0; p < numPoints*2; p += 2) {
8672         PetscInt o = points[p+1];
8673         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8674       } break;
8675     case ADD_VALUES:
8676       for (p = 0; p < numPoints*2; p += 2) {
8677         PetscInt o = points[p+1];
8678         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8679       } break;
8680     case ADD_ALL_VALUES:
8681       for (p = 0; p < numPoints*2; p += 2) {
8682         PetscInt o = points[p+1];
8683         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8684       } break;
8685     default:
8686       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8687     }
8688   } else {
8689     switch (mode) {
8690     case INSERT_VALUES:
8691       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8692         PetscInt o = points[p+1];
8693         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8694         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8695       } break;
8696     case INSERT_ALL_VALUES:
8697       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8698         PetscInt o = points[p+1];
8699         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8700         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8701       } break;
8702     case ADD_VALUES:
8703       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8704         PetscInt o = points[p+1];
8705         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8706         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8707       } break;
8708     case ADD_ALL_VALUES:
8709       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8710         PetscInt o = points[p+1];
8711         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8712         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8713       } break;
8714     default:
8715       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8716     }
8717   }
8718   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8719   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8720   PetscFunctionReturn(0);
8721 }
8722 
8723 #undef __FUNCT__
8724 #define __FUNCT__ "DMPlexPrintMatSetValues"
8725 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8726 {
8727   PetscMPIInt    rank;
8728   PetscInt       i, j;
8729   PetscErrorCode ierr;
8730 
8731   PetscFunctionBegin;
8732   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8733   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8734   for (i = 0; i < numIndices; i++) {
8735     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8736   }
8737   for (i = 0; i < numIndices; i++) {
8738     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8739     for (j = 0; j < numIndices; j++) {
8740 #if defined(PETSC_USE_COMPLEX)
8741       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8742 #else
8743       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8744 #endif
8745     }
8746     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8747   }
8748   PetscFunctionReturn(0);
8749 }
8750 
8751 #undef __FUNCT__
8752 #define __FUNCT__ "indicesPoint_private"
8753 /* . off - The global offset of this point */
8754 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8755 {
8756   PetscInt        dof;    /* The number of unknowns on this point */
8757   PetscInt        cdof;   /* The number of constraints on this point */
8758   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8759   PetscInt        cind = 0, k;
8760   PetscErrorCode  ierr;
8761 
8762   PetscFunctionBegin;
8763   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8764   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8765   if (!cdof || setBC) {
8766     if (orientation >= 0) {
8767       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8768     } else {
8769       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8770     }
8771   } else {
8772     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8773     if (orientation >= 0) {
8774       for (k = 0; k < dof; ++k) {
8775         if ((cind < cdof) && (k == cdofs[cind])) {
8776           /* Insert check for returning constrained indices */
8777           indices[*loff+k] = -(off+k+1);
8778           ++cind;
8779         } else {
8780           indices[*loff+k] = off+k-cind;
8781         }
8782       }
8783     } else {
8784       for (k = 0; k < dof; ++k) {
8785         if ((cind < cdof) && (k == cdofs[cind])) {
8786           /* Insert check for returning constrained indices */
8787           indices[*loff+dof-k-1] = -(off+k+1);
8788           ++cind;
8789         } else {
8790           indices[*loff+dof-k-1] = off+k-cind;
8791         }
8792       }
8793     }
8794   }
8795   *loff += dof;
8796   PetscFunctionReturn(0);
8797 }
8798 
8799 #undef __FUNCT__
8800 #define __FUNCT__ "indicesPointFields_private"
8801 /* . off - The global offset of this point */
8802 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8803 {
8804   PetscInt       numFields, foff, f;
8805   PetscErrorCode ierr;
8806 
8807   PetscFunctionBegin;
8808   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8809   for (f = 0, foff = 0; f < numFields; ++f) {
8810     PetscInt        fdof, fcomp, cfdof;
8811     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8812     PetscInt        cind = 0, k, c;
8813 
8814     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8815     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8816     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8817     if (!cfdof || setBC) {
8818       if (orientation >= 0) {
8819         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8820       } else {
8821         for (k = fdof/fcomp-1; k >= 0; --k) {
8822           for (c = 0; c < fcomp; ++c) {
8823             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8824           }
8825         }
8826       }
8827     } else {
8828       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8829       if (orientation >= 0) {
8830         for (k = 0; k < fdof; ++k) {
8831           if ((cind < cfdof) && (k == fcdofs[cind])) {
8832             indices[foffs[f]+k] = -(off+foff+k+1);
8833             ++cind;
8834           } else {
8835             indices[foffs[f]+k] = off+foff+k-cind;
8836           }
8837         }
8838       } else {
8839         for (k = fdof/fcomp-1; k >= 0; --k) {
8840           for (c = 0; c < fcomp; ++c) {
8841             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8842               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8843               ++cind;
8844             } else {
8845               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8846             }
8847           }
8848         }
8849       }
8850     }
8851     foff     += fdof - cfdof;
8852     foffs[f] += fdof;
8853   }
8854   PetscFunctionReturn(0);
8855 }
8856 
8857 #undef __FUNCT__
8858 #define __FUNCT__ "DMPlexMatSetClosure"
8859 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8860 {
8861   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8862   PetscInt      *points = NULL;
8863   PetscInt      *indices;
8864   PetscInt       offsets[32];
8865   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8866   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8867   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8868   PetscErrorCode ierr;
8869 
8870   PetscFunctionBegin;
8871   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8872   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8873   if (useDefault) {
8874     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8875   }
8876   if (useGlobalDefault) {
8877     if (useDefault) {
8878       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8879     } else {
8880       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8881     }
8882   }
8883   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8884   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8885   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8886   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8887   /* Compress out points not in the section */
8888   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8889   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8890     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8891       points[q*2]   = points[p];
8892       points[q*2+1] = points[p+1];
8893       ++q;
8894     }
8895   }
8896   numPoints = q;
8897   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8898     PetscInt fdof;
8899 
8900     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8901     for (f = 0; f < numFields; ++f) {
8902       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8903       offsets[f+1] += fdof;
8904     }
8905     numIndices += dof;
8906   }
8907   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8908 
8909   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8910   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8911   if (numFields) {
8912     for (p = 0; p < numPoints*2; p += 2) {
8913       PetscInt o = points[p+1];
8914       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8915       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8916     }
8917   } else {
8918     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8919       PetscInt o = points[p+1];
8920       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8921       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8922     }
8923   }
8924   if (useGlobalDefault && !useDefault) {
8925     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8926   }
8927   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8928   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8929   if (ierr) {
8930     PetscMPIInt    rank;
8931     PetscErrorCode ierr2;
8932 
8933     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8934     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8935     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8936     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8937     CHKERRQ(ierr);
8938   }
8939   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8940   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8941   PetscFunctionReturn(0);
8942 }
8943 
8944 #undef __FUNCT__
8945 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8946 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8947 {
8948   PetscSection       coordSection;
8949   Vec                coordinates;
8950   const PetscScalar *coords;
8951   const PetscInt     dim = 2;
8952   PetscInt           d, f;
8953   PetscErrorCode     ierr;
8954 
8955   PetscFunctionBegin;
8956   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8957   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8958   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8959   if (v0) {
8960     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8961   }
8962   if (J) {
8963     for (d = 0; d < dim; d++) {
8964       for (f = 0; f < dim; f++) {
8965         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8966       }
8967     }
8968     *detJ = J[0]*J[3] - J[1]*J[2];
8969 #if 0
8970     if (detJ < 0.0) {
8971       const PetscReal xLength = mesh->periodicity[0];
8972 
8973       if (xLength != 0.0) {
8974         PetscReal v0x = coords[0*dim+0];
8975 
8976         if (v0x == 0.0) v0x = v0[0] = xLength;
8977         for (f = 0; f < dim; f++) {
8978           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8979 
8980           J[0*dim+f] = 0.5*(px - v0x);
8981         }
8982       }
8983       detJ = J[0]*J[3] - J[1]*J[2];
8984     }
8985 #endif
8986     PetscLogFlops(8.0 + 3.0);
8987   }
8988   if (invJ) {
8989     const PetscReal invDet = 1.0/(*detJ);
8990 
8991     invJ[0] =  invDet*J[3];
8992     invJ[1] = -invDet*J[1];
8993     invJ[2] = -invDet*J[2];
8994     invJ[3] =  invDet*J[0];
8995     PetscLogFlops(5.0);
8996   }
8997   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8998   PetscFunctionReturn(0);
8999 }
9000 
9001 #undef __FUNCT__
9002 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9003 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9004 {
9005   PetscSection       coordSection;
9006   Vec                coordinates;
9007   const PetscScalar *coords;
9008   const PetscInt     dim = 2;
9009   PetscInt           d, f;
9010   PetscErrorCode     ierr;
9011 
9012   PetscFunctionBegin;
9013   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9014   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9015   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9016   if (v0) {
9017     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9018   }
9019   if (J) {
9020     for (d = 0; d < dim; d++) {
9021       for (f = 0; f < dim; f++) {
9022         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9023       }
9024     }
9025     *detJ = J[0]*J[3] - J[1]*J[2];
9026     PetscLogFlops(8.0 + 3.0);
9027   }
9028   if (invJ) {
9029     const PetscReal invDet = 1.0/(*detJ);
9030 
9031     invJ[0] =  invDet*J[3];
9032     invJ[1] = -invDet*J[1];
9033     invJ[2] = -invDet*J[2];
9034     invJ[3] =  invDet*J[0];
9035     PetscLogFlops(5.0);
9036   }
9037   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9038   PetscFunctionReturn(0);
9039 }
9040 
9041 #undef __FUNCT__
9042 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9043 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9044 {
9045   PetscSection       coordSection;
9046   Vec                coordinates;
9047   const PetscScalar *coords;
9048   const PetscInt     dim = 3;
9049   PetscInt           d, f;
9050   PetscErrorCode     ierr;
9051 
9052   PetscFunctionBegin;
9053   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9054   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9055   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9056   if (v0) {
9057     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9058   }
9059   if (J) {
9060     for (d = 0; d < dim; d++) {
9061       for (f = 0; f < dim; f++) {
9062         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9063       }
9064     }
9065     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9066     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9067              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9068              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9069     PetscLogFlops(18.0 + 12.0);
9070   }
9071   if (invJ) {
9072     const PetscReal invDet = 1.0/(*detJ);
9073 
9074     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9075     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9076     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9077     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9078     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9079     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9080     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9081     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9082     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9083     PetscLogFlops(37.0);
9084   }
9085   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9086   PetscFunctionReturn(0);
9087 }
9088 
9089 #undef __FUNCT__
9090 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9091 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9092 {
9093   PetscSection       coordSection;
9094   Vec                coordinates;
9095   const PetscScalar *coords;
9096   const PetscInt     dim = 3;
9097   PetscInt           d;
9098   PetscErrorCode     ierr;
9099 
9100   PetscFunctionBegin;
9101   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9102   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9103   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9104   if (v0) {
9105     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9106   }
9107   if (J) {
9108     for (d = 0; d < dim; d++) {
9109       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9110       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9111       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9112     }
9113     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9114              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9115              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9116     PetscLogFlops(18.0 + 12.0);
9117   }
9118   if (invJ) {
9119     const PetscReal invDet = -1.0/(*detJ);
9120 
9121     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9122     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9123     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9124     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9125     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9126     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9127     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9128     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9129     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9130     PetscLogFlops(37.0);
9131   }
9132   *detJ *= 8.0;
9133   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9134   PetscFunctionReturn(0);
9135 }
9136 
9137 #undef __FUNCT__
9138 #define __FUNCT__ "DMPlexComputeCellGeometry"
9139 /*@C
9140   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9141 
9142   Collective on DM
9143 
9144   Input Arguments:
9145 + dm   - the DM
9146 - cell - the cell
9147 
9148   Output Arguments:
9149 + v0   - the translation part of this affine transform
9150 . J    - the Jacobian of the transform to the reference element
9151 . invJ - the inverse of the Jacobian
9152 - detJ - the Jacobian determinant
9153 
9154   Level: advanced
9155 
9156 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9157 @*/
9158 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9159 {
9160   PetscInt       dim, coneSize;
9161   PetscErrorCode ierr;
9162 
9163   PetscFunctionBegin;
9164   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9165   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9166   switch (dim) {
9167   case 2:
9168     switch (coneSize) {
9169     case 3:
9170       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9171       break;
9172     case 4:
9173       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9174       break;
9175     default:
9176       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9177     }
9178     break;
9179   case 3:
9180     switch (coneSize) {
9181     case 4:
9182       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9183       break;
9184     case 8:
9185       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9186       break;
9187     default:
9188       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9189     }
9190     break;
9191   default:
9192     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9193   }
9194   PetscFunctionReturn(0);
9195 }
9196 
9197 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9198 {
9199   switch (i) {
9200   case 0:
9201     switch (j) {
9202     case 0: return 0;
9203     case 1:
9204       switch (k) {
9205       case 0: return 0;
9206       case 1: return 0;
9207       case 2: return 1;
9208       }
9209     case 2:
9210       switch (k) {
9211       case 0: return 0;
9212       case 1: return -1;
9213       case 2: return 0;
9214       }
9215     }
9216   case 1:
9217     switch (j) {
9218     case 0:
9219       switch (k) {
9220       case 0: return 0;
9221       case 1: return 0;
9222       case 2: return -1;
9223       }
9224     case 1: return 0;
9225     case 2:
9226       switch (k) {
9227       case 0: return 1;
9228       case 1: return 0;
9229       case 2: return 0;
9230       }
9231     }
9232   case 2:
9233     switch (j) {
9234     case 0:
9235       switch (k) {
9236       case 0: return 0;
9237       case 1: return 1;
9238       case 2: return 0;
9239       }
9240     case 1:
9241       switch (k) {
9242       case 0: return -1;
9243       case 1: return 0;
9244       case 2: return 0;
9245       }
9246     case 2: return 0;
9247     }
9248   }
9249   return 0;
9250 }
9251 
9252 #undef __FUNCT__
9253 #define __FUNCT__ "DMPlexCreateRigidBody"
9254 /*@C
9255   DMPlexCreateRigidBody - create rigid body modes from coordinates
9256 
9257   Collective on DM
9258 
9259   Input Arguments:
9260 + dm - the DM
9261 . section - the local section associated with the rigid field, or NULL for the default section
9262 - globalSection - the global section associated with the rigid field, or NULL for the default section
9263 
9264   Output Argument:
9265 . sp - the null space
9266 
9267   Note: This is necessary to take account of Dirichlet conditions on the displacements
9268 
9269   Level: advanced
9270 
9271 .seealso: MatNullSpaceCreate()
9272 @*/
9273 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9274 {
9275   MPI_Comm       comm = ((PetscObject) dm)->comm;
9276   Vec            coordinates, localMode, mode[6];
9277   PetscSection   coordSection;
9278   PetscScalar   *coords;
9279   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9280   PetscErrorCode ierr;
9281 
9282   PetscFunctionBegin;
9283   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9284   if (dim == 1) {
9285     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
9286     PetscFunctionReturn(0);
9287   }
9288   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9289   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9290   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9291   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9292   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9293   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9294   m    = (dim*(dim+1))/2;
9295   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9296   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9297   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9298   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9299   /* Assume P1 */
9300   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9301   for (d = 0; d < dim; ++d) {
9302     PetscScalar values[3] = {0.0, 0.0, 0.0};
9303 
9304     values[d] = 1.0;
9305     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9306     for (v = vStart; v < vEnd; ++v) {
9307       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9308     }
9309     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9310     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9311   }
9312   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9313   for (d = dim; d < dim*(dim+1)/2; ++d) {
9314     PetscInt i, j, k = dim > 2 ? d - dim : d;
9315 
9316     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9317     for (v = vStart; v < vEnd; ++v) {
9318       PetscScalar values[3] = {0.0, 0.0, 0.0};
9319       PetscInt    off;
9320 
9321       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9322       for (i = 0; i < dim; ++i) {
9323         for (j = 0; j < dim; ++j) {
9324           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9325         }
9326       }
9327       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9328     }
9329     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9330     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9331   }
9332   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9333   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9334   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
9335   /* Orthonormalize system */
9336   for (i = dim; i < m; ++i) {
9337     PetscScalar dots[6];
9338 
9339     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9340     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9341     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9342     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
9343   }
9344   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9345   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9346   PetscFunctionReturn(0);
9347 }
9348 
9349 #undef __FUNCT__
9350 #define __FUNCT__ "DMPlexGetHybridBounds"
9351 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9352 {
9353   DM_Plex       *mesh = (DM_Plex*) dm->data;
9354   PetscInt       dim;
9355   PetscErrorCode ierr;
9356 
9357   PetscFunctionBegin;
9358   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9359   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9360   if (cMax) *cMax = mesh->hybridPointMax[dim];
9361   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9362   if (eMax) *eMax = mesh->hybridPointMax[1];
9363   if (vMax) *vMax = mesh->hybridPointMax[0];
9364   PetscFunctionReturn(0);
9365 }
9366 
9367 #undef __FUNCT__
9368 #define __FUNCT__ "DMPlexSetHybridBounds"
9369 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9370 {
9371   DM_Plex       *mesh = (DM_Plex*) dm->data;
9372   PetscInt       dim;
9373   PetscErrorCode ierr;
9374 
9375   PetscFunctionBegin;
9376   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9377   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9378   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9379   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9380   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9381   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9382   PetscFunctionReturn(0);
9383 }
9384 
9385 #undef __FUNCT__
9386 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9387 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9388 {
9389   DM_Plex *mesh = (DM_Plex*) dm->data;
9390 
9391   PetscFunctionBegin;
9392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9393   PetscValidPointer(cellHeight, 2);
9394   *cellHeight = mesh->vtkCellHeight;
9395   PetscFunctionReturn(0);
9396 }
9397 
9398 #undef __FUNCT__
9399 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9400 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9401 {
9402   DM_Plex *mesh = (DM_Plex*) dm->data;
9403 
9404   PetscFunctionBegin;
9405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9406   mesh->vtkCellHeight = cellHeight;
9407   PetscFunctionReturn(0);
9408 }
9409 
9410 #undef __FUNCT__
9411 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9412 /* We can easily have a form that takes an IS instead */
9413 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9414 {
9415   PetscSection   section, globalSection;
9416   PetscInt      *numbers, p;
9417   PetscErrorCode ierr;
9418 
9419   PetscFunctionBegin;
9420   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
9421   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9422   for (p = pStart; p < pEnd; ++p) {
9423     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9424   }
9425   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9426   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9427   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9428   for (p = pStart; p < pEnd; ++p) {
9429     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9430   }
9431   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9432   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9433   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9434   PetscFunctionReturn(0);
9435 }
9436 
9437 #undef __FUNCT__
9438 #define __FUNCT__ "DMPlexGetCellNumbering"
9439 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9440 {
9441   DM_Plex       *mesh = (DM_Plex*) dm->data;
9442   PetscInt       cellHeight, cStart, cEnd, cMax;
9443   PetscErrorCode ierr;
9444 
9445   PetscFunctionBegin;
9446   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9447   if (!mesh->globalCellNumbers) {
9448     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9449     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9450     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
9451     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9452     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9453   }
9454   *globalCellNumbers = mesh->globalCellNumbers;
9455   PetscFunctionReturn(0);
9456 }
9457 
9458 #undef __FUNCT__
9459 #define __FUNCT__ "DMPlexGetVertexNumbering"
9460 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9461 {
9462   DM_Plex       *mesh = (DM_Plex*) dm->data;
9463   PetscInt       vStart, vEnd, vMax;
9464   PetscErrorCode ierr;
9465 
9466   PetscFunctionBegin;
9467   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9468   if (!mesh->globalVertexNumbers) {
9469     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9470     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9471     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9472     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9473   }
9474   *globalVertexNumbers = mesh->globalVertexNumbers;
9475   PetscFunctionReturn(0);
9476 }
9477 
9478 #undef __FUNCT__
9479 #define __FUNCT__ "DMPlexGetScale"
9480 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9481 {
9482   DM_Plex *mesh = (DM_Plex*) dm->data;
9483 
9484   PetscFunctionBegin;
9485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9486   PetscValidPointer(scale, 3);
9487   *scale = mesh->scale[unit];
9488   PetscFunctionReturn(0);
9489 }
9490 
9491 #undef __FUNCT__
9492 #define __FUNCT__ "DMPlexSetScale"
9493 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9494 {
9495   DM_Plex *mesh = (DM_Plex*) dm->data;
9496 
9497   PetscFunctionBegin;
9498   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9499   mesh->scale[unit] = scale;
9500   PetscFunctionReturn(0);
9501 }
9502 
9503 
9504 /*******************************************************************************
9505 This should be in a separate Discretization object, but I am not sure how to lay
9506 it out yet, so I am stuffing things here while I experiment.
9507 *******************************************************************************/
9508 #undef __FUNCT__
9509 #define __FUNCT__ "DMPlexSetFEMIntegration"
9510 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9511                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9512                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9513                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9514                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9515                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9516                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9517                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9518                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9519                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9520                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9521                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9522                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9523                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9524                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9525                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9526                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9527 {
9528   DM_Plex *mesh = (DM_Plex*) dm->data;
9529 
9530   PetscFunctionBegin;
9531   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9532   mesh->integrateResidualFEM       = integrateResidualFEM;
9533   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9534   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9535   PetscFunctionReturn(0);
9536 }
9537 
9538 #undef __FUNCT__
9539 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9540 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9541 {
9542   Vec            coordinates;
9543   PetscSection   section, cSection;
9544   PetscInt       dim, vStart, vEnd, v, c, d;
9545   PetscScalar   *values, *cArray;
9546   PetscReal     *coords;
9547   PetscErrorCode ierr;
9548 
9549   PetscFunctionBegin;
9550   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9551   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9552   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9553   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9554   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9555   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9556   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9557   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9558   for (v = vStart; v < vEnd; ++v) {
9559     PetscInt dof, off;
9560 
9561     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9562     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9563     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9564     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9565     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9566     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9567   }
9568   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9569   /* Temporary, must be replaced by a projection on the finite element basis */
9570   {
9571     PetscInt eStart = 0, eEnd = 0, e, depth;
9572 
9573     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9574     --depth;
9575     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9576     for (e = eStart; e < eEnd; ++e) {
9577       const PetscInt *cone = NULL;
9578       PetscInt        coneSize, d;
9579       PetscScalar    *coordsA, *coordsB;
9580 
9581       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9582       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9583       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9584       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9585       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9586       for (d = 0; d < dim; ++d) {
9587         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9588       }
9589       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9590       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9591     }
9592   }
9593 
9594   ierr = PetscFree(coords);CHKERRQ(ierr);
9595   ierr = PetscFree(values);CHKERRQ(ierr);
9596 #if 0
9597   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9598   PetscReal      detJ;
9599 
9600   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9601   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9602   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9603 
9604   for (PetscInt c = cStart; c < cEnd; ++c) {
9605     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9606     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9607     const int                          oSize   = pV.getSize();
9608     int                                v       = 0;
9609 
9610     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9611     for (PetscInt cl = 0; cl < oSize; ++cl) {
9612       const PetscInt fDim;
9613 
9614       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9615       if (pointDim) {
9616         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9617           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9618         }
9619       }
9620     }
9621     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9622     pV.clear();
9623   }
9624   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9625   ierr = PetscFree(values);CHKERRQ(ierr);
9626 #endif
9627   PetscFunctionReturn(0);
9628 }
9629 
9630 #undef __FUNCT__
9631 #define __FUNCT__ "DMPlexProjectFunction"
9632 /*@C
9633   DMPlexProjectFunction - This projects the given function into the function space provided.
9634 
9635   Input Parameters:
9636 + dm      - The DM
9637 . numComp - The number of components (functions)
9638 . funcs   - The coordinate functions to evaluate
9639 - mode    - The insertion mode for values
9640 
9641   Output Parameter:
9642 . X - vector
9643 
9644   Level: developer
9645 
9646   Note:
9647   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9648   We will eventually fix it.
9649 
9650 ,seealso: DMPlexComputeL2Diff()
9651 */
9652 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9653 {
9654   Vec            localX;
9655   PetscErrorCode ierr;
9656 
9657   PetscFunctionBegin;
9658   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9659   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9660   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9661   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9662   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9663   PetscFunctionReturn(0);
9664 }
9665 
9666 #undef __FUNCT__
9667 #define __FUNCT__ "DMPlexComputeL2Diff"
9668 /*@C
9669   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9670 
9671   Input Parameters:
9672 + dm    - The DM
9673 . quad  - The PetscQuadrature object for each field
9674 . funcs - The functions to evaluate for each field component
9675 - X     - The coefficient vector u_h
9676 
9677   Output Parameter:
9678 . diff - The diff ||u - u_h||_2
9679 
9680   Level: developer
9681 
9682 .seealso: DMPlexProjectFunction()
9683 */
9684 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9685 {
9686   const PetscInt debug = 0;
9687   PetscSection   section;
9688   Vec            localX;
9689   PetscReal     *coords, *v0, *J, *invJ, detJ;
9690   PetscReal      localDiff = 0.0;
9691   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9692   PetscErrorCode ierr;
9693 
9694   PetscFunctionBegin;
9695   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9696   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9697   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9698   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9699   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9700   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9701   for (field = 0; field < numFields; ++field) {
9702     numComponents += quad[field].numComponents;
9703   }
9704   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9705   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9706   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9707   for (c = cStart; c < cEnd; ++c) {
9708     const PetscScalar *x;
9709     PetscReal          elemDiff = 0.0;
9710 
9711     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9712     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9713     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9714 
9715     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9716       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9717       const PetscReal *quadPoints    = quad[field].quadPoints;
9718       const PetscReal *quadWeights   = quad[field].quadWeights;
9719       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9720       const PetscInt   numBasisComps = quad[field].numComponents;
9721       const PetscReal *basis         = quad[field].basis;
9722       PetscInt         q, d, e, fc, f;
9723 
9724       if (debug) {
9725         char title[1024];
9726         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9727         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9728       }
9729       for (q = 0; q < numQuadPoints; ++q) {
9730         for (d = 0; d < dim; d++) {
9731           coords[d] = v0[d];
9732           for (e = 0; e < dim; e++) {
9733             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9734           }
9735         }
9736         for (fc = 0; fc < numBasisComps; ++fc) {
9737           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9738           PetscReal       interpolant = 0.0;
9739           for (f = 0; f < numBasisFuncs; ++f) {
9740             const PetscInt fidx = f*numBasisComps+fc;
9741             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9742           }
9743           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9744           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9745         }
9746       }
9747       comp        += numBasisComps;
9748       fieldOffset += numBasisFuncs*numBasisComps;
9749     }
9750     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9751     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9752     localDiff += elemDiff;
9753   }
9754   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9755   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9756   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9757   *diff = PetscSqrtReal(*diff);
9758   PetscFunctionReturn(0);
9759 }
9760 
9761 #undef __FUNCT__
9762 #define __FUNCT__ "DMPlexComputeResidualFEM"
9763 /*@
9764   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9765 
9766   Input Parameters:
9767 + dm - The mesh
9768 . X  - Local input vector
9769 - user - The user context
9770 
9771   Output Parameter:
9772 . F  - Local output vector
9773 
9774   Note:
9775   The second member of the user context must be an FEMContext.
9776 
9777   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9778   like a GPU, or vectorize on a multicore machine.
9779 
9780 .seealso: DMPlexComputeJacobianActionFEM()
9781 */
9782 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9783 {
9784   DM_Plex         *mesh = (DM_Plex*) dm->data;
9785   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9786   PetscQuadrature *quad = fem->quad;
9787   PetscSection     section;
9788   PetscReal       *v0, *J, *invJ, *detJ;
9789   PetscScalar     *elemVec, *u;
9790   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9791   PetscInt         cellDof = 0, numComponents = 0;
9792   PetscErrorCode   ierr;
9793 
9794   PetscFunctionBegin;
9795   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9796   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9797   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9798   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9799   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9800   numCells = cEnd - cStart;
9801   for (field = 0; field < numFields; ++field) {
9802     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9803     numComponents += quad[field].numComponents;
9804   }
9805   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9806   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9807   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);
9808   for (c = cStart; c < cEnd; ++c) {
9809     const PetscScalar *x;
9810     PetscInt           i;
9811 
9812     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9813     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9814     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9815 
9816     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9817     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9818   }
9819   for (field = 0; field < numFields; ++field) {
9820     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9821     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9822     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9823     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9824     /* Conforming batches */
9825     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9826     PetscInt numBlocks  = 1;
9827     PetscInt batchSize  = numBlocks * blockSize;
9828     PetscInt numBatches = numBatchesTmp;
9829     PetscInt numChunks  = numCells / (numBatches*batchSize);
9830     /* Remainder */
9831     PetscInt numRemainder = numCells % (numBatches * batchSize);
9832     PetscInt offset       = numCells - numRemainder;
9833 
9834     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9835     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9836                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9837   }
9838   for (c = cStart; c < cEnd; ++c) {
9839     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9840     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9841   }
9842   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9843   if (mesh->printFEM) {
9844     PetscMPIInt rank, numProcs;
9845     PetscInt    p;
9846 
9847     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9848     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9849     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9850     for (p = 0; p < numProcs; ++p) {
9851       if (p == rank) {
9852         Vec f;
9853 
9854         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9855         ierr = VecCopy(F, f);CHKERRQ(ierr);
9856         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9857         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9858         ierr = VecDestroy(&f);CHKERRQ(ierr);
9859         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9860       }
9861       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9862     }
9863   }
9864   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9865   PetscFunctionReturn(0);
9866 }
9867 
9868 #undef __FUNCT__
9869 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9870 /*@C
9871   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9872 
9873   Input Parameters:
9874 + dm - The mesh
9875 . J  - The Jacobian shell matrix
9876 . X  - Local input vector
9877 - user - The user context
9878 
9879   Output Parameter:
9880 . F  - Local output vector
9881 
9882   Note:
9883   The second member of the user context must be an FEMContext.
9884 
9885   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9886   like a GPU, or vectorize on a multicore machine.
9887 
9888 .seealso: DMPlexComputeResidualFEM()
9889 */
9890 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9891 {
9892   DM_Plex         *mesh = (DM_Plex*) dm->data;
9893   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9894   PetscQuadrature *quad = fem->quad;
9895   PetscSection     section;
9896   JacActionCtx    *jctx;
9897   PetscReal       *v0, *J, *invJ, *detJ;
9898   PetscScalar     *elemVec, *u, *a;
9899   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9900   PetscInt         cellDof = 0;
9901   PetscErrorCode   ierr;
9902 
9903   PetscFunctionBegin;
9904   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9905   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9906   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9907   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9908   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9909   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9910   numCells = cEnd - cStart;
9911   for (field = 0; field < numFields; ++field) {
9912     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9913   }
9914   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9915   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);
9916   for (c = cStart; c < cEnd; ++c) {
9917     const PetscScalar *x;
9918     PetscInt           i;
9919 
9920     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9921     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9922     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9923     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9924     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9925     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9926     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9927     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9928   }
9929   for (field = 0; field < numFields; ++field) {
9930     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9931     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9932     /* Conforming batches */
9933     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9934     PetscInt numBlocks  = 1;
9935     PetscInt batchSize  = numBlocks * blockSize;
9936     PetscInt numBatches = numBatchesTmp;
9937     PetscInt numChunks  = numCells / (numBatches*batchSize);
9938     /* Remainder */
9939     PetscInt numRemainder = numCells % (numBatches * batchSize);
9940     PetscInt offset       = numCells - numRemainder;
9941 
9942     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);
9943     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],
9944                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9945   }
9946   for (c = cStart; c < cEnd; ++c) {
9947     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9948     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9949   }
9950   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9951   if (mesh->printFEM) {
9952     PetscMPIInt rank, numProcs;
9953     PetscInt    p;
9954 
9955     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9956     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9957     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9958     for (p = 0; p < numProcs; ++p) {
9959       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9960       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9961     }
9962   }
9963   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9964   PetscFunctionReturn(0);
9965 }
9966 
9967 #undef __FUNCT__
9968 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9969 /*@
9970   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9971 
9972   Input Parameters:
9973 + dm - The mesh
9974 . X  - Local input vector
9975 - user - The user context
9976 
9977   Output Parameter:
9978 . Jac  - Jacobian matrix
9979 
9980   Note:
9981   The second member of the user context must be an FEMContext.
9982 
9983   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9984   like a GPU, or vectorize on a multicore machine.
9985 
9986 .seealso: FormFunctionLocal()
9987 */
9988 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9989 {
9990   DM_Plex         *mesh = (DM_Plex*) dm->data;
9991   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9992   PetscQuadrature *quad = fem->quad;
9993   PetscSection     section;
9994   PetscReal       *v0, *J, *invJ, *detJ;
9995   PetscScalar     *elemMat, *u;
9996   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9997   PetscInt         cellDof = 0, numComponents = 0;
9998   PetscBool        isShell;
9999   PetscErrorCode   ierr;
10000 
10001   PetscFunctionBegin;
10002   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10003   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10004   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10005   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10006   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10007   numCells = cEnd - cStart;
10008   for (field = 0; field < numFields; ++field) {
10009     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10010     numComponents += quad[field].numComponents;
10011   }
10012   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10013   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10014   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);
10015   for (c = cStart; c < cEnd; ++c) {
10016     const PetscScalar *x;
10017     PetscInt           i;
10018 
10019     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10020     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10021     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10022 
10023     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10024     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10025   }
10026   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10027   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10028     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10029     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10030     PetscInt       fieldJ;
10031 
10032     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10033       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10034       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10035       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10036       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10037       /* Conforming batches */
10038       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10039       PetscInt numBlocks  = 1;
10040       PetscInt batchSize  = numBlocks * blockSize;
10041       PetscInt numBatches = numBatchesTmp;
10042       PetscInt numChunks  = numCells / (numBatches*batchSize);
10043       /* Remainder */
10044       PetscInt numRemainder = numCells % (numBatches * batchSize);
10045       PetscInt offset       = numCells - numRemainder;
10046 
10047       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10048       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10049                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10050     }
10051   }
10052   for (c = cStart; c < cEnd; ++c) {
10053     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10054     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10055   }
10056   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10057 
10058   /* Assemble matrix, using the 2-step process:
10059        MatAssemblyBegin(), MatAssemblyEnd(). */
10060   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10061   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10062 
10063   if (mesh->printFEM) {
10064     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10065     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10066     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10067   }
10068   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10069   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10070   if (isShell) {
10071     JacActionCtx *jctx;
10072 
10073     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10074     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10075   }
10076   *str = SAME_NONZERO_PATTERN;
10077   PetscFunctionReturn(0);
10078 }
10079 
10080 
10081 #undef __FUNCT__
10082 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10083 /*@C
10084   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10085   the local section and an SF describing the section point overlap.
10086 
10087   Input Parameters:
10088   + s - The PetscSection for the local field layout
10089   . sf - The SF describing parallel layout of the section points
10090   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10091   . label - The label specifying the points
10092   - labelValue - The label stratum specifying the points
10093 
10094   Output Parameter:
10095   . gsection - The PetscSection for the global field layout
10096 
10097   Note: This gives negative sizes and offsets to points not owned by this process
10098 
10099   Level: developer
10100 
10101 .seealso: PetscSectionCreate()
10102 @*/
10103 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10104 {
10105   PetscInt      *neg;
10106   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10107   PetscErrorCode ierr;
10108 
10109   PetscFunctionBegin;
10110   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10111   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10112   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10113   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10114   /* Mark ghost points with negative dof */
10115   for (p = pStart; p < pEnd; ++p) {
10116     PetscInt value;
10117 
10118     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10119     if (value != labelValue) continue;
10120     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10121     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10122     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10123     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10124     neg[p-pStart] = -(dof+1);
10125   }
10126   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10127   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
10128   if (nroots >= 0) {
10129     if (nroots > pEnd - pStart) {
10130       PetscInt *tmpDof;
10131       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10132       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10133       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10134       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10135       for (p = pStart; p < pEnd; ++p) {
10136         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
10137       }
10138       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10139     } else {
10140       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10141       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10142     }
10143   }
10144   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10145   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10146     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10147 
10148     (*gsection)->atlasOff[p] = off;
10149 
10150     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10151   }
10152   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10153   globalOff -= off;
10154   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10155     (*gsection)->atlasOff[p] += globalOff;
10156 
10157     neg[p] = -((*gsection)->atlasOff[p]+1);
10158   }
10159   /* Put in negative offsets for ghost points */
10160   if (nroots >= 0) {
10161     if (nroots > pEnd - pStart) {
10162       PetscInt *tmpOff;
10163       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10164       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10165       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10166       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10167       for (p = pStart; p < pEnd; ++p) {
10168         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
10169       }
10170       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10171     } else {
10172       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10173       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10174     }
10175   }
10176   ierr = PetscFree(neg);CHKERRQ(ierr);
10177   PetscFunctionReturn(0);
10178 }
10179