xref: /petsc/src/dm/impls/plex/plex.c (revision 0d644c17a87005f19204129b6fd2ef1d95a3ace6)
1 #include <petsc-private/pleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 
4 /* Logging support */
5 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
6 
7 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
8 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "VecView_Plex_Local"
12 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
13 {
14   DM             dm;
15   PetscBool      isvtk;
16   PetscErrorCode ierr;
17 
18   PetscFunctionBegin;
19   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
20   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
21   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
22   if (isvtk) {
23     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
24     PetscSection            section;
25     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
26 
27     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
28     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
29     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, PETSC_NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, PETSC_NULL);CHKERRQ(ierr);
32     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
33     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
34     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
35     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
36     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
37     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
38       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
39     } else if (cdof && vdof) {
40       SETERRQ(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
41     } else if (cdof) {
42       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
43        * vector or just happens to have the same number of dofs as the dimension. */
44       if (cdof == dim) {
45         ft = PETSC_VTK_CELL_VECTOR_FIELD;
46       } else {
47         ft = PETSC_VTK_CELL_FIELD;
48       }
49     } else if (vdof) {
50       if (vdof == dim) {
51         ft = PETSC_VTK_POINT_VECTOR_FIELD;
52       } else {
53         ft = PETSC_VTK_POINT_FIELD;
54       }
55     } else SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
56 
57     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
58     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
59     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
60   } else {
61     PetscBool isseq;
62 
63     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
64     if (isseq) {
65       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
66     } else {
67       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "VecView_Plex"
75 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
76 {
77   DM             dm;
78   PetscBool      isvtk;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
83   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
84   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
85   if (isvtk) {
86     Vec        locv;
87     const char *name;
88 
89     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
90     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
91     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
92     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
95     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
96   } else {
97     PetscBool isseq;
98 
99     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
100     if (isseq) {
101       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
102     } else {
103       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
104     }
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "DMPlexView_Ascii"
111 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
112 {
113   DM_Plex           *mesh = (DM_Plex*) dm->data;
114   DM                cdm;
115   DMLabel           markers;
116   PetscSection      coordSection;
117   Vec               coordinates;
118   PetscViewerFormat format;
119   PetscErrorCode    ierr;
120 
121   PetscFunctionBegin;
122   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
123   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
124   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
125   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
126   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
127     const char  *name;
128     PetscInt    maxConeSize, maxSupportSize;
129     PetscInt    pStart, pEnd, p;
130     PetscMPIInt rank, size;
131 
132     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
133     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
134     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
135     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
136     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
137     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
138     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
142     for (p = pStart; p < pEnd; ++p) {
143       PetscInt dof, off, s;
144 
145       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
146       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
147       for (s = off; s < off+dof; ++s) {
148         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
149       }
150     }
151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
152     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
153     for (p = pStart; p < pEnd; ++p) {
154       PetscInt dof, off, c;
155 
156       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
157       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
158       for (c = off; c < off+dof; ++c) {
159         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
160       }
161     }
162     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
163     ierr = PetscSectionGetChart(coordSection, &pStart, PETSC_NULL);CHKERRQ(ierr);
164     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
165     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
166     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
167     if (size > 1) {
168       PetscSF sf;
169 
170       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
171       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
172     }
173     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
174   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
175     const char  *name;
176     const char  *colors[3] = {"red", "blue", "green"};
177     const int   numColors  = 3;
178     PetscReal   scale      = 2.0;
179     PetscScalar *coords;
180     PetscInt    depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
181     PetscMPIInt rank, size;
182 
183     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
184     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
185     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
186     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
187     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
188     ierr = PetscViewerASCIIPrintf(viewer, "\
189 \\documentclass[crop,multi=false]{standalone}\n\n\
190 \\usepackage{tikz}\n\
191 \\usepackage{pgflibraryshapes}\n\
192 \\usetikzlibrary{backgrounds}\n\
193 \\usetikzlibrary{arrows}\n\
194 \\begin{document}\n\
195 \\section{%s}\n\
196 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
197     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
198     for (p = 0; p < size; ++p) {
199       if (p > 0 && p == size-1) {
200         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
201       } else if (p > 0) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
203       }
204       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
205     }
206     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
207 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
208     /* Plot vertices */
209     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
210     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
211     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
212     for (v = vStart; v < vEnd; ++v) {
213       PetscInt off, dof, d;
214 
215       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
216       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
217       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
218       for (d = 0; d < dof; ++d) {
219         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
220         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
221       }
222       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
223     }
224     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
225     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
226     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
227     /* Plot edges */
228     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
229     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
230     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
231     for (e = eStart; e < eEnd; ++e) {
232       const PetscInt *cone;
233       PetscInt       coneSize, offA, offB, dof, d;
234 
235       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
236       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
237       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
238       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
239       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
240       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
241       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
242       for (d = 0; d < dof; ++d) {
243         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
244         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
245       }
246       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
247     }
248     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
249     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
250     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
251     /* Plot cells */
252     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
253     for (c = cStart; c < cEnd; ++c) {
254       PetscInt *closure = PETSC_NULL;
255       PetscInt closureSize, firstPoint = -1;
256 
257       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
258       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
259       for (p = 0; p < closureSize*2; p += 2) {
260         const PetscInt point = closure[p];
261 
262         if ((point < vStart) || (point >= vEnd)) continue;
263         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
264         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
265         if (firstPoint < 0) firstPoint = point;
266       }
267       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
268       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
269       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
270     }
271     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
272     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
273     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
274   } else {
275     MPI_Comm    comm = ((PetscObject) dm)->comm;
276     PetscInt    *sizes;
277     PetscInt    locDepth, depth, dim, d;
278     PetscInt    pStart, pEnd, p;
279     PetscMPIInt size;
280 
281     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
282     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
283     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
284     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
285     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
286     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
287     if (depth == 1) {
288       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
289       pEnd = pEnd - pStart;
290       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
291       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
292       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
293       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
294       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
295       pEnd = pEnd - pStart;
296       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
297       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
298       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
299       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
300     } else {
301       for (d = 0; d <= dim; d++) {
302         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
303         pEnd = pEnd - pStart;
304         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
305         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
306         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
307         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
308       }
309     }
310     ierr = PetscFree(sizes);CHKERRQ(ierr);
311   }
312   PetscFunctionReturn(0);
313 }
314 
315 #undef __FUNCT__
316 #define __FUNCT__ "DMView_Plex"
317 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
318 {
319   PetscBool      iascii, isbinary;
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
324   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
325   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
326   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
327   if (iascii) {
328     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
329 #if 0
330   } else if (isbinary) {
331     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
332 #endif
333   }
334   PetscFunctionReturn(0);
335 }
336 
337 #undef __FUNCT__
338 #define __FUNCT__ "DMDestroy_Plex"
339 PetscErrorCode DMDestroy_Plex(DM dm)
340 {
341   DM_Plex        *mesh = (DM_Plex*) dm->data;
342   DMLabel        next  = mesh->labels;
343   PetscErrorCode ierr;
344 
345   PetscFunctionBegin;
346   if (--mesh->refct > 0) PetscFunctionReturn(0);
347   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
348   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
349   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
350   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
353   while (next) {
354     DMLabel tmp = next->next;
355 
356     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
357     next = tmp;
358   }
359   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
360   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
361   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
362   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
363   ierr = PetscFree(mesh);CHKERRQ(ierr);
364   PetscFunctionReturn(0);
365 }
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
369 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
370 {
371   const PetscInt *support = PETSC_NULL;
372   PetscInt       numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
373   PetscErrorCode ierr;
374 
375   PetscFunctionBegin;
376   if (useClosure) {
377     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
378     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
379     for (s = 0; s < supportSize; ++s) {
380       const PetscInt *cone = PETSC_NULL;
381       PetscInt       coneSize, c, q;
382 
383       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
384       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
385       for (c = 0; c < coneSize; ++c) {
386         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
387           if (cone[c] == adj[q]) break;
388         }
389         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
390       }
391     }
392   } else {
393     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
394     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
395     for (s = 0; s < supportSize; ++s) {
396       const PetscInt *cone = PETSC_NULL;
397       PetscInt       coneSize, c, q;
398 
399       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
400       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
401       for (c = 0; c < coneSize; ++c) {
402         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
403           if (cone[c] == adj[q]) break;
404         }
405         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
406       }
407     }
408   }
409   *adjSize = numAdj;
410   PetscFunctionReturn(0);
411 }
412 
413 #undef __FUNCT__
414 #define __FUNCT__ "DMPlexGetAdjacency_Private"
415 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
416 {
417   const PetscInt *star  = tmpClosure;
418   PetscInt       numAdj = 0, maxAdjSize = *adjSize, starSize, s;
419   PetscErrorCode ierr;
420 
421   PetscFunctionBegin;
422   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
423   for (s = 2; s < starSize*2; s += 2) {
424     const PetscInt *closure = PETSC_NULL;
425     PetscInt       closureSize, c, q;
426 
427     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
428     for (c = 0; c < closureSize*2; c += 2) {
429       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
430         if (closure[c] == adj[q]) break;
431       }
432       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
433     }
434     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
435   }
436   *adjSize = numAdj;
437   PetscFunctionReturn(0);
438 }
439 
440 #undef __FUNCT__
441 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
442 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
443 {
444   DM_Plex *mesh = (DM_Plex*) dm->data;
445 
446   PetscFunctionBegin;
447   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
448   mesh->preallocCenterDim = preallocCenterDim;
449   PetscFunctionReturn(0);
450 }
451 
452 #undef __FUNCT__
453 #define __FUNCT__ "DMPlexPreallocateOperator"
454 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
455 {
456   DM_Plex           *mesh = (DM_Plex*) dm->data;
457   MPI_Comm          comm  = ((PetscObject) dm)->comm;
458   PetscSF           sf, sfDof, sfAdj;
459   PetscSection      leafSectionAdj, rootSectionAdj, sectionAdj;
460   PetscInt          nleaves, l, p;
461   const PetscInt    *leaves;
462   const PetscSFNode *remotes;
463   PetscInt          dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
464   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
465   PetscInt          depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
466   PetscLayout       rLayout;
467   PetscInt          locRows, rStart, rEnd, r;
468   PetscMPIInt       size;
469   PetscBool         useClosure, debug = PETSC_FALSE;
470   PetscErrorCode    ierr;
471 
472   PetscFunctionBegin;
473   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
474   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
475   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
476   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
477   /* Create dof SF based on point SF */
478   if (debug) {
479     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
480     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
481     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
485   }
486   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
487   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
488   if (debug) {
489     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
490     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
491   }
492   /* Create section for dof adjacency (dof ==> # adj dof) */
493   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
494   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
495   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
496   if (mesh->preallocCenterDim == dim) {
497     useClosure = PETSC_FALSE;
498   } else if (mesh->preallocCenterDim == 0) {
499     useClosure = PETSC_TRUE;
500   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
501 
502   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
503   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
504   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
505   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
508   /*   Fill in the ghost dofs on the interface */
509   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
510   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
511   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
512 
513   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
514   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
515 
516   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
517 
518   /*
519    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
520     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
521        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
522     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
523        Create sfAdj connecting rootSectionAdj and leafSectionAdj
524     3. Visit unowned points on interface, write adjacencies to adj
525        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
526     4. Visit owned points on interface, write adjacencies to rootAdj
527        Remove redundancy in rootAdj
528    ** The last two traversals use transitive closure
529     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
530        Allocate memory addressed by sectionAdj (cols)
531     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
532    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
533   */
534 
535   for (l = 0; l < nleaves; ++l) {
536     PetscInt dof, off, d, q;
537     PetscInt p = leaves[l], numAdj = maxAdjSize;
538 
539     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
540     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
541     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
542     for (q = 0; q < numAdj; ++q) {
543       PetscInt ndof, ncdof;
544 
545       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
546       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
547       for (d = off; d < off+dof; ++d) {
548         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
549       }
550     }
551   }
552   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
553   if (debug) {
554     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
555     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
556   }
557   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
558   if (size > 1) {
559     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
560     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561   }
562   if (debug) {
563     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
564     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
565   }
566   /* Add in local adjacency sizes for owned dofs on interface (roots) */
567   for (p = pStart; p < pEnd; ++p) {
568     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
569 
570     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
571     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
572     if (!dof) continue;
573     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
574     if (adof <= 0) continue;
575     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
576     for (q = 0; q < numAdj; ++q) {
577       PetscInt ndof, ncdof;
578 
579       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
580       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
581       for (d = off; d < off+dof; ++d) {
582         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
583       }
584     }
585   }
586   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
587   if (debug) {
588     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
589     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
590   }
591   /* Create adj SF based on dof SF */
592   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
593   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
596     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
597   }
598   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
599   /* Create leaf adjacency */
600   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
601   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
602   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
603   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
604   for (l = 0; l < nleaves; ++l) {
605     PetscInt dof, off, d, q;
606     PetscInt p = leaves[l], numAdj = maxAdjSize;
607 
608     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
609     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
610     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
611     for (d = off; d < off+dof; ++d) {
612       PetscInt aoff, i = 0;
613 
614       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
615       for (q = 0; q < numAdj; ++q) {
616         PetscInt ndof, ncdof, ngoff, nd;
617 
618         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
619         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
620         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
621         for (nd = 0; nd < ndof-ncdof; ++nd) {
622           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
623           ++i;
624         }
625       }
626     }
627   }
628   /* Debugging */
629   if (debug) {
630     IS tmp;
631     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
632     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
633     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
634   }
635   /* Gather adjacenct indices to root */
636   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
637   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
638   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
639   if (size > 1) {
640     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
641     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
642   }
643   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
644   ierr = PetscFree(adj);CHKERRQ(ierr);
645   /* Debugging */
646   if (debug) {
647     IS tmp;
648     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
649     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
650     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
651   }
652   /* Add in local adjacency indices for owned dofs on interface (roots) */
653   for (p = pStart; p < pEnd; ++p) {
654     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
655 
656     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
657     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
658     if (!dof) continue;
659     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
660     if (adof <= 0) continue;
661     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
662     for (d = off; d < off+dof; ++d) {
663       PetscInt adof, aoff, i;
664 
665       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
666       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
667       i    = adof-1;
668       for (q = 0; q < numAdj; ++q) {
669         PetscInt ndof, ncdof, ngoff, nd;
670 
671         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
672         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
673         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
674         for (nd = 0; nd < ndof-ncdof; ++nd) {
675           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
676           --i;
677         }
678       }
679     }
680   }
681   /* Debugging */
682   if (debug) {
683     IS tmp;
684     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
685     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
686     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
687   }
688   /* Compress indices */
689   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
690   for (p = pStart; p < pEnd; ++p) {
691     PetscInt dof, cdof, off, d;
692     PetscInt adof, aoff;
693 
694     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
695     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
696     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
697     if (!dof) continue;
698     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
699     if (adof <= 0) continue;
700     for (d = off; d < off+dof-cdof; ++d) {
701       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
702       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
703       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
704       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
705     }
706   }
707   /* Debugging */
708   if (debug) {
709     IS tmp;
710     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
711     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
712     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
713     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
714     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
715   }
716   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
717   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
718   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
719   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
720   for (p = pStart; p < pEnd; ++p) {
721     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
722     PetscBool found  = PETSC_TRUE;
723 
724     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
725     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
726     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
727     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
728     for (d = 0; d < dof-cdof; ++d) {
729       PetscInt ldof, rdof;
730 
731       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
732       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
733       if (ldof > 0) {
734         /* We do not own this point */
735       } else if (rdof > 0) {
736         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
737       } else {
738         found = PETSC_FALSE;
739       }
740     }
741     if (found) continue;
742     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
743     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
744     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
745     for (q = 0; q < numAdj; ++q) {
746       PetscInt ndof, ncdof, noff;
747 
748       /* Adjacent points may not be in the section chart */
749       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
750       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
751       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
752       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
753       for (d = goff; d < goff+dof-cdof; ++d) {
754         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
755       }
756     }
757   }
758   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
759   if (debug) {
760     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
761     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
762   }
763   /* Get adjacent indices */
764   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
765   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
766   for (p = pStart; p < pEnd; ++p) {
767     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
768     PetscBool found  = PETSC_TRUE;
769 
770     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
771     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
772     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
773     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
774     for (d = 0; d < dof-cdof; ++d) {
775       PetscInt ldof, rdof;
776 
777       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
778       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
779       if (ldof > 0) {
780         /* We do not own this point */
781       } else if (rdof > 0) {
782         PetscInt aoff, roff;
783 
784         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
785         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
786         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
787       } else {
788         found = PETSC_FALSE;
789       }
790     }
791     if (found) continue;
792     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
793     for (d = goff; d < goff+dof-cdof; ++d) {
794       PetscInt adof, aoff, i = 0;
795 
796       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
797       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
798       for (q = 0; q < numAdj; ++q) {
799         PetscInt        ndof, ncdof, ngoff, nd;
800         const PetscInt *ncind;
801 
802         /* Adjacent points may not be in the section chart */
803         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
804         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
805         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
806         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
807         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
808         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
809           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
810         }
811       }
812       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
813     }
814   }
815   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
816   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
817   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
818   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
819   /* Debugging */
820   if (debug) {
821     IS tmp;
822     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
823     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
824     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
825   }
826   /* Create allocation vectors from adjacency graph */
827   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
828   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
829   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
830   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
831   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
832   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
833   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
834   /* Only loop over blocks of rows */
835   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
836   for (r = rStart/bs; r < rEnd/bs; ++r) {
837     const PetscInt row = r*bs;
838     PetscInt       numCols, cStart, c;
839 
840     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
841     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
842     for (c = cStart; c < cStart+numCols; ++c) {
843       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
844         ++dnz[r-rStart];
845         if (cols[c] >= row) ++dnzu[r-rStart];
846       } else {
847         ++onz[r-rStart];
848         if (cols[c] >= row) ++onzu[r-rStart];
849       }
850     }
851   }
852   if (bs > 1) {
853     for (r = 0; r < locRows/bs; ++r) {
854       dnz[r]  /= bs;
855       onz[r]  /= bs;
856       dnzu[r] /= bs;
857       onzu[r] /= bs;
858     }
859   }
860   /* Set matrix pattern */
861   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
862   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
863   /* Fill matrix with zeros */
864   if (fillMatrix) {
865     PetscScalar *values;
866     PetscInt    maxRowLen = 0;
867 
868     for (r = rStart; r < rEnd; ++r) {
869       PetscInt len;
870 
871       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
872       maxRowLen = PetscMax(maxRowLen, len);
873     }
874     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
875     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
876     for (r = rStart; r < rEnd; ++r) {
877       PetscInt numCols, cStart;
878 
879       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
880       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
881       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
882     }
883     ierr = PetscFree(values);CHKERRQ(ierr);
884     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
885     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
886   }
887   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
888   ierr = PetscFree(cols);CHKERRQ(ierr);
889   PetscFunctionReturn(0);
890 }
891 
892 #if 0
893 #undef __FUNCT__
894 #define __FUNCT__ "DMPlexPreallocateOperator_2"
895 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
896 {
897   PetscErrorCode ierr;
898   PetscInt       c,cStart,cEnd,pStart,pEnd;
899   PetscInt       *tmpClosure,*tmpAdj,*visits;
900 
901   PetscFunctionBegin;
902   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
903   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
904   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
905 
906   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
907 
908   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910 
911   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
912   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
914   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
915   for (c=cStart; c<cEnd; c++) {
916     PetscInt *support = tmpClosure;
917     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
918     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
919   }
920   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
921   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
923   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924 
925   ierr = PetscSFGetRanks();CHKERRQ(ierr);
926 
927 
928   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
929   for (c=cStart; c<cEnd; c++) {
930     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
931     /*
932      Depth-first walk of transitive closure.
933      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
934      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
935      */
936   }
937 
938   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
939   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
940   PetscFunctionReturn(0);
941 }
942 #endif
943 
944 #undef __FUNCT__
945 #define __FUNCT__ "DMCreateMatrix_Plex"
946 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
947 {
948   PetscSection   section, sectionGlobal;
949   PetscInt       bs = -1;
950   PetscInt       localSize;
951   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
952   PetscErrorCode ierr;
953 
954   PetscFunctionBegin;
955 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
956   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
957 #endif
958   if (!mtype) mtype = MATAIJ;
959   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
960   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
961   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
962   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
963   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
964   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
965   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
966   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
967   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
974   /* Check for symmetric storage */
975   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
976   if (isSymmetric) {
977     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
978   }
979   if (!isShell) {
980     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
981     PetscInt  *dnz, *onz, *dnzu, *onzu, bsLocal;
982 
983     if (bs < 0) {
984       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
985         PetscInt pStart, pEnd, p, dof;
986 
987         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
988         for (p = pStart; p < pEnd; ++p) {
989           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
990           if (dof) {
991             bs = dof;
992             break;
993           }
994         }
995       } else {
996         bs = 1;
997       }
998       /* Must have same blocksize on all procs (some might have no points) */
999       bsLocal = bs;
1000       ierr    = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1001     }
1002     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1003     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1004     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1005     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1006     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1007     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1008     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1009   }
1010   PetscFunctionReturn(0);
1011 }
1012 
1013 #undef __FUNCT__
1014 #define __FUNCT__ "DMPlexGetDimension"
1015 /*@
1016   DMPlexGetDimension - Return the topological mesh dimension
1017 
1018   Not collective
1019 
1020   Input Parameter:
1021 . mesh - The DMPlex
1022 
1023   Output Parameter:
1024 . dim - The topological mesh dimension
1025 
1026   Level: beginner
1027 
1028 .seealso: DMPlexCreate()
1029 @*/
1030 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1031 {
1032   DM_Plex *mesh = (DM_Plex*) dm->data;
1033 
1034   PetscFunctionBegin;
1035   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1036   PetscValidPointer(dim, 2);
1037   *dim = mesh->dim;
1038   PetscFunctionReturn(0);
1039 }
1040 
1041 #undef __FUNCT__
1042 #define __FUNCT__ "DMPlexSetDimension"
1043 /*@
1044   DMPlexSetDimension - Set the topological mesh dimension
1045 
1046   Collective on mesh
1047 
1048   Input Parameters:
1049 + mesh - The DMPlex
1050 - dim - The topological mesh dimension
1051 
1052   Level: beginner
1053 
1054 .seealso: DMPlexCreate()
1055 @*/
1056 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1057 {
1058   DM_Plex *mesh = (DM_Plex*) dm->data;
1059 
1060   PetscFunctionBegin;
1061   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1062   PetscValidLogicalCollectiveInt(dm, dim, 2);
1063   mesh->dim               = dim;
1064   mesh->preallocCenterDim = dim;
1065   PetscFunctionReturn(0);
1066 }
1067 
1068 #undef __FUNCT__
1069 #define __FUNCT__ "DMPlexGetChart"
1070 /*@
1071   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1072 
1073   Not collective
1074 
1075   Input Parameter:
1076 . mesh - The DMPlex
1077 
1078   Output Parameters:
1079 + pStart - The first mesh point
1080 - pEnd   - The upper bound for mesh points
1081 
1082   Level: beginner
1083 
1084 .seealso: DMPlexCreate(), DMPlexSetChart()
1085 @*/
1086 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1087 {
1088   DM_Plex        *mesh = (DM_Plex*) dm->data;
1089   PetscErrorCode ierr;
1090 
1091   PetscFunctionBegin;
1092   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1093   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1094   PetscFunctionReturn(0);
1095 }
1096 
1097 #undef __FUNCT__
1098 #define __FUNCT__ "DMPlexSetChart"
1099 /*@
1100   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1101 
1102   Not collective
1103 
1104   Input Parameters:
1105 + mesh - The DMPlex
1106 . pStart - The first mesh point
1107 - pEnd   - The upper bound for mesh points
1108 
1109   Output Parameters:
1110 
1111   Level: beginner
1112 
1113 .seealso: DMPlexCreate(), DMPlexGetChart()
1114 @*/
1115 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1116 {
1117   DM_Plex        *mesh = (DM_Plex*) dm->data;
1118   PetscErrorCode ierr;
1119 
1120   PetscFunctionBegin;
1121   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1122   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1123   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1124   PetscFunctionReturn(0);
1125 }
1126 
1127 #undef __FUNCT__
1128 #define __FUNCT__ "DMPlexGetConeSize"
1129 /*@
1130   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1131 
1132   Not collective
1133 
1134   Input Parameters:
1135 + mesh - The DMPlex
1136 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1137 
1138   Output Parameter:
1139 . size - The cone size for point p
1140 
1141   Level: beginner
1142 
1143 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1144 @*/
1145 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1146 {
1147   DM_Plex        *mesh = (DM_Plex*) dm->data;
1148   PetscErrorCode ierr;
1149 
1150   PetscFunctionBegin;
1151   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1152   PetscValidPointer(size, 3);
1153   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1154   PetscFunctionReturn(0);
1155 }
1156 
1157 #undef __FUNCT__
1158 #define __FUNCT__ "DMPlexSetConeSize"
1159 /*@
1160   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1161 
1162   Not collective
1163 
1164   Input Parameters:
1165 + mesh - The DMPlex
1166 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1167 - size - The cone size for point p
1168 
1169   Output Parameter:
1170 
1171   Note:
1172   This should be called after DMPlexSetChart().
1173 
1174   Level: beginner
1175 
1176 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1177 @*/
1178 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1179 {
1180   DM_Plex        *mesh = (DM_Plex*) dm->data;
1181   PetscErrorCode ierr;
1182 
1183   PetscFunctionBegin;
1184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1185   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1186 
1187   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1188   PetscFunctionReturn(0);
1189 }
1190 
1191 #undef __FUNCT__
1192 #define __FUNCT__ "DMPlexGetCone"
1193 /*@C
1194   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1195 
1196   Not collective
1197 
1198   Input Parameters:
1199 + mesh - The DMPlex
1200 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1201 
1202   Output Parameter:
1203 . cone - An array of points which are on the in-edges for point p
1204 
1205   Level: beginner
1206 
1207   Note:
1208   This routine is not available in Fortran.
1209 
1210 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1211 @*/
1212 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1213 {
1214   DM_Plex        *mesh = (DM_Plex*) dm->data;
1215   PetscInt       off;
1216   PetscErrorCode ierr;
1217 
1218   PetscFunctionBegin;
1219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1220   PetscValidPointer(cone, 3);
1221   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1222   *cone = &mesh->cones[off];
1223   PetscFunctionReturn(0);
1224 }
1225 
1226 #undef __FUNCT__
1227 #define __FUNCT__ "DMPlexSetCone"
1228 /*@
1229   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1230 
1231   Not collective
1232 
1233   Input Parameters:
1234 + mesh - The DMPlex
1235 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1236 - cone - An array of points which are on the in-edges for point p
1237 
1238   Output Parameter:
1239 
1240   Note:
1241   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1242 
1243   Level: beginner
1244 
1245 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1246 @*/
1247 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1248 {
1249   DM_Plex        *mesh = (DM_Plex*) dm->data;
1250   PetscInt       pStart, pEnd;
1251   PetscInt       dof, off, c;
1252   PetscErrorCode ierr;
1253 
1254   PetscFunctionBegin;
1255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1256   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1257   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1258   if (dof) PetscValidPointer(cone, 3);
1259   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1260   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1261   for (c = 0; c < dof; ++c) {
1262     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1263     mesh->cones[off+c] = cone[c];
1264   }
1265   PetscFunctionReturn(0);
1266 }
1267 
1268 #undef __FUNCT__
1269 #define __FUNCT__ "DMPlexGetConeOrientation"
1270 /*@C
1271   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1272 
1273   Not collective
1274 
1275   Input Parameters:
1276 + mesh - The DMPlex
1277 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1278 
1279   Output Parameter:
1280 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1281                     integer giving the prescription for cone traversal. If it is negative, the cone is
1282                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1283                     the index of the cone point on which to start.
1284 
1285   Level: beginner
1286 
1287   Note:
1288   This routine is not available in Fortran.
1289 
1290 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1291 @*/
1292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1293 {
1294   DM_Plex        *mesh = (DM_Plex*) dm->data;
1295   PetscInt       off;
1296   PetscErrorCode ierr;
1297 
1298   PetscFunctionBegin;
1299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1300 #if defined(PETSC_USE_DEBUG)
1301   {
1302     PetscInt dof;
1303     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1304     if (dof) PetscValidPointer(coneOrientation, 3);
1305   }
1306 #endif
1307   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1308 
1309   *coneOrientation = &mesh->coneOrientations[off];
1310   PetscFunctionReturn(0);
1311 }
1312 
1313 #undef __FUNCT__
1314 #define __FUNCT__ "DMPlexSetConeOrientation"
1315 /*@
1316   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1317 
1318   Not collective
1319 
1320   Input Parameters:
1321 + mesh - The DMPlex
1322 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1323 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1324                     integer giving the prescription for cone traversal. If it is negative, the cone is
1325                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1326                     the index of the cone point on which to start.
1327 
1328   Output Parameter:
1329 
1330   Note:
1331   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1332 
1333   Level: beginner
1334 
1335 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1336 @*/
1337 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1338 {
1339   DM_Plex        *mesh = (DM_Plex*) dm->data;
1340   PetscInt       pStart, pEnd;
1341   PetscInt       dof, off, c;
1342   PetscErrorCode ierr;
1343 
1344   PetscFunctionBegin;
1345   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1346   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1347   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1348   if (dof) PetscValidPointer(coneOrientation, 3);
1349   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1350   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);
1351   for (c = 0; c < dof; ++c) {
1352     PetscInt cdof, o = coneOrientation[c];
1353 
1354     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1355     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);
1356     mesh->coneOrientations[off+c] = o;
1357   }
1358   PetscFunctionReturn(0);
1359 }
1360 
1361 #undef __FUNCT__
1362 #define __FUNCT__ "DMPlexInsertCone"
1363 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1364 {
1365   DM_Plex        *mesh = (DM_Plex*) dm->data;
1366   PetscInt       pStart, pEnd;
1367   PetscInt       dof, off;
1368   PetscErrorCode ierr;
1369 
1370   PetscFunctionBegin;
1371   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1372   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1373   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1374   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1375   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);
1376   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);
1377   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);
1378   mesh->cones[off+conePos] = conePoint;
1379   PetscFunctionReturn(0);
1380 }
1381 
1382 #undef __FUNCT__
1383 #define __FUNCT__ "DMPlexGetSupportSize"
1384 /*@
1385   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1386 
1387   Not collective
1388 
1389   Input Parameters:
1390 + mesh - The DMPlex
1391 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1392 
1393   Output Parameter:
1394 . size - The support size for point p
1395 
1396   Level: beginner
1397 
1398 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1399 @*/
1400 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1401 {
1402   DM_Plex        *mesh = (DM_Plex*) dm->data;
1403   PetscErrorCode ierr;
1404 
1405   PetscFunctionBegin;
1406   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1407   PetscValidPointer(size, 3);
1408   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1409   PetscFunctionReturn(0);
1410 }
1411 
1412 #undef __FUNCT__
1413 #define __FUNCT__ "DMPlexSetSupportSize"
1414 /*@
1415   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1416 
1417   Not collective
1418 
1419   Input Parameters:
1420 + mesh - The DMPlex
1421 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1422 - size - The support size for point p
1423 
1424   Output Parameter:
1425 
1426   Note:
1427   This should be called after DMPlexSetChart().
1428 
1429   Level: beginner
1430 
1431 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1432 @*/
1433 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1434 {
1435   DM_Plex        *mesh = (DM_Plex*) dm->data;
1436   PetscErrorCode ierr;
1437 
1438   PetscFunctionBegin;
1439   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1440   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1441 
1442   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1443   PetscFunctionReturn(0);
1444 }
1445 
1446 #undef __FUNCT__
1447 #define __FUNCT__ "DMPlexGetSupport"
1448 /*@C
1449   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1450 
1451   Not collective
1452 
1453   Input Parameters:
1454 + mesh - The DMPlex
1455 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1456 
1457   Output Parameter:
1458 . support - An array of points which are on the out-edges for point p
1459 
1460   Level: beginner
1461 
1462 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1463 @*/
1464 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1465 {
1466   DM_Plex        *mesh = (DM_Plex*) dm->data;
1467   PetscInt       off;
1468   PetscErrorCode ierr;
1469 
1470   PetscFunctionBegin;
1471   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1472   PetscValidPointer(support, 3);
1473   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1474   *support = &mesh->supports[off];
1475   PetscFunctionReturn(0);
1476 }
1477 
1478 #undef __FUNCT__
1479 #define __FUNCT__ "DMPlexSetSupport"
1480 /*@
1481   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1482 
1483   Not collective
1484 
1485   Input Parameters:
1486 + mesh - The DMPlex
1487 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1488 - support - An array of points which are on the in-edges for point p
1489 
1490   Output Parameter:
1491 
1492   Note:
1493   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1494 
1495   Level: beginner
1496 
1497 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1498 @*/
1499 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1500 {
1501   DM_Plex        *mesh = (DM_Plex*) dm->data;
1502   PetscInt       pStart, pEnd;
1503   PetscInt       dof, off, c;
1504   PetscErrorCode ierr;
1505 
1506   PetscFunctionBegin;
1507   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1508   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1509   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1510   if (dof) PetscValidPointer(support, 3);
1511   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1512   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);
1513   for (c = 0; c < dof; ++c) {
1514     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);
1515     mesh->supports[off+c] = support[c];
1516   }
1517   PetscFunctionReturn(0);
1518 }
1519 
1520 #undef __FUNCT__
1521 #define __FUNCT__ "DMPlexInsertSupport"
1522 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1523 {
1524   DM_Plex        *mesh = (DM_Plex*) dm->data;
1525   PetscInt       pStart, pEnd;
1526   PetscInt       dof, off;
1527   PetscErrorCode ierr;
1528 
1529   PetscFunctionBegin;
1530   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1531   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1532   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1533   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1534   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);
1535   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);
1536   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);
1537   mesh->supports[off+supportPos] = supportPoint;
1538   PetscFunctionReturn(0);
1539 }
1540 
1541 #undef __FUNCT__
1542 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1543 /*@C
1544   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1545 
1546   Not collective
1547 
1548   Input Parameters:
1549 + mesh - The DMPlex
1550 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1551 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1552 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1553 
1554   Output Parameters:
1555 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1556 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1557 
1558   Note:
1559   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1560 
1561   Level: beginner
1562 
1563 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1564 @*/
1565 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1566 {
1567   DM_Plex        *mesh = (DM_Plex*) dm->data;
1568   PetscInt       *closure, *fifo;
1569   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1570   PetscInt       tmpSize, t;
1571   PetscInt       depth       = 0, maxSize;
1572   PetscInt       closureSize = 2, fifoSize = 0, fifoStart = 0;
1573   PetscErrorCode ierr;
1574 
1575   PetscFunctionBegin;
1576   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1577   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1578   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1579   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1580   if (*points) {
1581     closure = *points;
1582   } else {
1583     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1584   }
1585   closure[0] = p; closure[1] = 0;
1586   /* This is only 1-level */
1587   if (useCone) {
1588     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1589     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1590     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1591   } else {
1592     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1593     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1594   }
1595   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1596     const PetscInt cp = tmp[t];
1597     const PetscInt co = tmpO ? tmpO[t] : 0;
1598 
1599     closure[closureSize]   = cp;
1600     closure[closureSize+1] = co;
1601     fifo[fifoSize]         = cp;
1602     fifo[fifoSize+1]       = co;
1603   }
1604   while (fifoSize - fifoStart) {
1605     const PetscInt q   = fifo[fifoStart];
1606     const PetscInt o   = fifo[fifoStart+1];
1607     const PetscInt rev = o >= 0 ? 0 : 1;
1608     const PetscInt off = rev ? -(o+1) : o;
1609 
1610     if (useCone) {
1611       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1612       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1613       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1614     } else {
1615       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1616       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1617       tmpO = PETSC_NULL;
1618     }
1619     for (t = 0; t < tmpSize; ++t) {
1620       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1621       const PetscInt cp = tmp[i];
1622       /* Must propogate orientation */
1623       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1624       PetscInt       c;
1625 
1626       /* Check for duplicate */
1627       for (c = 0; c < closureSize; c += 2) {
1628         if (closure[c] == cp) break;
1629       }
1630       if (c == closureSize) {
1631         closure[closureSize]   = cp;
1632         closure[closureSize+1] = co;
1633         fifo[fifoSize]         = cp;
1634         fifo[fifoSize+1]       = co;
1635         closureSize           += 2;
1636         fifoSize              += 2;
1637       }
1638     }
1639     fifoStart += 2;
1640   }
1641   if (numPoints) *numPoints = closureSize/2;
1642   if (points)    *points    = closure;
1643   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1644   PetscFunctionReturn(0);
1645 }
1646 
1647 #undef __FUNCT__
1648 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1649 /*@C
1650   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1651 
1652   Not collective
1653 
1654   Input Parameters:
1655 + mesh - The DMPlex
1656 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1657 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1658 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1659 
1660   Output Parameters:
1661 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1662 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1663 
1664   Note:
1665   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1666 
1667   Level: beginner
1668 
1669 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1670 @*/
1671 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1672 {
1673   PetscErrorCode ierr;
1674 
1675   PetscFunctionBegin;
1676   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1677   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1678   PetscFunctionReturn(0);
1679 }
1680 
1681 #undef __FUNCT__
1682 #define __FUNCT__ "DMPlexGetFaces"
1683 /*
1684   DMPlexGetFaces -
1685 
1686   Note: This will only work for cell-vertex meshes.
1687 */
1688 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1689 {
1690   DM_Plex        *mesh = (DM_Plex*) dm->data;
1691   const PetscInt *cone = PETSC_NULL;
1692   PetscInt       depth = 0, dim, coneSize;
1693   PetscErrorCode ierr;
1694 
1695   PetscFunctionBegin;
1696   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1697   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1698   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1699   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1700   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1701   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1702   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1703   switch (dim) {
1704   case 2:
1705     switch (coneSize) {
1706     case 3:
1707       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1708       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1709       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1710       *numFaces         = 3;
1711       *faceSize         = 2;
1712       *faces            = mesh->facesTmp;
1713       break;
1714     case 4:
1715       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1716       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1717       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1718       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1719       *numFaces         = 4;
1720       *faceSize         = 2;
1721       *faces            = mesh->facesTmp;
1722       break;
1723     default:
1724       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1725     }
1726     break;
1727   case 3:
1728     switch (coneSize) {
1729     case 3:
1730       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1731       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1732       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1733       *numFaces         = 3;
1734       *faceSize         = 2;
1735       *faces            = mesh->facesTmp;
1736       break;
1737     case 4:
1738       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1739       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1740       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1741       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1742       *numFaces         = 4;
1743       *faceSize         = 3;
1744       *faces            = mesh->facesTmp;
1745       break;
1746     default:
1747       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1748     }
1749     break;
1750   default:
1751     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1752   }
1753   PetscFunctionReturn(0);
1754 }
1755 
1756 #undef __FUNCT__
1757 #define __FUNCT__ "DMPlexGetMaxSizes"
1758 /*@
1759   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1760 
1761   Not collective
1762 
1763   Input Parameter:
1764 . mesh - The DMPlex
1765 
1766   Output Parameters:
1767 + maxConeSize - The maximum number of in-edges
1768 - maxSupportSize - The maximum number of out-edges
1769 
1770   Level: beginner
1771 
1772 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1773 @*/
1774 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1775 {
1776   DM_Plex *mesh = (DM_Plex*) dm->data;
1777 
1778   PetscFunctionBegin;
1779   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1780   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1781   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1782   PetscFunctionReturn(0);
1783 }
1784 
1785 #undef __FUNCT__
1786 #define __FUNCT__ "DMSetUp_Plex"
1787 PetscErrorCode DMSetUp_Plex(DM dm)
1788 {
1789   DM_Plex        *mesh = (DM_Plex*) dm->data;
1790   PetscInt       size;
1791   PetscErrorCode ierr;
1792 
1793   PetscFunctionBegin;
1794   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1795   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1796   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1797   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1798   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1799   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1800   if (mesh->maxSupportSize) {
1801     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1802     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1803     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1804   }
1805   PetscFunctionReturn(0);
1806 }
1807 
1808 #undef __FUNCT__
1809 #define __FUNCT__ "DMCreateSubDM_Plex"
1810 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1811 {
1812   PetscSection   section, sectionGlobal;
1813   PetscInt       *subIndices;
1814   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1815   PetscErrorCode ierr;
1816 
1817   PetscFunctionBegin;
1818   if (!numFields) PetscFunctionReturn(0);
1819   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1820   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1821   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1822   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1823   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1824   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);
1825   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1826   for (p = pStart; p < pEnd; ++p) {
1827     PetscInt gdof;
1828 
1829     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1830     if (gdof > 0) {
1831       for (f = 0; f < numFields; ++f) {
1832         PetscInt fdof, fcdof;
1833 
1834         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1835         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1836         subSize += fdof-fcdof;
1837       }
1838     }
1839   }
1840   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1841   for (p = pStart; p < pEnd; ++p) {
1842     PetscInt gdof, goff;
1843 
1844     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1845     if (gdof > 0) {
1846       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1847       for (f = 0; f < numFields; ++f) {
1848         PetscInt fdof, fcdof, fc, f2, poff = 0;
1849 
1850         /* Can get rid of this loop by storing field information in the global section */
1851         for (f2 = 0; f2 < fields[f]; ++f2) {
1852           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1853           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1854           poff += fdof-fcdof;
1855         }
1856         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1857         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1858         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1859           subIndices[subOff] = goff+poff+fc;
1860         }
1861       }
1862     }
1863   }
1864   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1865   if (subdm) {
1866     PetscSection subsection;
1867     PetscBool    haveNull = PETSC_FALSE;
1868     PetscInt     f, nf = 0;
1869 
1870     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1871     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1872     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1873     for (f = 0; f < numFields; ++f) {
1874       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1875       if ((*subdm)->nullspaceConstructors[f]) {
1876         haveNull = PETSC_TRUE;
1877         nf       = f;
1878       }
1879     }
1880     if (haveNull) {
1881       MatNullSpace nullSpace;
1882 
1883       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1884       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1885       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1886     }
1887     if (dm->fields) {
1888       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);
1889       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1890       for (f = 0; f < numFields; ++f) {
1891         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1892       }
1893       if (numFields == 1) {
1894         MatNullSpace space;
1895         Mat          pmat;
1896 
1897         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1898         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1899         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1900         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1901         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1902         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1903       }
1904     }
1905   }
1906   PetscFunctionReturn(0);
1907 }
1908 
1909 #undef __FUNCT__
1910 #define __FUNCT__ "DMPlexSymmetrize"
1911 /*@
1912   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1913 
1914   Not collective
1915 
1916   Input Parameter:
1917 . mesh - The DMPlex
1918 
1919   Output Parameter:
1920 
1921   Note:
1922   This should be called after all calls to DMPlexSetCone()
1923 
1924   Level: beginner
1925 
1926 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1927 @*/
1928 PetscErrorCode DMPlexSymmetrize(DM dm)
1929 {
1930   DM_Plex        *mesh = (DM_Plex*) dm->data;
1931   PetscInt       *offsets;
1932   PetscInt       supportSize;
1933   PetscInt       pStart, pEnd, p;
1934   PetscErrorCode ierr;
1935 
1936   PetscFunctionBegin;
1937   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1938   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1939   /* Calculate support sizes */
1940   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1941   for (p = pStart; p < pEnd; ++p) {
1942     PetscInt dof, off, c;
1943 
1944     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1945     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1946     for (c = off; c < off+dof; ++c) {
1947       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1948     }
1949   }
1950   for (p = pStart; p < pEnd; ++p) {
1951     PetscInt dof;
1952 
1953     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1954 
1955     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1956   }
1957   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1958   /* Calculate supports */
1959   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1960   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1961   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1962   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1963   for (p = pStart; p < pEnd; ++p) {
1964     PetscInt dof, off, c;
1965 
1966     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1967     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1968     for (c = off; c < off+dof; ++c) {
1969       const PetscInt q = mesh->cones[c];
1970       PetscInt       offS;
1971 
1972       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1973 
1974       mesh->supports[offS+offsets[q]] = p;
1975       ++offsets[q];
1976     }
1977   }
1978   ierr = PetscFree(offsets);CHKERRQ(ierr);
1979   PetscFunctionReturn(0);
1980 }
1981 
1982 #undef __FUNCT__
1983 #define __FUNCT__ "DMPlexSetDepth_Private"
1984 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1985 {
1986   PetscInt       d;
1987   PetscErrorCode ierr;
1988 
1989   PetscFunctionBegin;
1990   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1991   if (d < 0) {
1992     /* We are guaranteed that the point has a cone since the depth was not yet set */
1993     const PetscInt *cone = PETSC_NULL;
1994     PetscInt       dCone;
1995 
1996     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1997     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1998     d    = dCone+1;
1999     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2000   }
2001   *depth = d;
2002   PetscFunctionReturn(0);
2003 }
2004 
2005 #undef __FUNCT__
2006 #define __FUNCT__ "DMPlexStratify"
2007 /*@
2008   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2009   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2010   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2011   the DAG.
2012 
2013   Not collective
2014 
2015   Input Parameter:
2016 . mesh - The DMPlex
2017 
2018   Output Parameter:
2019 
2020   Notes:
2021   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2022   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2023 
2024   This should be called after all calls to DMPlexSymmetrize()
2025 
2026   Level: beginner
2027 
2028 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2029 @*/
2030 PetscErrorCode DMPlexStratify(DM dm)
2031 {
2032   DM_Plex        *mesh = (DM_Plex*) dm->data;
2033   PetscInt       pStart, pEnd, p;
2034   PetscInt       numRoots = 0, numLeaves = 0;
2035   PetscErrorCode ierr;
2036 
2037   PetscFunctionBegin;
2038   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2039   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2040   /* Calculate depth */
2041   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2042   /* Initialize roots and count leaves */
2043   for (p = pStart; p < pEnd; ++p) {
2044     PetscInt coneSize, supportSize;
2045 
2046     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2047     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2048     if (!coneSize && supportSize) {
2049       ++numRoots;
2050       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2051     } else if (!supportSize && coneSize) {
2052       ++numLeaves;
2053     } else if (!supportSize && !coneSize) {
2054       /* Isolated points */
2055       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2056     }
2057   }
2058   if (numRoots + numLeaves == (pEnd - pStart)) {
2059     for (p = pStart; p < pEnd; ++p) {
2060       PetscInt coneSize, supportSize;
2061 
2062       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2063       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2064       if (!supportSize && coneSize) {
2065         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2066       }
2067     }
2068   } else {
2069     /* This might be slow since lookup is not fast */
2070     for (p = pStart; p < pEnd; ++p) {
2071       PetscInt depth;
2072 
2073       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2074     }
2075   }
2076   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2077   PetscFunctionReturn(0);
2078 }
2079 
2080 #undef __FUNCT__
2081 #define __FUNCT__ "DMPlexGetJoin"
2082 /*@C
2083   DMPlexGetJoin - Get an array for the join of the set of points
2084 
2085   Not Collective
2086 
2087   Input Parameters:
2088 + dm - The DMPlex object
2089 . numPoints - The number of input points for the join
2090 - points - The input points
2091 
2092   Output Parameters:
2093 + numCoveredPoints - The number of points in the join
2094 - coveredPoints - The points in the join
2095 
2096   Level: intermediate
2097 
2098   Note: Currently, this is restricted to a single level join
2099 
2100 .keywords: mesh
2101 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2102 @*/
2103 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2104 {
2105   DM_Plex        *mesh = (DM_Plex*) dm->data;
2106   PetscInt       *join[2];
2107   PetscInt       joinSize, i = 0;
2108   PetscInt       dof, off, p, c, m;
2109   PetscErrorCode ierr;
2110 
2111   PetscFunctionBegin;
2112   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2113   PetscValidPointer(points, 2);
2114   PetscValidPointer(numCoveredPoints, 3);
2115   PetscValidPointer(coveredPoints, 4);
2116   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2117   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2118   /* Copy in support of first point */
2119   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2120   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2121   for (joinSize = 0; joinSize < dof; ++joinSize) {
2122     join[i][joinSize] = mesh->supports[off+joinSize];
2123   }
2124   /* Check each successive support */
2125   for (p = 1; p < numPoints; ++p) {
2126     PetscInt newJoinSize = 0;
2127 
2128     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2129     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2130     for (c = 0; c < dof; ++c) {
2131       const PetscInt point = mesh->supports[off+c];
2132 
2133       for (m = 0; m < joinSize; ++m) {
2134         if (point == join[i][m]) {
2135           join[1-i][newJoinSize++] = point;
2136           break;
2137         }
2138       }
2139     }
2140     joinSize = newJoinSize;
2141     i        = 1-i;
2142   }
2143   *numCoveredPoints = joinSize;
2144   *coveredPoints    = join[i];
2145   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2146   PetscFunctionReturn(0);
2147 }
2148 
2149 #undef __FUNCT__
2150 #define __FUNCT__ "DMPlexRestoreJoin"
2151 /*@C
2152   DMPlexRestoreJoin - Restore an array for the join of the set of points
2153 
2154   Not Collective
2155 
2156   Input Parameters:
2157 + dm - The DMPlex object
2158 . numPoints - The number of input points for the join
2159 - points - The input points
2160 
2161   Output Parameters:
2162 + numCoveredPoints - The number of points in the join
2163 - coveredPoints - The points in the join
2164 
2165   Level: intermediate
2166 
2167 .keywords: mesh
2168 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2169 @*/
2170 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2171 {
2172   PetscErrorCode ierr;
2173 
2174   PetscFunctionBegin;
2175   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2176   PetscValidPointer(coveredPoints, 4);
2177   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2178   PetscFunctionReturn(0);
2179 }
2180 
2181 #undef __FUNCT__
2182 #define __FUNCT__ "DMPlexGetFullJoin"
2183 /*@C
2184   DMPlexGetFullJoin - Get an array for the join of the set of points
2185 
2186   Not Collective
2187 
2188   Input Parameters:
2189 + dm - The DMPlex object
2190 . numPoints - The number of input points for the join
2191 - points - The input points
2192 
2193   Output Parameters:
2194 + numCoveredPoints - The number of points in the join
2195 - coveredPoints - The points in the join
2196 
2197   Level: intermediate
2198 
2199 .keywords: mesh
2200 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2201 @*/
2202 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2203 {
2204   DM_Plex        *mesh = (DM_Plex*) dm->data;
2205   PetscInt       *offsets, **closures;
2206   PetscInt       *join[2];
2207   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2208   PetscInt       p, d, c, m;
2209   PetscErrorCode ierr;
2210 
2211   PetscFunctionBegin;
2212   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2213   PetscValidPointer(points, 2);
2214   PetscValidPointer(numCoveredPoints, 3);
2215   PetscValidPointer(coveredPoints, 4);
2216 
2217   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2218   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2219   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2220   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2221   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2222   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2223   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2224 
2225   for (p = 0; p < numPoints; ++p) {
2226     PetscInt closureSize;
2227 
2228     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2229 
2230     offsets[p*(depth+2)+0] = 0;
2231     for (d = 0; d < depth+1; ++d) {
2232       PetscInt pStart, pEnd, i;
2233 
2234       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2235       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2236         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2237           offsets[p*(depth+2)+d+1] = i;
2238           break;
2239         }
2240       }
2241       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2242     }
2243     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);
2244   }
2245   for (d = 0; d < depth+1; ++d) {
2246     PetscInt dof;
2247 
2248     /* Copy in support of first point */
2249     dof = offsets[d+1] - offsets[d];
2250     for (joinSize = 0; joinSize < dof; ++joinSize) {
2251       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2252     }
2253     /* Check each successive cone */
2254     for (p = 1; p < numPoints && joinSize; ++p) {
2255       PetscInt newJoinSize = 0;
2256 
2257       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2258       for (c = 0; c < dof; ++c) {
2259         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2260 
2261         for (m = 0; m < joinSize; ++m) {
2262           if (point == join[i][m]) {
2263             join[1-i][newJoinSize++] = point;
2264             break;
2265           }
2266         }
2267       }
2268       joinSize = newJoinSize;
2269       i        = 1-i;
2270     }
2271     if (joinSize) break;
2272   }
2273   *numCoveredPoints = joinSize;
2274   *coveredPoints    = join[i];
2275   for (p = 0; p < numPoints; ++p) {
2276     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2277   }
2278   ierr = PetscFree(closures);CHKERRQ(ierr);
2279   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2280   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2281   PetscFunctionReturn(0);
2282 }
2283 
2284 #undef __FUNCT__
2285 #define __FUNCT__ "DMPlexGetMeet"
2286 /*@C
2287   DMPlexGetMeet - Get an array for the meet of the set of points
2288 
2289   Not Collective
2290 
2291   Input Parameters:
2292 + dm - The DMPlex object
2293 . numPoints - The number of input points for the meet
2294 - points - The input points
2295 
2296   Output Parameters:
2297 + numCoveredPoints - The number of points in the meet
2298 - coveredPoints - The points in the meet
2299 
2300   Level: intermediate
2301 
2302   Note: Currently, this is restricted to a single level meet
2303 
2304 .keywords: mesh
2305 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2306 @*/
2307 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2308 {
2309   DM_Plex        *mesh = (DM_Plex*) dm->data;
2310   PetscInt       *meet[2];
2311   PetscInt       meetSize, i = 0;
2312   PetscInt       dof, off, p, c, m;
2313   PetscErrorCode ierr;
2314 
2315   PetscFunctionBegin;
2316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2317   PetscValidPointer(points, 2);
2318   PetscValidPointer(numCoveringPoints, 3);
2319   PetscValidPointer(coveringPoints, 4);
2320   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2321   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2322   /* Copy in cone of first point */
2323   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2324   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2325   for (meetSize = 0; meetSize < dof; ++meetSize) {
2326     meet[i][meetSize] = mesh->cones[off+meetSize];
2327   }
2328   /* Check each successive cone */
2329   for (p = 1; p < numPoints; ++p) {
2330     PetscInt newMeetSize = 0;
2331 
2332     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2333     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2334     for (c = 0; c < dof; ++c) {
2335       const PetscInt point = mesh->cones[off+c];
2336 
2337       for (m = 0; m < meetSize; ++m) {
2338         if (point == meet[i][m]) {
2339           meet[1-i][newMeetSize++] = point;
2340           break;
2341         }
2342       }
2343     }
2344     meetSize = newMeetSize;
2345     i        = 1-i;
2346   }
2347   *numCoveringPoints = meetSize;
2348   *coveringPoints    = meet[i];
2349   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2350   PetscFunctionReturn(0);
2351 }
2352 
2353 #undef __FUNCT__
2354 #define __FUNCT__ "DMPlexRestoreMeet"
2355 /*@C
2356   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2357 
2358   Not Collective
2359 
2360   Input Parameters:
2361 + dm - The DMPlex object
2362 . numPoints - The number of input points for the meet
2363 - points - The input points
2364 
2365   Output Parameters:
2366 + numCoveredPoints - The number of points in the meet
2367 - coveredPoints - The points in the meet
2368 
2369   Level: intermediate
2370 
2371 .keywords: mesh
2372 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2373 @*/
2374 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2375 {
2376   PetscErrorCode ierr;
2377 
2378   PetscFunctionBegin;
2379   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2380   PetscValidPointer(coveredPoints, 4);
2381   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2382   PetscFunctionReturn(0);
2383 }
2384 
2385 #undef __FUNCT__
2386 #define __FUNCT__ "DMPlexGetFullMeet"
2387 /*@C
2388   DMPlexGetFullMeet - Get an array for the meet of the set of points
2389 
2390   Not Collective
2391 
2392   Input Parameters:
2393 + dm - The DMPlex object
2394 . numPoints - The number of input points for the meet
2395 - points - The input points
2396 
2397   Output Parameters:
2398 + numCoveredPoints - The number of points in the meet
2399 - coveredPoints - The points in the meet
2400 
2401   Level: intermediate
2402 
2403 .keywords: mesh
2404 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2405 @*/
2406 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2407 {
2408   DM_Plex        *mesh = (DM_Plex*) dm->data;
2409   PetscInt       *offsets, **closures;
2410   PetscInt       *meet[2];
2411   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2412   PetscInt       p, h, c, m;
2413   PetscErrorCode ierr;
2414 
2415   PetscFunctionBegin;
2416   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2417   PetscValidPointer(points, 2);
2418   PetscValidPointer(numCoveredPoints, 3);
2419   PetscValidPointer(coveredPoints, 4);
2420 
2421   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2422   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2423   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2424   maxSize = PetscPowInt(mesh->maxConeSize,height);
2425   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2426   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2427 
2428   for (p = 0; p < numPoints; ++p) {
2429     PetscInt closureSize;
2430 
2431     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2432 
2433     offsets[p*(height+2)+0] = 0;
2434     for (h = 0; h < height+1; ++h) {
2435       PetscInt pStart, pEnd, i;
2436 
2437       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2438       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2439         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2440           offsets[p*(height+2)+h+1] = i;
2441           break;
2442         }
2443       }
2444       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2445     }
2446     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);
2447   }
2448   for (h = 0; h < height+1; ++h) {
2449     PetscInt dof;
2450 
2451     /* Copy in cone of first point */
2452     dof = offsets[h+1] - offsets[h];
2453     for (meetSize = 0; meetSize < dof; ++meetSize) {
2454       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2455     }
2456     /* Check each successive cone */
2457     for (p = 1; p < numPoints && meetSize; ++p) {
2458       PetscInt newMeetSize = 0;
2459 
2460       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2461       for (c = 0; c < dof; ++c) {
2462         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2463 
2464         for (m = 0; m < meetSize; ++m) {
2465           if (point == meet[i][m]) {
2466             meet[1-i][newMeetSize++] = point;
2467             break;
2468           }
2469         }
2470       }
2471       meetSize = newMeetSize;
2472       i        = 1-i;
2473     }
2474     if (meetSize) break;
2475   }
2476   *numCoveredPoints = meetSize;
2477   *coveredPoints    = meet[i];
2478   for (p = 0; p < numPoints; ++p) {
2479     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2480   }
2481   ierr = PetscFree(closures);CHKERRQ(ierr);
2482   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2483   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2484   PetscFunctionReturn(0);
2485 }
2486 
2487 #undef __FUNCT__
2488 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2489 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2490 {
2491   MPI_Comm       comm = ((PetscObject) dm)->comm;
2492   PetscInt       cellDim;
2493   PetscErrorCode ierr;
2494 
2495   PetscFunctionBegin;
2496   PetscValidPointer(numFaceVertices,3);
2497   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2498   switch (cellDim) {
2499   case 0:
2500     *numFaceVertices = 0;
2501     break;
2502   case 1:
2503     *numFaceVertices = 1;
2504     break;
2505   case 2:
2506     switch (numCorners) {
2507     case 3: /* triangle */
2508       *numFaceVertices = 2; /* Edge has 2 vertices */
2509       break;
2510     case 4: /* quadrilateral */
2511       *numFaceVertices = 2; /* Edge has 2 vertices */
2512       break;
2513     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2514       *numFaceVertices = 3; /* Edge has 3 vertices */
2515       break;
2516     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2517       *numFaceVertices = 3; /* Edge has 3 vertices */
2518       break;
2519     default:
2520       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2521     }
2522     break;
2523   case 3:
2524     switch (numCorners) {
2525     case 4: /* tetradehdron */
2526       *numFaceVertices = 3; /* Face has 3 vertices */
2527       break;
2528     case 6: /* tet cohesive cells */
2529       *numFaceVertices = 4; /* Face has 4 vertices */
2530       break;
2531     case 8: /* hexahedron */
2532       *numFaceVertices = 4; /* Face has 4 vertices */
2533       break;
2534     case 9: /* tet cohesive Lagrange cells */
2535       *numFaceVertices = 6; /* Face has 6 vertices */
2536       break;
2537     case 10: /* quadratic tetrahedron */
2538       *numFaceVertices = 6; /* Face has 6 vertices */
2539       break;
2540     case 12: /* hex cohesive Lagrange cells */
2541       *numFaceVertices = 6; /* Face has 6 vertices */
2542       break;
2543     case 18: /* quadratic tet cohesive Lagrange cells */
2544       *numFaceVertices = 6; /* Face has 6 vertices */
2545       break;
2546     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2547       *numFaceVertices = 9; /* Face has 9 vertices */
2548       break;
2549     default:
2550       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2551     }
2552     break;
2553   default:
2554     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2555   }
2556   PetscFunctionReturn(0);
2557 }
2558 
2559 #undef __FUNCT__
2560 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2561 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2562 {
2563   const PetscInt maxFaceCases = 30;
2564   PetscInt       numFaceCases = 0;
2565   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2566   PetscInt       *off, *adj;
2567   PetscInt       *neighborCells, *tmpClosure;
2568   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2569   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2570   PetscErrorCode ierr;
2571 
2572   PetscFunctionBegin;
2573   /* For parallel partitioning, I think you have to communicate supports */
2574   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2575   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2576   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2577   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2578   if (cEnd - cStart == 0) {
2579     if (numVertices) *numVertices = 0;
2580     if (offsets)   *offsets   = PETSC_NULL;
2581     if (adjacency) *adjacency = PETSC_NULL;
2582     PetscFunctionReturn(0);
2583   }
2584   numCells = cEnd - cStart;
2585   /* Setup face recognition */
2586   if (depth == 1) {
2587     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 */
2588 
2589     for (c = cStart; c < cEnd; ++c) {
2590       PetscInt corners;
2591 
2592       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2593       if (!cornersSeen[corners]) {
2594         PetscInt nFV;
2595 
2596         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2597         cornersSeen[corners] = 1;
2598 
2599         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2600 
2601         numFaceVertices[numFaceCases++] = nFV;
2602       }
2603     }
2604   }
2605   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2606   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2607   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2608   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2609   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2610   /* Count neighboring cells */
2611   for (cell = cStart; cell < cEnd; ++cell) {
2612     PetscInt numNeighbors = maxNeighbors, n;
2613 
2614     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2615     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2616     for (n = 0; n < numNeighbors; ++n) {
2617       PetscInt       cellPair[2];
2618       PetscBool      found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2619       PetscInt       meetSize = 0;
2620       const PetscInt *meet    = PETSC_NULL;
2621 
2622       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2623       if (cellPair[0] == cellPair[1]) continue;
2624       if (!found) {
2625         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2626         if (meetSize) {
2627           PetscInt f;
2628 
2629           for (f = 0; f < numFaceCases; ++f) {
2630             if (numFaceVertices[f] == meetSize) {
2631               found = PETSC_TRUE;
2632               break;
2633             }
2634           }
2635         }
2636         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2637       }
2638       if (found) ++off[cell-cStart+1];
2639     }
2640   }
2641   /* Prefix sum */
2642   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2643 
2644   if (adjacency) {
2645     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2646     /* Get neighboring cells */
2647     for (cell = cStart; cell < cEnd; ++cell) {
2648       PetscInt numNeighbors = maxNeighbors, n;
2649       PetscInt cellOffset   = 0;
2650 
2651       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2652       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2653       for (n = 0; n < numNeighbors; ++n) {
2654         PetscInt       cellPair[2];
2655         PetscBool      found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2656         PetscInt       meetSize = 0;
2657         const PetscInt *meet    = PETSC_NULL;
2658 
2659         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2660         if (cellPair[0] == cellPair[1]) continue;
2661         if (!found) {
2662           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2663           if (meetSize) {
2664             PetscInt f;
2665 
2666             for (f = 0; f < numFaceCases; ++f) {
2667               if (numFaceVertices[f] == meetSize) {
2668                 found = PETSC_TRUE;
2669                 break;
2670               }
2671             }
2672           }
2673           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2674         }
2675         if (found) {
2676           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2677           ++cellOffset;
2678         }
2679       }
2680     }
2681   }
2682   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2683   if (numVertices) *numVertices = numCells;
2684   if (offsets)   *offsets   = off;
2685   if (adjacency) *adjacency = adj;
2686   PetscFunctionReturn(0);
2687 }
2688 
2689 #if defined(PETSC_HAVE_CHACO)
2690 #if defined(PETSC_HAVE_UNISTD_H)
2691 #include <unistd.h>
2692 #endif
2693 /* Chaco does not have an include file */
2694 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2695                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2696                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2697                        int mesh_dims[3], double *goal, int global_method, int local_method,
2698                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2699 
2700 extern int FREE_GRAPH;
2701 
2702 #undef __FUNCT__
2703 #define __FUNCT__ "DMPlexPartition_Chaco"
2704 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2705 {
2706   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2707   MPI_Comm       comm           = ((PetscObject) dm)->comm;
2708   int            nvtxs          = numVertices; /* number of vertices in full graph */
2709   int            *vwgts         = NULL;   /* weights for all vertices */
2710   float          *ewgts         = NULL;   /* weights for all edges */
2711   float          *x             = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2712   char           *outassignname = NULL;   /*  name of assignment output file */
2713   char           *outfilename   = NULL;   /* output file name */
2714   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2715   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2716   int            mesh_dims[3];            /* dimensions of mesh of processors */
2717   double         *goal         = NULL;    /* desired set sizes for each set */
2718   int            global_method = 1;       /* global partitioning algorithm */
2719   int            local_method  = 1;       /* local partitioning algorithm */
2720   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2721   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2722   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2723   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2724   long           seed          = 123636512; /* for random graph mutations */
2725   short int      *assignment;             /* Output partition */
2726   int            fd_stdout, fd_pipe[2];
2727   PetscInt       *points;
2728   PetscMPIInt    commSize;
2729   int            i, v, p;
2730   PetscErrorCode ierr;
2731 
2732   PetscFunctionBegin;
2733   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2734   if (!numVertices) {
2735     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2736     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2737     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2738     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2739     PetscFunctionReturn(0);
2740   }
2741   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2742   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2743 
2744   if (global_method == INERTIAL_METHOD) {
2745     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2746     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2747   }
2748   mesh_dims[0] = commSize;
2749   mesh_dims[1] = 1;
2750   mesh_dims[2] = 1;
2751   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2752   /* Chaco outputs to stdout. We redirect this to a buffer. */
2753   /* TODO: check error codes for UNIX calls */
2754 #if defined(PETSC_HAVE_UNISTD_H)
2755   {
2756     int piperet;
2757     piperet = pipe(fd_pipe);
2758     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2759     fd_stdout = dup(1);
2760     close(1);
2761     dup2(fd_pipe[1], 1);
2762   }
2763 #endif
2764   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2765                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2766                    vmax, ndims, eigtol, seed);
2767 #if defined(PETSC_HAVE_UNISTD_H)
2768   {
2769     char msgLog[10000];
2770     int  count;
2771 
2772     fflush(stdout);
2773     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2774     if (count < 0) count = 0;
2775     msgLog[count] = 0;
2776     close(1);
2777     dup2(fd_stdout, 1);
2778     close(fd_stdout);
2779     close(fd_pipe[0]);
2780     close(fd_pipe[1]);
2781     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2782   }
2783 #endif
2784   /* Convert to PetscSection+IS */
2785   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2786   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2787   for (v = 0; v < nvtxs; ++v) {
2788     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2789   }
2790   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2791   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2792   for (p = 0, i = 0; p < commSize; ++p) {
2793     for (v = 0; v < nvtxs; ++v) {
2794       if (assignment[v] == p) points[i++] = v;
2795     }
2796   }
2797   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2798   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2799   if (global_method == INERTIAL_METHOD) {
2800     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2801   }
2802   ierr = PetscFree(assignment);CHKERRQ(ierr);
2803   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2804   PetscFunctionReturn(0);
2805 }
2806 #endif
2807 
2808 #if defined(PETSC_HAVE_PARMETIS)
2809 #undef __FUNCT__
2810 #define __FUNCT__ "DMPlexPartition_ParMetis"
2811 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2812 {
2813   PetscFunctionBegin;
2814   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2815   PetscFunctionReturn(0);
2816 }
2817 #endif
2818 
2819 #undef __FUNCT__
2820 #define __FUNCT__ "DMPlexEnlargePartition"
2821 /* Expand the partition by BFS on the adjacency graph */
2822 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2823 {
2824   PetscHashI     h;
2825   const PetscInt *points;
2826   PetscInt       **tmpPoints, *newPoints, totPoints = 0;
2827   PetscInt       pStart, pEnd, part, q;
2828   PetscErrorCode ierr;
2829 
2830   PetscFunctionBegin;
2831   PetscHashICreate(h);
2832   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2833   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2834   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2835   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2836   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2837   for (part = pStart; part < pEnd; ++part) {
2838     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2839 
2840     PetscHashIClear(h);
2841     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2842     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2843     /* Add all existing points to h */
2844     for (p = 0; p < numPoints; ++p) {
2845       const PetscInt point = points[off+p];
2846       PetscHashIAdd(h, point, 1);
2847     }
2848     PetscHashISize(h, nP);
2849     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2850     /* Add all points in next BFS level */
2851     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2852     for (p = 0; p < numPoints; ++p) {
2853       const PetscInt point = points[off+p];
2854       PetscInt       s     = start[point], e = start[point+1], a;
2855 
2856       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2857     }
2858     PetscHashISize(h, numNewPoints);
2859     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2860     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2861     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2862     totPoints += numNewPoints;
2863   }
2864   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2865   PetscHashIDestroy(h);
2866   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2867   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2868   for (part = pStart, q = 0; part < pEnd; ++part) {
2869     PetscInt numPoints, p;
2870 
2871     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2872     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2873     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2874   }
2875   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2876   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2877   PetscFunctionReturn(0);
2878 }
2879 
2880 #undef __FUNCT__
2881 #define __FUNCT__ "DMPlexCreatePartition"
2882 /*
2883   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2884 
2885   Collective on DM
2886 
2887   Input Parameters:
2888   + dm - The DM
2889   . height - The height for points in the partition
2890   - enlarge - Expand each partition with neighbors
2891 
2892   Output Parameters:
2893   + partSection - The PetscSection giving the division of points by partition
2894   . partition - The list of points by partition
2895   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2896   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2897 
2898   Level: developer
2899 
2900 .seealso DMPlexDistribute()
2901 */
2902 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2903 {
2904   PetscMPIInt    size;
2905   PetscErrorCode ierr;
2906 
2907   PetscFunctionBegin;
2908   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2909 
2910   *origPartSection = PETSC_NULL;
2911   *origPartition   = PETSC_NULL;
2912   if (size == 1) {
2913     PetscInt *points;
2914     PetscInt cStart, cEnd, c;
2915 
2916     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2917     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2918     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2919     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2920     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2921     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2922     for (c = cStart; c < cEnd; ++c) points[c] = c;
2923     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2924     PetscFunctionReturn(0);
2925   }
2926   if (height == 0) {
2927     PetscInt numVertices;
2928     PetscInt *start     = PETSC_NULL;
2929     PetscInt *adjacency = PETSC_NULL;
2930 
2931     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2932     if (1) {
2933 #if defined(PETSC_HAVE_CHACO)
2934       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2935 #endif
2936     } else {
2937 #if defined(PETSC_HAVE_PARMETIS)
2938       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2939 #endif
2940     }
2941     if (enlarge) {
2942       *origPartSection = *partSection;
2943       *origPartition   = *partition;
2944 
2945       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2946     }
2947     ierr = PetscFree(start);CHKERRQ(ierr);
2948     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2949 # if 0
2950   } else if (height == 1) {
2951     /* Build the dual graph for faces and partition the hypergraph */
2952     PetscInt numEdges;
2953 
2954     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2955     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2956     destroyCSR(numEdges, start, adjacency);
2957 #endif
2958   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2959   PetscFunctionReturn(0);
2960 }
2961 
2962 #undef __FUNCT__
2963 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2964 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2965 {
2966   /* const PetscInt  height = 0; */
2967   const PetscInt *partArray;
2968   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2969   PetscInt       rStart, rEnd, rank, maxPartSize = 0, newSize;
2970   PetscErrorCode ierr;
2971 
2972   PetscFunctionBegin;
2973   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2974   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2975   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2976   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2977   for (rank = rStart; rank < rEnd; ++rank) {
2978     PetscInt partSize = 0;
2979     PetscInt numPoints, offset, p;
2980 
2981     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2982     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2983     for (p = 0; p < numPoints; ++p) {
2984       PetscInt point    = partArray[offset+p], closureSize, c;
2985       PetscInt *closure = PETSC_NULL;
2986 
2987       /* TODO Include support for height > 0 case */
2988       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2989       /* Merge into existing points */
2990       if (partSize+closureSize > maxPartSize) {
2991         PetscInt *tmpPoints;
2992 
2993         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2994         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2995         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2996         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2997 
2998         partPoints = tmpPoints;
2999       }
3000       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3001       partSize += closureSize;
3002 
3003       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3004       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3005     }
3006     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3007   }
3008   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3009   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3010   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3011 
3012   for (rank = rStart; rank < rEnd; ++rank) {
3013     PetscInt partSize = 0, newOffset;
3014     PetscInt numPoints, offset, p;
3015 
3016     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3017     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3018     for (p = 0; p < numPoints; ++p) {
3019       PetscInt point    = partArray[offset+p], closureSize, c;
3020       PetscInt *closure = PETSC_NULL;
3021 
3022       /* TODO Include support for height > 0 case */
3023       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3024       /* Merge into existing points */
3025       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3026       partSize += closureSize;
3027 
3028       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3029       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3030     }
3031     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3032     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3033   }
3034   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3035   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3036   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3037   PetscFunctionReturn(0);
3038 }
3039 
3040 #undef __FUNCT__
3041 #define __FUNCT__ "DMPlexDistributeField"
3042 /*
3043   Input Parameters:
3044 . originalSection
3045 , originalVec
3046 
3047   Output Parameters:
3048 . newSection
3049 . newVec
3050 */
3051 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3052 {
3053   PetscSF        fieldSF;
3054   PetscInt       *remoteOffsets, fieldSize;
3055   PetscScalar    *originalValues, *newValues;
3056   PetscErrorCode ierr;
3057 
3058   PetscFunctionBegin;
3059   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3060 
3061   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3062   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3063   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3064 
3065   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3066   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3067   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3068   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3069   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3070   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3071   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3072   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3073   PetscFunctionReturn(0);
3074 }
3075 
3076 #undef __FUNCT__
3077 #define __FUNCT__ "DMPlexDistribute"
3078 /*@C
3079   DMPlexDistribute - Distributes the mesh and any associated sections.
3080 
3081   Not Collective
3082 
3083   Input Parameter:
3084 + dm  - The original DMPlex object
3085 . partitioner - The partitioning package, or NULL for the default
3086 - overlap - The overlap of partitions, 0 is the default
3087 
3088   Output Parameter:
3089 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3090 
3091   Note: If the mesh was not distributed, the return value is PETSC_NULL
3092 
3093   Level: intermediate
3094 
3095 .keywords: mesh, elements
3096 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3097 @*/
3098 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3099 {
3100   DM_Plex                *mesh  = (DM_Plex*) dm->data, *pmesh;
3101   MPI_Comm               comm   = ((PetscObject) dm)->comm;
3102   const PetscInt         height = 0;
3103   PetscInt               dim, numRemoteRanks;
3104   IS                     origCellPart,        cellPart,        part;
3105   PetscSection           origCellPartSection, cellPartSection, partSection;
3106   PetscSFNode            *remoteRanks;
3107   PetscSF                partSF, pointSF, coneSF;
3108   ISLocalToGlobalMapping renumbering;
3109   PetscSection           originalConeSection, newConeSection;
3110   PetscInt               *remoteOffsets;
3111   PetscInt               *cones, *newCones, newConesSize;
3112   PetscBool              flg;
3113   PetscMPIInt            rank, numProcs, p;
3114   PetscErrorCode         ierr;
3115 
3116   PetscFunctionBegin;
3117   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3118   PetscValidPointer(dmParallel,4);
3119 
3120   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3121   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3122   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3123 
3124   *dmParallel = PETSC_NULL;
3125   if (numProcs == 1) PetscFunctionReturn(0);
3126 
3127   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3128   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3129   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3130   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3131   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3132   if (!rank) numRemoteRanks = numProcs;
3133   else       numRemoteRanks = 0;
3134   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3135   for (p = 0; p < numRemoteRanks; ++p) {
3136     remoteRanks[p].rank  = p;
3137     remoteRanks[p].index = 0;
3138   }
3139   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3140   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3141   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3142   if (flg) {
3143     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3144     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3145     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3146     if (origCellPart) {
3147       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3148       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3149       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3150     }
3151     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3152   }
3153   /* Close the partition over the mesh */
3154   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3155   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3156   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3157   /* Create new mesh */
3158   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3159   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3160   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3161   pmesh = (DM_Plex*) (*dmParallel)->data;
3162   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3163   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3164   if (flg) {
3165     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3166     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3167     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3168     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3169     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3170     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3171   }
3172   /* Distribute cone section */
3173   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3174   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3175   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3176   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3177   {
3178     PetscInt pStart, pEnd, p;
3179 
3180     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3181     for (p = pStart; p < pEnd; ++p) {
3182       PetscInt coneSize;
3183       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3184       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3185     }
3186   }
3187   /* Communicate and renumber cones */
3188   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3189   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3190   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3191   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3192   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3193   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3194   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3195   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3196   if (flg) {
3197     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3198     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3199     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3200     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3201     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3202   }
3203   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3204   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3205   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3206   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3207   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3208   /* Create supports and stratify sieve */
3209   {
3210     PetscInt pStart, pEnd;
3211 
3212     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3213     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3214   }
3215   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3216   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3217   /* Distribute Coordinates */
3218   {
3219     PetscSection originalCoordSection, newCoordSection;
3220     Vec          originalCoordinates, newCoordinates;
3221     const char   *name;
3222 
3223     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3224     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3225     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3226     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3227     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3228     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3229 
3230     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3231     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3232     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3233   }
3234   /* Distribute labels */
3235   {
3236     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3237     PetscInt numLabels = 0, l;
3238 
3239     /* Bcast number of labels */
3240     while (next) {
3241       ++numLabels; next = next->next;
3242     }
3243     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3244     next = mesh->labels;
3245     for (l = 0; l < numLabels; ++l) {
3246       DMLabel        newLabel;
3247       const PetscInt *partArray;
3248       char           *name;
3249       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3250       PetscMPIInt    *sendcnts     = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3251       PetscInt       nameSize, s, p;
3252       PetscBool      isdepth;
3253       size_t         len = 0;
3254 
3255       /* Bcast name (could filter for no points) */
3256       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3257       nameSize = len;
3258       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3259       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3260       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3261       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3262       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3263       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3264       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3265       newLabel->name = name;
3266       /* Bcast numStrata (could filter for no points in stratum) */
3267       if (!rank) newLabel->numStrata = next->numStrata;
3268       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3269       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3270                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3271                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3272       /* Bcast stratumValues (could filter for no points in stratum) */
3273       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3274       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3275       /* Find size on each process and Scatter */
3276       if (!rank) {
3277         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3278         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3279         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3280         for (s = 0; s < next->numStrata; ++s) {
3281           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3282             const PetscInt point = next->points[p];
3283             PetscInt       proc;
3284 
3285             for (proc = 0; proc < numProcs; ++proc) {
3286               PetscInt dof, off, pPart;
3287 
3288               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3289               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3290               for (pPart = off; pPart < off+dof; ++pPart) {
3291                 if (partArray[pPart] == point) {
3292                   ++stratumSizes[proc*next->numStrata+s];
3293                   break;
3294                 }
3295               }
3296             }
3297           }
3298         }
3299         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3300       }
3301       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3302       /* Calculate stratumOffsets */
3303       newLabel->stratumOffsets[0] = 0;
3304       for (s = 0; s < newLabel->numStrata; ++s) {
3305         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3306       }
3307       /* Pack points and Scatter */
3308       if (!rank) {
3309         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3310         displs[0] = 0;
3311         for (p = 0; p < numProcs; ++p) {
3312           sendcnts[p] = 0;
3313           for (s = 0; s < next->numStrata; ++s) {
3314             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3315           }
3316           offsets[p]  = displs[p];
3317           displs[p+1] = displs[p] + sendcnts[p];
3318         }
3319         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3320         for (s = 0; s < next->numStrata; ++s) {
3321           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3322             const PetscInt point = next->points[p];
3323             PetscInt       proc;
3324 
3325             for (proc = 0; proc < numProcs; ++proc) {
3326               PetscInt dof, off, pPart;
3327 
3328               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3329               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3330               for (pPart = off; pPart < off+dof; ++pPart) {
3331                 if (partArray[pPart] == point) {
3332                   points[offsets[proc]++] = point;
3333                   break;
3334                 }
3335               }
3336             }
3337           }
3338         }
3339       }
3340       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3341       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3342       ierr = PetscFree(points);CHKERRQ(ierr);
3343       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3344       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3345       /* Renumber points */
3346       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3347       /* Sort points */
3348       for (s = 0; s < newLabel->numStrata; ++s) {
3349         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3350       }
3351       /* Insert into list */
3352       if (newNext) newNext->next = newLabel;
3353       else pmesh->labels = newLabel;
3354       newNext = newLabel;
3355       if (!rank) next = next->next;
3356     }
3357   }
3358   /* Cleanup Partition */
3359   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3360   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3361   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3362   ierr = ISDestroy(&part);CHKERRQ(ierr);
3363   /* Create point SF for parallel mesh */
3364   {
3365     const PetscInt *leaves;
3366     PetscSFNode    *remotePoints, *rowners, *lowners;
3367     PetscInt       numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3368     PetscInt       pStart, pEnd;
3369 
3370     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3371     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3372     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3373     for (p=0; p<numRoots; p++) {
3374       rowners[p].rank  = -1;
3375       rowners[p].index = -1;
3376     }
3377     if (origCellPart) {
3378       /* Make sure cells in the original partition are not assigned to other procs */
3379       const PetscInt *origCells;
3380 
3381       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3382       for (p = 0; p < numProcs; ++p) {
3383         PetscInt dof, off, d;
3384 
3385         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3386         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3387         for (d = off; d < off+dof; ++d) {
3388           rowners[origCells[d]].rank = p;
3389         }
3390       }
3391       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3392     }
3393     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3394     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3395 
3396     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3397     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3398     for (p = 0; p < numLeaves; ++p) {
3399       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3400         lowners[p].rank  = rank;
3401         lowners[p].index = leaves ? leaves[p] : p;
3402       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3403         lowners[p].rank  = -2;
3404         lowners[p].index = -2;
3405       }
3406     }
3407     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3408       rowners[p].rank  = -3;
3409       rowners[p].index = -3;
3410     }
3411     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3412     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3413     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3414     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3415     for (p = 0; p < numLeaves; ++p) {
3416       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3417       if (lowners[p].rank != rank) ++numGhostPoints;
3418     }
3419     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3420     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3421     for (p = 0, gp = 0; p < numLeaves; ++p) {
3422       if (lowners[p].rank != rank) {
3423         ghostPoints[gp]        = leaves ? leaves[p] : p;
3424         remotePoints[gp].rank  = lowners[p].rank;
3425         remotePoints[gp].index = lowners[p].index;
3426         ++gp;
3427       }
3428     }
3429     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3430     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3431     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3432   }
3433   /* Cleanup */
3434   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3435   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3436   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3437   PetscFunctionReturn(0);
3438 }
3439 
3440 #undef __FUNCT__
3441 #define __FUNCT__ "DMPlexRenumber_Private"
3442 /*
3443   Reasons to renumber:
3444 
3445   1) Permute points, e.g. bandwidth reduction (Renumber)
3446 
3447     a) Must not mix strata
3448 
3449   2) Shift numbers for point insertion (Shift)
3450 
3451     a) Want operation brken into parts so that insertion can be interleaved
3452 
3453   renumbering - An IS which provides the new numbering
3454 */
3455 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3456 {
3457   PetscFunctionBegin;
3458   PetscFunctionReturn(0);
3459 }
3460 
3461 #undef __FUNCT__
3462 #define __FUNCT__ "DMPlexShiftPoint_Private"
3463 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3464 {
3465   if (depth < 0) return p;
3466   /* Cells    */ if (p < depthEnd[depth])   return p;
3467   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3468   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3469   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3470 }
3471 
3472 #undef __FUNCT__
3473 #define __FUNCT__ "DMPlexShiftSizes_Private"
3474 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3475 {
3476   PetscInt       *depthEnd;
3477   PetscInt       depth = 0, d, pStart, pEnd, p;
3478   PetscErrorCode ierr;
3479 
3480   PetscFunctionBegin;
3481   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3482   if (depth < 0) PetscFunctionReturn(0);
3483   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3484   /* Step 1: Expand chart */
3485   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3486   for (d = 0; d <= depth; ++d) {
3487     pEnd += depthShift[d];
3488     ierr  = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3489   }
3490   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3491   /* Step 2: Set cone and support sizes */
3492   for (d = 0; d <= depth; ++d) {
3493     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3494     for (p = pStart; p < pEnd; ++p) {
3495       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3496       PetscInt size;
3497 
3498       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3499       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3500       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3501       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3502     }
3503   }
3504   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3505   PetscFunctionReturn(0);
3506 }
3507 
3508 #undef __FUNCT__
3509 #define __FUNCT__ "DMPlexShiftPoints_Private"
3510 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3511 {
3512   PetscInt       *depthEnd, *newpoints;
3513   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3514   PetscErrorCode ierr;
3515 
3516   PetscFunctionBegin;
3517   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3518   if (depth < 0) PetscFunctionReturn(0);
3519   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3520   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3521   for (d = 0; d <= depth; ++d) {
3522     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3523   }
3524   /* Step 5: Set cones and supports */
3525   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3526   for (p = pStart; p < pEnd; ++p) {
3527     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3528     PetscInt       size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3529 
3530     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3531     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3532     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3533     for (i = 0; i < size; ++i) {
3534       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3535     }
3536     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3537     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3538     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3539     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3540     for (i = 0; i < size; ++i) {
3541       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3542     }
3543     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3544   }
3545   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3546   PetscFunctionReturn(0);
3547 }
3548 
3549 #undef __FUNCT__
3550 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3551 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3552 {
3553   PetscSection   coordSection, newCoordSection;
3554   Vec            coordinates, newCoordinates;
3555   PetscScalar    *coords, *newCoords;
3556   PetscInt       *depthEnd, coordSize;
3557   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3558   PetscErrorCode ierr;
3559 
3560   PetscFunctionBegin;
3561   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3562   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3563   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3564   for (d = 0; d <= depth; ++d) {
3565     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3566   }
3567   /* Step 8: Convert coordinates */
3568   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3569   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3570   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3571   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3572   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3573   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3574   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3575   for (v = vStartNew; v < vEndNew; ++v) {
3576     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3577     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3578   }
3579   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3580   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3581   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3582   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3583   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3584   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3585   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3586   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3587   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3588   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3589   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3590   for (v = vStart; v < vEnd; ++v) {
3591     PetscInt dof, off, noff, d;
3592 
3593     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3594     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3595     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3596     for (d = 0; d < dof; ++d) {
3597       newCoords[noff+d] = coords[off+d];
3598     }
3599   }
3600   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3601   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3602   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3603   PetscFunctionReturn(0);
3604 }
3605 
3606 #undef __FUNCT__
3607 #define __FUNCT__ "DMPlexShiftSF_Private"
3608 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3609 {
3610   PetscInt          *depthEnd;
3611   PetscInt          depth = 0, d;
3612   PetscSF           sfPoint, sfPointNew;
3613   const PetscSFNode *remotePoints;
3614   PetscSFNode       *gremotePoints;
3615   const PetscInt    *localPoints;
3616   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3617   PetscInt          numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3618   PetscMPIInt       numProcs;
3619   PetscErrorCode    ierr;
3620 
3621   PetscFunctionBegin;
3622   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3623   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3624   for (d = 0; d <= depth; ++d) {
3625     totShift += depthShift[d];
3626     ierr      = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3627   }
3628   /* Step 9: Convert pointSF */
3629   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3630   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3631   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3632   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3633   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3634   if (numRoots >= 0) {
3635     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3636     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3637     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3638     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3639     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3640     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3641     for (l = 0; l < numLeaves; ++l) {
3642       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3643       gremotePoints[l].rank  = remotePoints[l].rank;
3644       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3645     }
3646     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3647     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3648   }
3649   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3650   PetscFunctionReturn(0);
3651 }
3652 
3653 #undef __FUNCT__
3654 #define __FUNCT__ "DMPlexShiftLabels_Private"
3655 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3656 {
3657   PetscSF           sfPoint;
3658   DMLabel           vtkLabel, ghostLabel;
3659   PetscInt          *depthEnd;
3660   const PetscSFNode *leafRemote;
3661   const PetscInt    *leafLocal;
3662   PetscInt          depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3663   PetscMPIInt       rank;
3664   PetscErrorCode    ierr;
3665 
3666   PetscFunctionBegin;
3667   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3668   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3669   for (d = 0; d <= depth; ++d) {
3670     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3671   }
3672   /* Step 10: Convert labels */
3673   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3674   for (l = 0; l < numLabels; ++l) {
3675     DMLabel        label, newlabel;
3676     const char     *lname;
3677     PetscBool      isDepth;
3678     IS             valueIS;
3679     const PetscInt *values;
3680     PetscInt       numValues, val;
3681 
3682     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3683     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3684     if (isDepth) continue;
3685     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3686     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3687     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3688     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3689     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3690     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3691     for (val = 0; val < numValues; ++val) {
3692       IS             pointIS;
3693       const PetscInt *points;
3694       PetscInt       numPoints, p;
3695 
3696       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3697       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3698       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3699       for (p = 0; p < numPoints; ++p) {
3700         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3701 
3702         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3703       }
3704       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3705       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3706     }
3707     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3708     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3709   }
3710   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3711   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3712   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3713   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3714   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3715   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3716   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3717   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3718   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3719   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3720   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3721     for (; c < leafLocal[l] && c < cEnd; ++c) {
3722       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3723     }
3724     if (leafLocal[l] >= cEnd) break;
3725     if (leafRemote[l].rank == rank) {
3726       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3727     } else {
3728       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3729     }
3730   }
3731   for (; c < cEnd; ++c) {
3732     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3733   }
3734   if (0) {
3735     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3736     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3737     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3738   }
3739   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3740   for (f = fStart; f < fEnd; ++f) {
3741     PetscInt numCells;
3742 
3743     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3744     if (numCells < 2) {
3745       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3746     } else {
3747       const PetscInt *cells = PETSC_NULL;
3748       PetscInt       vA, vB;
3749 
3750       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3751       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3752       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3753       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3754     }
3755   }
3756   if (0) {
3757     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3758     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3759     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3760   }
3761   PetscFunctionReturn(0);
3762 }
3763 
3764 #undef __FUNCT__
3765 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3766 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3767 {
3768   DMLabel        label;
3769   IS             valueIS;
3770   const PetscInt *values;
3771   PetscInt       *depthShift;
3772   PetscInt       depth = 0, numFS, fs, ghostCell, cEnd, c;
3773   PetscErrorCode ierr;
3774 
3775   PetscFunctionBegin;
3776   /* Count ghost cells */
3777   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3778   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3779   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3780   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3781 
3782   *numGhostCells = 0;
3783   for (fs = 0; fs < numFS; ++fs) {
3784     PetscInt numBdFaces;
3785 
3786     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3787 
3788     *numGhostCells += numBdFaces;
3789   }
3790   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3791   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3792   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3793   if (depth >= 0) depthShift[depth] = *numGhostCells;
3794   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3795   /* Step 3: Set cone/support sizes for new points */
3796   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3797   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3798     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3799   }
3800   for (fs = 0; fs < numFS; ++fs) {
3801     IS             faceIS;
3802     const PetscInt *faces;
3803     PetscInt       numFaces, f;
3804 
3805     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3806     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3807     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3808     for (f = 0; f < numFaces; ++f) {
3809       PetscInt size;
3810 
3811       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3812       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3813       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3814     }
3815     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3816     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3817   }
3818   /* Step 4: Setup ghosted DM */
3819   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3820   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3821   /* Step 6: Set cones and supports for new points */
3822   ghostCell = cEnd;
3823   for (fs = 0; fs < numFS; ++fs) {
3824     IS             faceIS;
3825     const PetscInt *faces;
3826     PetscInt       numFaces, f;
3827 
3828     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3829     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3830     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3831     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3832       PetscInt newFace = faces[f] + *numGhostCells;
3833 
3834       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3835       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3836     }
3837     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3838     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3839   }
3840   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3841   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3842   /* Step 7: Stratify */
3843   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3844   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3845   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3846   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3847   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3848   PetscFunctionReturn(0);
3849 }
3850 
3851 #undef __FUNCT__
3852 #define __FUNCT__ "DMPlexConstructGhostCells"
3853 /*@C
3854   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3855 
3856   Collective on dm
3857 
3858   Input Parameters:
3859 + dm - The original DM
3860 - labelName - The label specifying the boundary faces (this could be auto-generated)
3861 
3862   Output Parameters:
3863 + numGhostCells - The number of ghost cells added to the DM
3864 - dmGhosted - The new DM
3865 
3866   Level: developer
3867 
3868 .seealso: DMCreate()
3869 */
3870 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3871 {
3872   DM             gdm;
3873   PetscInt       dim;
3874   PetscErrorCode ierr;
3875 
3876   PetscFunctionBegin;
3877   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3878   PetscValidPointer(numGhostCells, 3);
3879   PetscValidPointer(dmGhosted, 4);
3880   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3881   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3882   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3883   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3884   switch (dim) {
3885   case 2:
3886     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3887     break;
3888   default:
3889     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3890   }
3891   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3892   *dmGhosted = gdm;
3893   PetscFunctionReturn(0);
3894 }
3895 
3896 #undef __FUNCT__
3897 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3898 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, const char labelName[], DM sdm)
3899 {
3900   MPI_Comm       comm = ((PetscObject) dm)->comm;
3901   DMLabel        label;
3902   IS             valueIS, *pointIS;
3903   const PetscInt *values, **splitPoints;
3904   PetscSection   coordSection;
3905   Vec            coordinates;
3906   PetscScalar    *coords;
3907   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3908   PetscInt       shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3909   PetscErrorCode ierr;
3910 
3911   PetscFunctionBegin;
3912   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3913   /* Count split points and add cohesive cells */
3914   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3915   if (label) {
3916     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3917     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3918     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3919   }
3920   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3921   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3922   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3923   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3924   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3925   for (d = 0; d <= depth; ++d) {
3926     ierr              = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3927     numSplitPoints[d] = 0;
3928     splitPoints[d]    = PETSC_NULL;
3929     pointIS[d]        = PETSC_NULL;
3930   }
3931   for (sp = 0; sp < numSP; ++sp) {
3932     const PetscInt dep = values[sp];
3933 
3934     if ((dep < 0) || (dep > depth)) continue;
3935     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3936     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3937     if (pointIS[dep]) {
3938       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3939       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3940     }
3941   }
3942   if (depth >= 0) {
3943     /* Calculate number of additional points */
3944     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3945     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3946     /* Calculate hybrid bound for each dimension */
3947     pMaxNew[0] += depthShift[depth];
3948     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3949     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3950 
3951     /* Calculate point offset for each dimension */
3952     depthOffset[depth] = 0;
3953     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3954     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3955     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3956   }
3957   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3958   /* Step 3: Set cone/support sizes for new points */
3959   for (dep = 0; dep <= depth; ++dep) {
3960     for (p = 0; p < numSplitPoints[dep]; ++p) {
3961       const PetscInt oldp   = splitPoints[dep][p];
3962       const PetscInt newp   = depthOffset[dep] + oldp;
3963       const PetscInt splitp = pMaxNew[dep] + p;
3964       const PetscInt *support;
3965       PetscInt       coneSize, supportSize, q, e;
3966 
3967       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3968       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3969       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3970       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3971       if (dep == depth-1) {
3972         const PetscInt ccell = pMaxNew[depth] + p;
3973         /* Add cohesive cells, they are prisms */
3974         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3975       } else if (dep == 0) {
3976         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3977 
3978         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3979         /* Split old vertex: Edges in old split faces and new cohesive edge */
3980         for (e = 0, q = 0; e < supportSize; ++e) {
3981           PetscInt val;
3982 
3983           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3984           if ((val == 1) || (val == (shift + 1))) ++q;
3985         }
3986         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3987         /* Split new vertex: Edges in new split faces and new cohesive edge */
3988         for (e = 0, q = 0; e < supportSize; ++e) {
3989           PetscInt val;
3990 
3991           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3992           if ((val == 1) || (val == -(shift + 1))) ++q;
3993         }
3994         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
3995         /* Add cohesive edges */
3996         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
3997         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3998       } else if (dep == dim-2) {
3999         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4000         /* Split old edge: Faces in positive side cells and old split faces */
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 == dim-1) || (val == (shift + dim-1))) ++q;
4006         }
4007         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4008         /* Split new edge: Faces in negative side cells and new split faces */
4009         for (e = 0, q = 0; e < supportSize; ++e) {
4010           PetscInt val;
4011 
4012           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4013           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4014         }
4015         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4016       }
4017     }
4018   }
4019   /* Step 4: Setup split DM */
4020   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4021   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4022   /* Step 6: Set cones and supports for new points */
4023   for (dep = 0; dep <= depth; ++dep) {
4024     for (p = 0; p < numSplitPoints[dep]; ++p) {
4025       const PetscInt oldp   = splitPoints[dep][p];
4026       const PetscInt newp   = depthOffset[dep] + oldp;
4027       const PetscInt splitp = pMaxNew[dep] + p;
4028       const PetscInt *cone, *support, *ornt;
4029       PetscInt       coneSize, supportSize, q, v, e, s;
4030 
4031       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4032       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4033       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4034       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4035       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4036       if (dep == depth-1) {
4037         const PetscInt ccell = pMaxNew[depth] + p;
4038         const PetscInt *supportF;
4039 
4040         /* Split face:       copy in old face to new face to start */
4041         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4042         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4043         /* Split old face:   old vertices/edges in cone so no change */
4044         /* Split new face:   new vertices/edges in cone */
4045         for (q = 0; q < coneSize; ++q) {
4046           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4047 
4048           coneNew[2+q] = pMaxNew[dim-2] + v;
4049         }
4050         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4051         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4052         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4053         coneNew[0] = newp;
4054         coneNew[1] = splitp;
4055         for (q = 0; q < coneSize; ++q) {
4056           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4057         }
4058         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4059 
4060 
4061         for (s = 0; s < supportSize; ++s) {
4062           PetscInt val;
4063 
4064           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4065           if (val < 0) {
4066             /* Split old face:   Replace negative side cell with cohesive cell */
4067             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4068           } else {
4069             /* Split new face:   Replace positive side cell with cohesive cell */
4070             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4071           }
4072         }
4073       } else if (dep == 0) {
4074         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4075 
4076         /* Split old vertex: Edges in old split faces and new cohesive edge */
4077         for (e = 0, q = 0; e < supportSize; ++e) {
4078           PetscInt val;
4079 
4080           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4081           if ((val == 1) || (val == (shift + 1))) {
4082             supportNew[q++] = depthOffset[1] + support[e];
4083           }
4084         }
4085         supportNew[q] = cedge;
4086 
4087         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4088         /* Split new vertex: Edges in new split faces and new cohesive edge */
4089         for (e = 0, q = 0; e < supportSize; ++e) {
4090           PetscInt val, edge;
4091 
4092           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4093           if (val == 1) {
4094             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4095             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4096             supportNew[q++] = pMaxNew[1] + edge;
4097           } else if (val == -(shift + 1)) {
4098             supportNew[q++] = depthOffset[1] + support[e];
4099           }
4100         }
4101         supportNew[q] = cedge;
4102         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4103         /* Cohesive edge:    Old and new split vertex, punting on support */
4104         coneNew[0] = newp;
4105         coneNew[1] = splitp;
4106         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4107       } else if (dep == dim-2) {
4108         /* Split old edge:   old vertices in cone so no change */
4109         /* Split new edge:   new vertices in cone */
4110         for (q = 0; q < coneSize; ++q) {
4111           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4112 
4113           coneNew[q] = pMaxNew[dim-3] + v;
4114         }
4115         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4116         /* Split old edge: Faces in positive side cells and old split faces */
4117         for (e = 0, q = 0; e < supportSize; ++e) {
4118           PetscInt val;
4119 
4120           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4121           if ((val == dim-1) || (val == (shift + dim-1))) {
4122             supportNew[q++] = depthOffset[dim-1] + support[e];
4123           }
4124         }
4125         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4126         /* Split new edge: Faces in negative side cells and new split faces */
4127         for(e = 0, q = 0; e < supportSize; ++e) {
4128           PetscInt val, face;
4129 
4130           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4131           if (val == dim-1) {
4132             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4133             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4134             supportNew[q++] = pMaxNew[dim-1] + face;
4135           } else if (val == -(shift + dim-1)) {
4136             supportNew[q++] = depthOffset[dim-1] + support[e];
4137           }
4138         }
4139         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4140       }
4141     }
4142   }
4143   /* Step 6b: Replace split points in negative side cones */
4144   for (sp = 0; sp < numSP; ++sp) {
4145     PetscInt       dep = values[sp];
4146     IS             pIS;
4147     PetscInt       numPoints;
4148     const PetscInt *points;
4149 
4150     if (dep >= 0) continue;
4151     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4152     if (!pIS) continue;
4153     dep  = -dep - shift;
4154     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4155     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4156     for (p = 0; p < numPoints; ++p) {
4157       const PetscInt oldp = points[p];
4158       const PetscInt newp = depthOffset[dep] + oldp;
4159       const PetscInt *cone;
4160       PetscInt       coneSize, c;
4161       PetscBool      replaced = PETSC_FALSE;
4162 
4163       /* Negative edge: replace split vertex */
4164       /* Negative cell: replace split face */
4165       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4166       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4167       for (c = 0; c < coneSize; ++c) {
4168         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4169         PetscInt       csplitp, cp, val;
4170 
4171         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4172         if (val == dep-1) {
4173           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4174           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4175           csplitp  = pMaxNew[dep-1] + cp;
4176           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4177           replaced = PETSC_TRUE;
4178         }
4179       }
4180       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4181     }
4182     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4183     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4184   }
4185   /* Step 7: Stratify */
4186   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4187   /* Step 8: Coordinates */
4188   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4189   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4190   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4191   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4192   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4193     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4194     const PetscInt splitp = pMaxNew[0] + v;
4195     PetscInt       dof, off, soff, d;
4196 
4197     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4198     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4199     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4200     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4201   }
4202   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4203   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4204   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4205   /* Step 10: Labels */
4206   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4207   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4208   for (dep = 0; dep <= depth; ++dep) {
4209     for (p = 0; p < numSplitPoints[dep]; ++p) {
4210       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4211       const PetscInt splitp = pMaxNew[dep] + p;
4212       PetscInt       l;
4213 
4214       for (l = 0; l < numLabels; ++l) {
4215         DMLabel    label;
4216         const char *lname;
4217         PetscInt   val;
4218 
4219         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4220         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4221         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4222         if (val >= 0) {
4223           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4224           if (dep == 0) {
4225             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4226             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4227           }
4228         }
4229       }
4230     }
4231   }
4232   for (sp = 0; sp < numSP; ++sp) {
4233     const PetscInt dep = values[sp];
4234 
4235     if ((dep < 0) || (dep > depth)) continue;
4236     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4237     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4238   }
4239   if (label) {
4240     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4241     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4242   }
4243   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4244   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4245   PetscFunctionReturn(0);
4246 }
4247 
4248 #undef __FUNCT__
4249 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4250 /*@C
4251   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4252 
4253   Collective on dm
4254 
4255   Input Parameters:
4256 + dm - The original DM
4257 - labelName - The label specifying the boundary faces (this could be auto-generated)
4258 
4259   Output Parameters:
4260 - dmSplit - The new DM
4261 
4262   Level: developer
4263 
4264 .seealso: DMCreate()
4265 */
4266 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4267 {
4268   DM             sdm;
4269   PetscInt       dim;
4270   PetscErrorCode ierr;
4271 
4272   PetscFunctionBegin;
4273   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4274   PetscValidPointer(dmSplit, 4);
4275   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4276   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4277   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4278   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4279   switch (dim) {
4280   case 2:
4281   case 3:
4282     ierr = DMPlexConstructCohesiveCells_Private(dm, labelName, sdm);CHKERRQ(ierr);
4283     break;
4284   default:
4285     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4286   }
4287   *dmSplit = sdm;
4288   PetscFunctionReturn(0);
4289 }
4290 
4291 #undef __FUNCT__
4292 #define __FUNCT__ "DMLabelCohesiveComplete"
4293 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4294 {
4295   IS             dimIS;
4296   const PetscInt *points;
4297   PetscInt       shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4298   PetscErrorCode ierr;
4299 
4300   PetscFunctionBegin;
4301   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4302   /* Cell orientation for face gives the side of the fault */
4303   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4304   if (!dimIS) PetscFunctionReturn(0);
4305   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4306   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4307   for (p = 0; p < numPoints; ++p) {
4308     const PetscInt *support;
4309     PetscInt       supportSize, s;
4310 
4311     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4312     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4313     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4314     for (s = 0; s < supportSize; ++s) {
4315       const PetscInt *cone, *ornt;
4316       PetscInt       coneSize, c;
4317       PetscBool      pos = PETSC_TRUE;
4318 
4319       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4320       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4321       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4322       for(c = 0; c < coneSize; ++c) {
4323         if (cone[c] == points[p]) {
4324           if (ornt[c] >= 0) {
4325             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4326           } else {
4327             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4328             pos  = PETSC_FALSE;
4329           }
4330           break;
4331         }
4332       }
4333       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]);
4334       /* Put faces touching the fault in the label */
4335       for (c = 0; c < coneSize; ++c) {
4336         const PetscInt point = cone[c];
4337 
4338         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4339         if (val == -1) {
4340           PetscInt *closure = PETSC_NULL;
4341           PetscInt closureSize, cl;
4342 
4343           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4344           for (cl = 0; cl < closureSize*2; cl += 2) {
4345             const PetscInt clp = closure[cl];
4346 
4347             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4348             if ((val >= 0) && (val < dim-1)) {
4349               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4350               break;
4351             }
4352           }
4353           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4354         }
4355       }
4356     }
4357   }
4358   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4359   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4360   /* Search for other cells/faces/edges connected to the fault by a vertex */
4361   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4362   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4363   if (!dimIS) PetscFunctionReturn(0);
4364   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4365   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4366   for (p = 0; p < numPoints; ++p) {
4367     PetscInt *star = PETSC_NULL;
4368     PetscInt starSize, s;
4369     PetscInt again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4370 
4371     /* First mark cells connected to the fault */
4372     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4373     while (again) {
4374       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4375       again = 0;
4376       for (s = 0; s < starSize*2; s += 2) {
4377         const PetscInt point = star[s];
4378         const PetscInt *cone;
4379         PetscInt       coneSize, c;
4380 
4381         if ((point < cStart) || (point >= cEnd)) continue;
4382         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4383         if (val != -1) continue;
4384         again = 2;
4385         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4386         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4387         for (c = 0; c < coneSize; ++c) {
4388           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4389           if (val != -1) {
4390             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);
4391             if (val > 0) {
4392               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4393             } else {
4394               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4395             }
4396             again = 1;
4397             break;
4398           }
4399         }
4400       }
4401     }
4402     /* Classify the rest by cell membership */
4403     for (s = 0; s < starSize*2; s += 2) {
4404       const PetscInt point = star[s];
4405 
4406       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4407       if (val == -1) {
4408         PetscInt  *sstar = PETSC_NULL;
4409         PetscInt  sstarSize, ss;
4410         PetscBool marked = PETSC_FALSE;
4411 
4412         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4413         for (ss = 0; ss < sstarSize*2; ss += 2) {
4414           const PetscInt spoint = sstar[ss];
4415 
4416           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4417           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4418           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4419           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4420           if (val > 0) {
4421             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4422           } else {
4423             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4424           }
4425           marked = PETSC_TRUE;
4426           break;
4427         }
4428         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4429         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4430       }
4431     }
4432     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4433   }
4434   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4435   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4436   PetscFunctionReturn(0);
4437 }
4438 
4439 #undef __FUNCT__
4440 #define __FUNCT__ "DMPlexInterpolate_2D"
4441 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4442 {
4443   DM             idm;
4444   DM_Plex        *mesh;
4445   PetscHashIJ    edgeTable;
4446   PetscInt       *off;
4447   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4448   PetscInt       numEdges, firstEdge, edge, e;
4449   PetscErrorCode ierr;
4450 
4451   PetscFunctionBegin;
4452   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4453   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4454   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4455   numCells    = cEnd - cStart;
4456   numVertices = vEnd - vStart;
4457   firstEdge   = numCells + numVertices;
4458   numEdges    = 0;
4459   /* Count edges using algorithm from CreateNeighborCSR */
4460   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4461   if (off) {
4462     PetscInt numCorners = 0;
4463 
4464     numEdges = off[numCells]/2;
4465 #if 0
4466     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4467     numEdges += 3*numCells - off[numCells];
4468 #else
4469     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4470     for (c = cStart; c < cEnd; ++c) {
4471       PetscInt coneSize;
4472 
4473       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4474       numCorners += coneSize;
4475     }
4476     numEdges += numCorners - off[numCells];
4477 #endif
4478   }
4479 #if 0
4480   /* Check Euler characteristic V - E + F = 1 */
4481   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4482 #endif
4483   /* Create interpolated mesh */
4484   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4485   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4486   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4487   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4488   for (c = 0; c < numCells; ++c) {
4489     PetscInt numCorners;
4490 
4491     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4492     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4493   }
4494   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4495     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4496   }
4497   ierr = DMSetUp(idm);CHKERRQ(ierr);
4498   /* Get edge cones from subsets of cell vertices */
4499   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4500   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4501 
4502   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4503     const PetscInt *cellFaces;
4504     PetscInt       numCellFaces, faceSize, cf;
4505 
4506     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4507     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4508     for (cf = 0; cf < numCellFaces; ++cf) {
4509 #if 1
4510       PetscHashIJKey key;
4511 
4512       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4513       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4514       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4515       if (e < 0) {
4516         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4517         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4518         e    = edge++;
4519       }
4520 #else
4521       PetscBool found = PETSC_FALSE;
4522 
4523       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4524       for (e = firstEdge; e < edge; ++e) {
4525         const PetscInt *cone;
4526 
4527         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4528         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4529             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4530           found = PETSC_TRUE;
4531           break;
4532         }
4533       }
4534       if (!found) {
4535         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4536         ++edge;
4537       }
4538 #endif
4539       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4540     }
4541   }
4542   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4543   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4544   ierr = PetscFree(off);CHKERRQ(ierr);
4545   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4546   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4547   mesh = (DM_Plex*) (idm)->data;
4548   /* Orient edges */
4549   for (c = 0; c < numCells; ++c) {
4550     const PetscInt *cone = PETSC_NULL, *cellFaces;
4551     PetscInt       coneSize, coff, numCellFaces, faceSize, cf;
4552 
4553     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4554     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4555     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4556     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4557     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4558     for (cf = 0; cf < numCellFaces; ++cf) {
4559       const PetscInt *econe = PETSC_NULL;
4560       PetscInt       esize;
4561 
4562       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4563       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4564       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]);
4565       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4566         /* Correctly oriented */
4567         mesh->coneOrientations[coff+cf] = 0;
4568       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4569         /* Start at index 1, and reverse orientation */
4570         mesh->coneOrientations[coff+cf] = -(1+1);
4571       }
4572     }
4573   }
4574   *dmInt = idm;
4575   PetscFunctionReturn(0);
4576 }
4577 
4578 #undef __FUNCT__
4579 #define __FUNCT__ "DMPlexInterpolate_3D"
4580 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4581 {
4582   DM             idm, fdm;
4583   DM_Plex        *mesh;
4584   PetscInt       *off;
4585   const PetscInt numCorners = 4;
4586   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4587   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4588   PetscErrorCode ierr;
4589 
4590   PetscFunctionBegin;
4591   {
4592     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4593     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4594     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4595   }
4596   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4597   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4598   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4599   numCells    = cEnd - cStart;
4600   numVertices = vEnd - vStart;
4601   firstFace   = numCells + numVertices;
4602   numFaces    = 0;
4603   /* Count faces using algorithm from CreateNeighborCSR */
4604   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4605   if (off) {
4606     numFaces = off[numCells]/2;
4607     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4608     numFaces += 4*numCells - off[numCells];
4609   }
4610   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4611   firstEdge = firstFace + numFaces;
4612   numEdges  = numVertices + numFaces - numCells - 1;
4613   /* Create interpolated mesh */
4614   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4615   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4616   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4617   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4618   for (c = 0; c < numCells; ++c) {
4619     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4620   }
4621   for (f = firstFace; f < firstFace+numFaces; ++f) {
4622     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4623   }
4624   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4625     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4626   }
4627   ierr = DMSetUp(idm);CHKERRQ(ierr);
4628   /* Get face cones from subsets of cell vertices */
4629   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4630   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4631   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4632   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4633   for (f = firstFace; f < firstFace+numFaces; ++f) {
4634     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4635   }
4636   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4637   for (c = 0, face = firstFace; c < numCells; ++c) {
4638     const PetscInt *cellFaces;
4639     PetscInt       numCellFaces, faceSize, cf;
4640 
4641     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4642     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4643     for (cf = 0; cf < numCellFaces; ++cf) {
4644       PetscBool found = PETSC_FALSE;
4645 
4646       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4647       for (f = firstFace; f < face; ++f) {
4648         const PetscInt *cone = PETSC_NULL;
4649 
4650         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4651         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4652             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4653             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4654             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4655             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4656             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4657           found = PETSC_TRUE;
4658           break;
4659         }
4660       }
4661       if (!found) {
4662         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4663         /* Save the vertices for orientation calculation */
4664         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4665         ++face;
4666       }
4667       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4668     }
4669   }
4670   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4671   /* Get edge cones from subsets of face vertices */
4672   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4673     const PetscInt *cellFaces;
4674     PetscInt       numCellFaces, faceSize, cf;
4675 
4676     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4677     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4678     for (cf = 0; cf < numCellFaces; ++cf) {
4679       PetscBool found = PETSC_FALSE;
4680 
4681       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4682       for (e = firstEdge; e < edge; ++e) {
4683         const PetscInt *cone = PETSC_NULL;
4684 
4685         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4686         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4687             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4688           found = PETSC_TRUE;
4689           break;
4690         }
4691       }
4692       if (!found) {
4693         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4694         ++edge;
4695       }
4696       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4697     }
4698   }
4699   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4700   ierr = PetscFree(off);CHKERRQ(ierr);
4701   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4702   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4703   mesh = (DM_Plex*) (idm)->data;
4704   /* Orient edges */
4705   for (f = firstFace; f < firstFace+numFaces; ++f) {
4706     const PetscInt *cone, *cellFaces;
4707     PetscInt       coneSize, coff, numCellFaces, faceSize, cf;
4708 
4709     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4710     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4711     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4712     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4713     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4714     for (cf = 0; cf < numCellFaces; ++cf) {
4715       const PetscInt *econe;
4716       PetscInt       esize;
4717 
4718       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4719       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4720       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]);
4721       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4722         /* Correctly oriented */
4723         mesh->coneOrientations[coff+cf] = 0;
4724       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4725         /* Start at index 1, and reverse orientation */
4726         mesh->coneOrientations[coff+cf] = -(1+1);
4727       }
4728     }
4729   }
4730   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4731   /* Orient faces */
4732   for (c = 0; c < numCells; ++c) {
4733     const PetscInt *cone, *cellFaces;
4734     PetscInt       coneSize, coff, numCellFaces, faceSize, cf;
4735 
4736     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4737     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4738     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4739     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4740     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4741     for (cf = 0; cf < numCellFaces; ++cf) {
4742       PetscInt *origClosure = PETSC_NULL, *closure;
4743       PetscInt closureSize, i;
4744 
4745       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4746       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4747       for (i = 4; i < 7; ++i) {
4748         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);
4749       }
4750       closure = &origClosure[4*2];
4751       /* Remember that this is the orientation for edges, not vertices */
4752       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4753         /* Correctly oriented */
4754         mesh->coneOrientations[coff+cf] = 0;
4755       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4756         /* Shifted by 1 */
4757         mesh->coneOrientations[coff+cf] = 1;
4758       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4759         /* Shifted by 2 */
4760         mesh->coneOrientations[coff+cf] = 2;
4761       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4762         /* Start at edge 1, and reverse orientation */
4763         mesh->coneOrientations[coff+cf] = -(1+1);
4764       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4765         /* Start at index 0, and reverse orientation */
4766         mesh->coneOrientations[coff+cf] = -(0+1);
4767       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4768         /* Start at index 2, and reverse orientation */
4769         mesh->coneOrientations[coff+cf] = -(2+1);
4770       } 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);
4771       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4772     }
4773   }
4774   {
4775     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4776     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4777     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4778   }
4779   *dmInt = idm;
4780   PetscFunctionReturn(0);
4781 }
4782 
4783 #undef __FUNCT__
4784 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4785 /*
4786   This takes as input the common mesh generator output, a list of the vertices for each cell
4787 */
4788 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4789 {
4790   PetscInt       *cone, c, p;
4791   PetscErrorCode ierr;
4792 
4793   PetscFunctionBegin;
4794   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4795   for (c = 0; c < numCells; ++c) {
4796     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4797   }
4798   ierr = DMSetUp(dm);CHKERRQ(ierr);
4799   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4800   for (c = 0; c < numCells; ++c) {
4801     for (p = 0; p < numCorners; ++p) {
4802       cone[p] = cells[c*numCorners+p]+numCells;
4803     }
4804     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4805   }
4806   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4807   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4808   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4809   PetscFunctionReturn(0);
4810 }
4811 
4812 #undef __FUNCT__
4813 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4814 /*
4815   This takes as input the coordinates for each vertex
4816 */
4817 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4818 {
4819   PetscSection   coordSection;
4820   Vec            coordinates;
4821   PetscScalar    *coords;
4822   PetscInt       coordSize, v, d;
4823   PetscErrorCode ierr;
4824 
4825   PetscFunctionBegin;
4826   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4827   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4828   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4829   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4830   for (v = numCells; v < numCells+numVertices; ++v) {
4831     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4832     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4833   }
4834   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4835   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4836   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4837   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4838   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4839   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4840   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4841   for (v = 0; v < numVertices; ++v) {
4842     for (d = 0; d < spaceDim; ++d) {
4843       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4844     }
4845   }
4846   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4847   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4848   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4849   PetscFunctionReturn(0);
4850 }
4851 
4852 #undef __FUNCT__
4853 #define __FUNCT__ "DMPlexCreateFromCellList"
4854 /*
4855   This takes as input the common mesh generator output, a list of the vertices for each cell
4856 */
4857 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4858 {
4859   PetscErrorCode ierr;
4860 
4861   PetscFunctionBegin;
4862   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4863   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4864   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4865   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4866   if (interpolate) {
4867     DM idm;
4868 
4869     switch (dim) {
4870     case 2:
4871       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4872     case 3:
4873       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4874     default:
4875       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4876     }
4877     ierr = DMDestroy(dm);CHKERRQ(ierr);
4878     *dm  = idm;
4879   }
4880   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4881   PetscFunctionReturn(0);
4882 }
4883 
4884 #if defined(PETSC_HAVE_TRIANGLE)
4885 #include <triangle.h>
4886 
4887 #undef __FUNCT__
4888 #define __FUNCT__ "InitInput_Triangle"
4889 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4890 {
4891   PetscFunctionBegin;
4892   inputCtx->numberofpoints             = 0;
4893   inputCtx->numberofpointattributes    = 0;
4894   inputCtx->pointlist                  = PETSC_NULL;
4895   inputCtx->pointattributelist         = PETSC_NULL;
4896   inputCtx->pointmarkerlist            = PETSC_NULL;
4897   inputCtx->numberofsegments           = 0;
4898   inputCtx->segmentlist                = PETSC_NULL;
4899   inputCtx->segmentmarkerlist          = PETSC_NULL;
4900   inputCtx->numberoftriangleattributes = 0;
4901   inputCtx->trianglelist               = PETSC_NULL;
4902   inputCtx->numberofholes              = 0;
4903   inputCtx->holelist                   = PETSC_NULL;
4904   inputCtx->numberofregions            = 0;
4905   inputCtx->regionlist                 = PETSC_NULL;
4906   PetscFunctionReturn(0);
4907 }
4908 
4909 #undef __FUNCT__
4910 #define __FUNCT__ "InitOutput_Triangle"
4911 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4912 {
4913   PetscFunctionBegin;
4914   outputCtx->numberofpoints        = 0;
4915   outputCtx->pointlist             = PETSC_NULL;
4916   outputCtx->pointattributelist    = PETSC_NULL;
4917   outputCtx->pointmarkerlist       = PETSC_NULL;
4918   outputCtx->numberoftriangles     = 0;
4919   outputCtx->trianglelist          = PETSC_NULL;
4920   outputCtx->triangleattributelist = PETSC_NULL;
4921   outputCtx->neighborlist          = PETSC_NULL;
4922   outputCtx->segmentlist           = PETSC_NULL;
4923   outputCtx->segmentmarkerlist     = PETSC_NULL;
4924   outputCtx->numberofedges         = 0;
4925   outputCtx->edgelist              = PETSC_NULL;
4926   outputCtx->edgemarkerlist        = PETSC_NULL;
4927   PetscFunctionReturn(0);
4928 }
4929 
4930 #undef __FUNCT__
4931 #define __FUNCT__ "FiniOutput_Triangle"
4932 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4933 {
4934   PetscFunctionBegin;
4935   free(outputCtx->pointmarkerlist);
4936   free(outputCtx->edgelist);
4937   free(outputCtx->edgemarkerlist);
4938   free(outputCtx->trianglelist);
4939   free(outputCtx->neighborlist);
4940   PetscFunctionReturn(0);
4941 }
4942 
4943 #undef __FUNCT__
4944 #define __FUNCT__ "DMPlexGenerate_Triangle"
4945 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4946 {
4947   MPI_Comm             comm             = ((PetscObject) boundary)->comm;
4948   PetscInt             dim              = 2;
4949   const PetscBool      createConvexHull = PETSC_FALSE;
4950   const PetscBool      constrained      = PETSC_FALSE;
4951   struct triangulateio in;
4952   struct triangulateio out;
4953   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4954   PetscMPIInt          rank;
4955   PetscErrorCode       ierr;
4956 
4957   PetscFunctionBegin;
4958   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4959   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4960   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4961   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4962 
4963   in.numberofpoints = vEnd - vStart;
4964   if (in.numberofpoints > 0) {
4965     PetscSection coordSection;
4966     Vec          coordinates;
4967     PetscScalar  *array;
4968 
4969     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4970     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4971     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4972     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4973     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4974     for (v = vStart; v < vEnd; ++v) {
4975       const PetscInt idx = v - vStart;
4976       PetscInt       off, d;
4977 
4978       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4979       for (d = 0; d < dim; ++d) {
4980         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4981       }
4982       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4983     }
4984     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4985   }
4986   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4987   in.numberofsegments = eEnd - eStart;
4988   if (in.numberofsegments > 0) {
4989     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4990     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4991     for (e = eStart; e < eEnd; ++e) {
4992       const PetscInt idx = e - eStart;
4993       const PetscInt *cone;
4994 
4995       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4996 
4997       in.segmentlist[idx*2+0] = cone[0] - vStart;
4998       in.segmentlist[idx*2+1] = cone[1] - vStart;
4999 
5000       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5001     }
5002   }
5003 #if 0 /* Do not currently support holes */
5004   PetscReal *holeCoords;
5005   PetscInt  h, d;
5006 
5007   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5008   if (in.numberofholes > 0) {
5009     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5010     for (h = 0; h < in.numberofholes; ++h) {
5011       for (d = 0; d < dim; ++d) {
5012         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5013       }
5014     }
5015   }
5016 #endif
5017   if (!rank) {
5018     char args[32];
5019 
5020     /* Take away 'Q' for verbose output */
5021     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5022     if (createConvexHull) {
5023       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5024     }
5025     if (constrained) {
5026       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5027     }
5028     triangulate(args, &in, &out, PETSC_NULL);
5029   }
5030   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5031   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5032   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5033   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5034   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5035 
5036   {
5037     const PetscInt numCorners  = 3;
5038     const PetscInt numCells    = out.numberoftriangles;
5039     const PetscInt numVertices = out.numberofpoints;
5040     const int      *cells      = out.trianglelist;
5041     const double   *meshCoords = out.pointlist;
5042 
5043     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5044     /* Set labels */
5045     for (v = 0; v < numVertices; ++v) {
5046       if (out.pointmarkerlist[v]) {
5047         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5048       }
5049     }
5050     if (interpolate) {
5051       for (e = 0; e < out.numberofedges; e++) {
5052         if (out.edgemarkerlist[e]) {
5053           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5054           const PetscInt *edges;
5055           PetscInt       numEdges;
5056 
5057           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5058           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5059           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5060           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5061         }
5062       }
5063     }
5064     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5065   }
5066 #if 0 /* Do not currently support holes */
5067   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5068 #endif
5069   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5070   PetscFunctionReturn(0);
5071 }
5072 
5073 #undef __FUNCT__
5074 #define __FUNCT__ "DMPlexRefine_Triangle"
5075 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5076 {
5077   MPI_Comm             comm = ((PetscObject) dm)->comm;
5078   PetscInt             dim  = 2;
5079   struct triangulateio in;
5080   struct triangulateio out;
5081   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5082   PetscMPIInt          rank;
5083   PetscErrorCode       ierr;
5084 
5085   PetscFunctionBegin;
5086   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5087   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5088   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5089   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5090   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5091   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5092 
5093   in.numberofpoints = vEnd - vStart;
5094   if (in.numberofpoints > 0) {
5095     PetscSection coordSection;
5096     Vec          coordinates;
5097     PetscScalar  *array;
5098 
5099     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5100     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5101     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5102     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5103     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5104     for (v = vStart; v < vEnd; ++v) {
5105       const PetscInt idx = v - vStart;
5106       PetscInt       off, d;
5107 
5108       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5109       for (d = 0; d < dim; ++d) {
5110         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5111       }
5112       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5113     }
5114     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5115   }
5116   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5117 
5118   in.numberofcorners   = 3;
5119   in.numberoftriangles = cEnd - cStart;
5120 
5121   in.trianglearealist  = (double*) maxVolumes;
5122   if (in.numberoftriangles > 0) {
5123     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5124     for (c = cStart; c < cEnd; ++c) {
5125       const PetscInt idx      = c - cStart;
5126       PetscInt       *closure = PETSC_NULL;
5127       PetscInt       closureSize;
5128 
5129       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5130       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5131       for (v = 0; v < 3; ++v) {
5132         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5133       }
5134       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5135     }
5136   }
5137   /* TODO: Segment markers are missing on input */
5138 #if 0 /* Do not currently support holes */
5139   PetscReal *holeCoords;
5140   PetscInt  h, d;
5141 
5142   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5143   if (in.numberofholes > 0) {
5144     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5145     for (h = 0; h < in.numberofholes; ++h) {
5146       for (d = 0; d < dim; ++d) {
5147         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5148       }
5149     }
5150   }
5151 #endif
5152   if (!rank) {
5153     char args[32];
5154 
5155     /* Take away 'Q' for verbose output */
5156     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5157     triangulate(args, &in, &out, PETSC_NULL);
5158   }
5159   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5160   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5161   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5162   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5163   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5164 
5165   {
5166     const PetscInt numCorners  = 3;
5167     const PetscInt numCells    = out.numberoftriangles;
5168     const PetscInt numVertices = out.numberofpoints;
5169     const int      *cells      = out.trianglelist;
5170     const double   *meshCoords = out.pointlist;
5171     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5172 
5173     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5174     /* Set labels */
5175     for (v = 0; v < numVertices; ++v) {
5176       if (out.pointmarkerlist[v]) {
5177         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5178       }
5179     }
5180     if (interpolate) {
5181       PetscInt e;
5182 
5183       for (e = 0; e < out.numberofedges; e++) {
5184         if (out.edgemarkerlist[e]) {
5185           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5186           const PetscInt *edges;
5187           PetscInt       numEdges;
5188 
5189           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5190           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5191           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5192           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5193         }
5194       }
5195     }
5196     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5197   }
5198 #if 0 /* Do not currently support holes */
5199   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5200 #endif
5201   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5202   PetscFunctionReturn(0);
5203 }
5204 #endif
5205 
5206 #if defined(PETSC_HAVE_TETGEN)
5207 #include <tetgen.h>
5208 #undef __FUNCT__
5209 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5210 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5211 {
5212   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5213   const PetscInt dim  = 3;
5214   ::tetgenio     in;
5215   ::tetgenio     out;
5216   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5217   PetscMPIInt    rank;
5218   PetscErrorCode ierr;
5219 
5220   PetscFunctionBegin;
5221   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5222   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5223   in.numberofpoints = vEnd - vStart;
5224   if (in.numberofpoints > 0) {
5225     PetscSection coordSection;
5226     Vec          coordinates;
5227     PetscScalar  *array;
5228 
5229     in.pointlist       = new double[in.numberofpoints*dim];
5230     in.pointmarkerlist = new int[in.numberofpoints];
5231 
5232     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5233     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5234     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5235     for (v = vStart; v < vEnd; ++v) {
5236       const PetscInt idx = v - vStart;
5237       PetscInt       off, d;
5238 
5239       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5240       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5241       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5242     }
5243     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5244   }
5245   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5246 
5247   in.numberoffacets = fEnd - fStart;
5248   if (in.numberoffacets > 0) {
5249     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5250     in.facetmarkerlist = new int[in.numberoffacets];
5251     for (f = fStart; f < fEnd; ++f) {
5252       const PetscInt idx     = f - fStart;
5253       PetscInt       *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5254 
5255       in.facetlist[idx].numberofpolygons = 1;
5256       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5257       in.facetlist[idx].numberofholes    = 0;
5258       in.facetlist[idx].holelist         = NULL;
5259 
5260       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5261       for (p = 0; p < numPoints*2; p += 2) {
5262         const PetscInt point = points[p];
5263         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5264       }
5265 
5266       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5267       poly->numberofvertices = numVertices;
5268       poly->vertexlist       = new int[poly->numberofvertices];
5269       for (v = 0; v < numVertices; ++v) {
5270         const PetscInt vIdx = points[v] - vStart;
5271         poly->vertexlist[v] = vIdx;
5272       }
5273       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5274       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5275     }
5276   }
5277   if (!rank) {
5278     char args[32];
5279 
5280     /* Take away 'Q' for verbose output */
5281     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5282     ::tetrahedralize(args, &in, &out);
5283   }
5284   {
5285     const PetscInt numCorners  = 4;
5286     const PetscInt numCells    = out.numberoftetrahedra;
5287     const PetscInt numVertices = out.numberofpoints;
5288     const int      *cells      = out.tetrahedronlist;
5289     const double   *meshCoords = out.pointlist;
5290 
5291     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5292     /* Set labels */
5293     for (v = 0; v < numVertices; ++v) {
5294       if (out.pointmarkerlist[v]) {
5295         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5296       }
5297     }
5298     if (interpolate) {
5299       PetscInt e;
5300 
5301       for (e = 0; e < out.numberofedges; e++) {
5302         if (out.edgemarkerlist[e]) {
5303           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5304           const PetscInt *edges;
5305           PetscInt       numEdges;
5306 
5307           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5308           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5309           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5310           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5311         }
5312       }
5313       for (f = 0; f < out.numberoftrifaces; f++) {
5314         if (out.trifacemarkerlist[f]) {
5315           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5316           const PetscInt *faces;
5317           PetscInt       numFaces;
5318 
5319           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5320           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5321           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5322           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5323         }
5324       }
5325     }
5326     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5327   }
5328   PetscFunctionReturn(0);
5329 }
5330 
5331 #undef __FUNCT__
5332 #define __FUNCT__ "DMPlexRefine_Tetgen"
5333 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5334 {
5335   MPI_Comm       comm = ((PetscObject) dm)->comm;
5336   const PetscInt dim  = 3;
5337   ::tetgenio     in;
5338   ::tetgenio     out;
5339   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5340   PetscMPIInt    rank;
5341   PetscErrorCode ierr;
5342 
5343   PetscFunctionBegin;
5344   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5345   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5346   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5347   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5348 
5349   in.numberofpoints = vEnd - vStart;
5350   if (in.numberofpoints > 0) {
5351     PetscSection coordSection;
5352     Vec          coordinates;
5353     PetscScalar  *array;
5354 
5355     in.pointlist       = new double[in.numberofpoints*dim];
5356     in.pointmarkerlist = new int[in.numberofpoints];
5357 
5358     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5359     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5360     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5361     for (v = vStart; v < vEnd; ++v) {
5362       const PetscInt idx = v - vStart;
5363       PetscInt       off, d;
5364 
5365       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5366       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5367       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5368     }
5369     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5370   }
5371   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5372 
5373   in.numberofcorners       = 4;
5374   in.numberoftetrahedra    = cEnd - cStart;
5375   in.tetrahedronvolumelist = (double*) maxVolumes;
5376   if (in.numberoftetrahedra > 0) {
5377     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5378     for (c = cStart; c < cEnd; ++c) {
5379       const PetscInt idx      = c - cStart;
5380       PetscInt       *closure = PETSC_NULL;
5381       PetscInt       closureSize;
5382 
5383       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5384       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5385       for (v = 0; v < 4; ++v) {
5386         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5387       }
5388       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5389     }
5390   }
5391   /* TODO: Put in boundary faces with markers */
5392   if (!rank) {
5393     char args[32];
5394 
5395     /* Take away 'Q' for verbose output */
5396     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5397     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5398     ::tetrahedralize(args, &in, &out);
5399   }
5400   in.tetrahedronvolumelist = NULL;
5401 
5402   {
5403     const PetscInt numCorners  = 4;
5404     const PetscInt numCells    = out.numberoftetrahedra;
5405     const PetscInt numVertices = out.numberofpoints;
5406     const int      *cells      = out.tetrahedronlist;
5407     const double   *meshCoords = out.pointlist;
5408     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5409 
5410     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5411     /* Set labels */
5412     for (v = 0; v < numVertices; ++v) {
5413       if (out.pointmarkerlist[v]) {
5414         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5415       }
5416     }
5417     if (interpolate) {
5418       PetscInt e, f;
5419 
5420       for (e = 0; e < out.numberofedges; e++) {
5421         if (out.edgemarkerlist[e]) {
5422           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5423           const PetscInt *edges;
5424           PetscInt       numEdges;
5425 
5426           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5427           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5428           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5429           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5430         }
5431       }
5432       for (f = 0; f < out.numberoftrifaces; f++) {
5433         if (out.trifacemarkerlist[f]) {
5434           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5435           const PetscInt *faces;
5436           PetscInt       numFaces;
5437 
5438           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5439           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5440           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5441           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5442         }
5443       }
5444     }
5445     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5446   }
5447   PetscFunctionReturn(0);
5448 }
5449 #endif
5450 
5451 #if defined(PETSC_HAVE_CTETGEN)
5452 #include "ctetgen.h"
5453 
5454 #undef __FUNCT__
5455 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5456 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5457 {
5458   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5459   const PetscInt dim  = 3;
5460   PLC            *in, *out;
5461   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5462   PetscMPIInt    rank;
5463   PetscErrorCode ierr;
5464 
5465   PetscFunctionBegin;
5466   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5467   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5468   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5469   ierr = PLCCreate(&in);CHKERRQ(ierr);
5470   ierr = PLCCreate(&out);CHKERRQ(ierr);
5471 
5472   in->numberofpoints = vEnd - vStart;
5473   if (in->numberofpoints > 0) {
5474     PetscSection coordSection;
5475     Vec          coordinates;
5476     PetscScalar  *array;
5477 
5478     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5479     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5480     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5481     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5482     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5483     for (v = vStart; v < vEnd; ++v) {
5484       const PetscInt idx = v - vStart;
5485       PetscInt       off, d, m;
5486 
5487       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5488       for (d = 0; d < dim; ++d) {
5489         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5490       }
5491       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5492 
5493       in->pointmarkerlist[idx] = (int) m;
5494     }
5495     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5496   }
5497   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5498 
5499   in->numberoffacets = fEnd - fStart;
5500   if (in->numberoffacets > 0) {
5501     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5502     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5503     for (f = fStart; f < fEnd; ++f) {
5504       const PetscInt idx     = f - fStart;
5505       PetscInt       *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5506       polygon        *poly;
5507 
5508       in->facetlist[idx].numberofpolygons = 1;
5509 
5510       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5511 
5512       in->facetlist[idx].numberofholes    = 0;
5513       in->facetlist[idx].holelist         = PETSC_NULL;
5514 
5515       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5516       for (p = 0; p < numPoints*2; p += 2) {
5517         const PetscInt point = points[p];
5518         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5519       }
5520 
5521       poly                   = in->facetlist[idx].polygonlist;
5522       poly->numberofvertices = numVertices;
5523       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5524       for (v = 0; v < numVertices; ++v) {
5525         const PetscInt vIdx = points[v] - vStart;
5526         poly->vertexlist[v] = vIdx;
5527       }
5528       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5529       in->facetmarkerlist[idx] = (int) m;
5530       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5531     }
5532   }
5533   if (!rank) {
5534     TetGenOpts t;
5535 
5536     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5537     t.in        = boundary; /* Should go away */
5538     t.plc       = 1;
5539     t.quality   = 1;
5540     t.edgesout  = 1;
5541     t.zeroindex = 1;
5542     t.quiet     = 1;
5543     t.verbose   = verbose;
5544     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5545     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5546   }
5547   {
5548     const PetscInt numCorners  = 4;
5549     const PetscInt numCells    = out->numberoftetrahedra;
5550     const PetscInt numVertices = out->numberofpoints;
5551     const int      *cells      = out->tetrahedronlist;
5552     const double   *meshCoords = out->pointlist;
5553 
5554     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5555     /* Set labels */
5556     for (v = 0; v < numVertices; ++v) {
5557       if (out->pointmarkerlist[v]) {
5558         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5559       }
5560     }
5561     if (interpolate) {
5562       PetscInt e;
5563 
5564       for (e = 0; e < out->numberofedges; e++) {
5565         if (out->edgemarkerlist[e]) {
5566           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5567           const PetscInt *edges;
5568           PetscInt       numEdges;
5569 
5570           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5571           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5572           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5573           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5574         }
5575       }
5576       for (f = 0; f < out->numberoftrifaces; f++) {
5577         if (out->trifacemarkerlist[f]) {
5578           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5579           const PetscInt *faces;
5580           PetscInt       numFaces;
5581 
5582           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5583           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5584           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5585           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5586         }
5587       }
5588     }
5589     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5590   }
5591 
5592   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5593   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5594   PetscFunctionReturn(0);
5595 }
5596 
5597 #undef __FUNCT__
5598 #define __FUNCT__ "DMPlexRefine_CTetgen"
5599 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5600 {
5601   MPI_Comm       comm = ((PetscObject) dm)->comm;
5602   const PetscInt dim  = 3;
5603   PLC            *in, *out;
5604   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5605   PetscMPIInt    rank;
5606   PetscErrorCode ierr;
5607 
5608   PetscFunctionBegin;
5609   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5610   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5611   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5612   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5613   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5614   ierr = PLCCreate(&in);CHKERRQ(ierr);
5615   ierr = PLCCreate(&out);CHKERRQ(ierr);
5616 
5617   in->numberofpoints = vEnd - vStart;
5618   if (in->numberofpoints > 0) {
5619     PetscSection coordSection;
5620     Vec          coordinates;
5621     PetscScalar  *array;
5622 
5623     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5624     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5625     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5626     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5627     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5628     for (v = vStart; v < vEnd; ++v) {
5629       const PetscInt idx = v - vStart;
5630       PetscInt       off, d, m;
5631 
5632       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5633       for (d = 0; d < dim; ++d) {
5634         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5635       }
5636       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5637 
5638       in->pointmarkerlist[idx] = (int) m;
5639     }
5640     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5641   }
5642   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5643 
5644   in->numberofcorners       = 4;
5645   in->numberoftetrahedra    = cEnd - cStart;
5646   in->tetrahedronvolumelist = maxVolumes;
5647   if (in->numberoftetrahedra > 0) {
5648     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5649     for (c = cStart; c < cEnd; ++c) {
5650       const PetscInt idx      = c - cStart;
5651       PetscInt       *closure = PETSC_NULL;
5652       PetscInt       closureSize;
5653 
5654       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5655       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5656       for (v = 0; v < 4; ++v) {
5657         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5658       }
5659       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5660     }
5661   }
5662   if (!rank) {
5663     TetGenOpts t;
5664 
5665     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5666 
5667     t.in        = dm; /* Should go away */
5668     t.refine    = 1;
5669     t.varvolume = 1;
5670     t.quality   = 1;
5671     t.edgesout  = 1;
5672     t.zeroindex = 1;
5673     t.quiet     = 1;
5674     t.verbose   = verbose; /* Change this */
5675 
5676     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5677     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5678   }
5679   {
5680     const PetscInt numCorners  = 4;
5681     const PetscInt numCells    = out->numberoftetrahedra;
5682     const PetscInt numVertices = out->numberofpoints;
5683     const int      *cells      = out->tetrahedronlist;
5684     const double   *meshCoords = out->pointlist;
5685     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5686 
5687     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5688     /* Set labels */
5689     for (v = 0; v < numVertices; ++v) {
5690       if (out->pointmarkerlist[v]) {
5691         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5692       }
5693     }
5694     if (interpolate) {
5695       PetscInt e, f;
5696 
5697       for (e = 0; e < out->numberofedges; e++) {
5698         if (out->edgemarkerlist[e]) {
5699           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5700           const PetscInt *edges;
5701           PetscInt       numEdges;
5702 
5703           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5704           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5705           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5706           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5707         }
5708       }
5709       for (f = 0; f < out->numberoftrifaces; f++) {
5710         if (out->trifacemarkerlist[f]) {
5711           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5712           const PetscInt *faces;
5713           PetscInt       numFaces;
5714 
5715           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5716           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5717           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5718           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5719         }
5720       }
5721     }
5722     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5723   }
5724   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5725   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5726   PetscFunctionReturn(0);
5727 }
5728 #endif
5729 
5730 #undef __FUNCT__
5731 #define __FUNCT__ "DMPlexGenerate"
5732 /*@C
5733   DMPlexGenerate - Generates a mesh.
5734 
5735   Not Collective
5736 
5737   Input Parameters:
5738 + boundary - The DMPlex boundary object
5739 . name - The mesh generation package name
5740 - interpolate - Flag to create intermediate mesh elements
5741 
5742   Output Parameter:
5743 . mesh - The DMPlex object
5744 
5745   Level: intermediate
5746 
5747 .keywords: mesh, elements
5748 .seealso: DMPlexCreate(), DMRefine()
5749 @*/
5750 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5751 {
5752   PetscInt       dim;
5753   char           genname[1024];
5754   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5755   PetscErrorCode ierr;
5756 
5757   PetscFunctionBegin;
5758   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5759   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5760   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5761   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5762   if (flg) name = genname;
5763   if (name) {
5764     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5765     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5766     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5767   }
5768   switch (dim) {
5769   case 1:
5770     if (!name || isTriangle) {
5771 #if defined(PETSC_HAVE_TRIANGLE)
5772       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5773 #else
5774       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5775 #endif
5776     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5777     break;
5778   case 2:
5779     if (!name || isCTetgen) {
5780 #if defined(PETSC_HAVE_CTETGEN)
5781       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5782 #else
5783       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5784 #endif
5785     } else if (isTetgen) {
5786 #if defined(PETSC_HAVE_TETGEN)
5787       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5788 #else
5789       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5790 #endif
5791     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5792     break;
5793   default:
5794     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5795   }
5796   PetscFunctionReturn(0);
5797 }
5798 
5799 typedef PetscInt CellRefiner;
5800 
5801 #undef __FUNCT__
5802 #define __FUNCT__ "GetDepthStart_Private"
5803 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5804 {
5805   PetscFunctionBegin;
5806   if (cStart) *cStart = 0;
5807   if (vStart) *vStart = depthSize[depth];
5808   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5809   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5810   PetscFunctionReturn(0);
5811 }
5812 
5813 #undef __FUNCT__
5814 #define __FUNCT__ "GetDepthEnd_Private"
5815 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5816 {
5817   PetscFunctionBegin;
5818   if (cEnd) *cEnd = depthSize[depth];
5819   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5820   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5821   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5822   PetscFunctionReturn(0);
5823 }
5824 
5825 #undef __FUNCT__
5826 #define __FUNCT__ "CellRefinerGetSizes"
5827 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5828 {
5829   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5830   PetscErrorCode ierr;
5831 
5832   PetscFunctionBegin;
5833   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5834   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5835   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5836   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5837   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5838   switch (refiner) {
5839   case 1:
5840     /* Simplicial 2D */
5841     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5842     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5843     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5844     break;
5845   case 3:
5846     /* Hybrid 2D */
5847     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5848     cMax = PetscMin(cEnd, cMax);
5849     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5850     fMax         = PetscMin(fEnd, fMax);
5851     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5852     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 */
5853     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5854     break;
5855   case 2:
5856     /* Hex 2D */
5857     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5858     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5859     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5860     break;
5861   default:
5862     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5863   }
5864   PetscFunctionReturn(0);
5865 }
5866 
5867 #undef __FUNCT__
5868 #define __FUNCT__ "CellRefinerSetConeSizes"
5869 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5870 {
5871   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5872   PetscErrorCode ierr;
5873 
5874   PetscFunctionBegin;
5875   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5876   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5877   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5878   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5879   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5880   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5881   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5882   switch (refiner) {
5883   case 1:
5884     /* Simplicial 2D */
5885     /* All cells have 3 faces */
5886     for (c = cStart; c < cEnd; ++c) {
5887       for (r = 0; r < 4; ++r) {
5888         const PetscInt newp = (c - cStart)*4 + r;
5889 
5890         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5891       }
5892     }
5893     /* Split faces have 2 vertices and the same cells as the parent */
5894     for (f = fStart; f < fEnd; ++f) {
5895       for (r = 0; r < 2; ++r) {
5896         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5897         PetscInt       size;
5898 
5899         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5900         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5901         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5902       }
5903     }
5904     /* Interior faces have 2 vertices and 2 cells */
5905     for (c = cStart; c < cEnd; ++c) {
5906       for (r = 0; r < 3; ++r) {
5907         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5908 
5909         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5910         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5911       }
5912     }
5913     /* Old vertices have identical supports */
5914     for (v = vStart; v < vEnd; ++v) {
5915       const PetscInt newp = vStartNew + (v - vStart);
5916       PetscInt       size;
5917 
5918       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5919       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5920     }
5921     /* Face vertices have 2 + cells*2 supports */
5922     for (f = fStart; f < fEnd; ++f) {
5923       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5924       PetscInt       size;
5925 
5926       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5927       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5928     }
5929     break;
5930   case 2:
5931     /* Hex 2D */
5932     /* All cells have 4 faces */
5933     for (c = cStart; c < cEnd; ++c) {
5934       for (r = 0; r < 4; ++r) {
5935         const PetscInt newp = (c - cStart)*4 + r;
5936 
5937         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5938       }
5939     }
5940     /* Split faces have 2 vertices and the same cells as the parent */
5941     for (f = fStart; f < fEnd; ++f) {
5942       for (r = 0; r < 2; ++r) {
5943         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5944         PetscInt       size;
5945 
5946         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5947         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5948         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5949       }
5950     }
5951     /* Interior faces have 2 vertices and 2 cells */
5952     for (c = cStart; c < cEnd; ++c) {
5953       for (r = 0; r < 4; ++r) {
5954         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5955 
5956         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5957         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5958       }
5959     }
5960     /* Old vertices have identical supports */
5961     for (v = vStart; v < vEnd; ++v) {
5962       const PetscInt newp = vStartNew + (v - vStart);
5963       PetscInt       size;
5964 
5965       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5966       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5967     }
5968     /* Face vertices have 2 + cells supports */
5969     for (f = fStart; f < fEnd; ++f) {
5970       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5971       PetscInt       size;
5972 
5973       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5974       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5975     }
5976     /* Cell vertices have 4 supports */
5977     for (c = cStart; c < cEnd; ++c) {
5978       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5979 
5980       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5981     }
5982     break;
5983   case 3:
5984     /* Hybrid 2D */
5985     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5986     cMax = PetscMin(cEnd, cMax);
5987     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5988     fMax = PetscMin(fEnd, fMax);
5989     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5990     /* Interior cells have 3 faces */
5991     for (c = cStart; c < cMax; ++c) {
5992       for (r = 0; r < 4; ++r) {
5993         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5994 
5995         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5996       }
5997     }
5998     /* Hybrid cells have 4 faces */
5999     for (c = cMax; c < cEnd; ++c) {
6000       for (r = 0; r < 2; ++r) {
6001         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6002 
6003         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6004       }
6005     }
6006     /* Interior split faces have 2 vertices and the same cells as the parent */
6007     for (f = fStart; f < fMax; ++f) {
6008       for (r = 0; r < 2; ++r) {
6009         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6010         PetscInt       size;
6011 
6012         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6013         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6014         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6015       }
6016     }
6017     /* Interior cell faces have 2 vertices and 2 cells */
6018     for (c = cStart; c < cMax; ++c) {
6019       for (r = 0; r < 3; ++r) {
6020         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6021 
6022         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6023         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6024       }
6025     }
6026     /* Hybrid faces have 2 vertices and the same cells */
6027     for (f = fMax; f < fEnd; ++f) {
6028       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6029       PetscInt       size;
6030 
6031       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6032       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6033       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6034     }
6035     /* Hybrid cell faces have 2 vertices and 2 cells */
6036     for (c = cMax; c < cEnd; ++c) {
6037       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6038 
6039       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6040       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6041     }
6042     /* Old vertices have identical supports */
6043     for (v = vStart; v < vEnd; ++v) {
6044       const PetscInt newp = vStartNew + (v - vStart);
6045       PetscInt       size;
6046 
6047       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6048       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6049     }
6050     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6051     for (f = fStart; f < fMax; ++f) {
6052       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6053       const PetscInt *support;
6054       PetscInt       size, newSize = 2, s;
6055 
6056       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6057       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6058       for (s = 0; s < size; ++s) {
6059         if (support[s] >= cMax) newSize += 1;
6060         else newSize += 2;
6061       }
6062       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6063     }
6064     break;
6065   default:
6066     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6067   }
6068   PetscFunctionReturn(0);
6069 }
6070 
6071 #undef __FUNCT__
6072 #define __FUNCT__ "CellRefinerSetCones"
6073 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6074 {
6075   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;
6076   PetscInt       maxSupportSize, *supportRef;
6077   PetscErrorCode ierr;
6078 
6079   PetscFunctionBegin;
6080   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6081   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6082   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6083   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6084   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6085   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6086   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6087   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6088   switch (refiner) {
6089   case 1:
6090     /* Simplicial 2D */
6091     /*
6092      2
6093      |\
6094      | \
6095      |  \
6096      |   \
6097      | C  \
6098      |     \
6099      |      \
6100      2---1---1
6101      |\  D  / \
6102      | 2   0   \
6103      |A \ /  B  \
6104      0---0-------1
6105      */
6106     /* All cells have 3 faces */
6107     for (c = cStart; c < cEnd; ++c) {
6108       const PetscInt newp = cStartNew + (c - cStart)*4;
6109       const PetscInt *cone, *ornt;
6110       PetscInt       coneNew[3], orntNew[3];
6111 
6112       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6113       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6114       /* A triangle */
6115       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6116       orntNew[0] = ornt[0];
6117       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6118       orntNew[1] = -2;
6119       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6120       orntNew[2] = ornt[2];
6121       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6122       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6123 #if 1
6124       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);
6125       for (p = 0; p < 3; ++p) {
6126         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);
6127       }
6128 #endif
6129       /* B triangle */
6130       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6131       orntNew[0] = ornt[0];
6132       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6133       orntNew[1] = ornt[1];
6134       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6135       orntNew[2] = -2;
6136       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6137       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6138 #if 1
6139       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);
6140       for (p = 0; p < 3; ++p) {
6141         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);
6142       }
6143 #endif
6144       /* C triangle */
6145       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6146       orntNew[0] = -2;
6147       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6148       orntNew[1] = ornt[1];
6149       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6150       orntNew[2] = ornt[2];
6151       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6152       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6153 #if 1
6154       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);
6155       for (p = 0; p < 3; ++p) {
6156         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);
6157       }
6158 #endif
6159       /* D triangle */
6160       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6161       orntNew[0] = 0;
6162       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6163       orntNew[1] = 0;
6164       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6165       orntNew[2] = 0;
6166       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6167       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6168 #if 1
6169       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);
6170       for (p = 0; p < 3; ++p) {
6171         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);
6172       }
6173 #endif
6174     }
6175     /* Split faces have 2 vertices and the same cells as the parent */
6176     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6177     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6178     for (f = fStart; f < fEnd; ++f) {
6179       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6180 
6181       for (r = 0; r < 2; ++r) {
6182         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6183         const PetscInt *cone, *support;
6184         PetscInt       coneNew[2], coneSize, c, supportSize, s;
6185 
6186         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6187         coneNew[0]       = vStartNew + (cone[0] - vStart);
6188         coneNew[1]       = vStartNew + (cone[1] - vStart);
6189         coneNew[(r+1)%2] = newv;
6190         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6191 #if 1
6192         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6193         for (p = 0; p < 2; ++p) {
6194           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);
6195         }
6196 #endif
6197         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6198         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6199         for (s = 0; s < supportSize; ++s) {
6200           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6201           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6202           for (c = 0; c < coneSize; ++c) {
6203             if (cone[c] == f) break;
6204           }
6205           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6206         }
6207         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6208 #if 1
6209         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6210         for (p = 0; p < supportSize; ++p) {
6211           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);
6212         }
6213 #endif
6214       }
6215     }
6216     /* Interior faces have 2 vertices and 2 cells */
6217     for (c = cStart; c < cEnd; ++c) {
6218       const PetscInt *cone;
6219 
6220       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6221       for (r = 0; r < 3; ++r) {
6222         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6223         PetscInt       coneNew[2];
6224         PetscInt       supportNew[2];
6225 
6226         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6227         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6228         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6229 #if 1
6230         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6231         for (p = 0; p < 2; ++p) {
6232           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);
6233         }
6234 #endif
6235         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6236         supportNew[1] = (c - cStart)*4 + 3;
6237         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6238 #if 1
6239         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6240         for (p = 0; p < 2; ++p) {
6241           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);
6242         }
6243 #endif
6244       }
6245     }
6246     /* Old vertices have identical supports */
6247     for (v = vStart; v < vEnd; ++v) {
6248       const PetscInt newp = vStartNew + (v - vStart);
6249       const PetscInt *support, *cone;
6250       PetscInt       size, s;
6251 
6252       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6253       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6254       for (s = 0; s < size; ++s) {
6255         PetscInt r = 0;
6256 
6257         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6258         if (cone[1] == v) r = 1;
6259         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6260       }
6261       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6262 #if 1
6263       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6264       for (p = 0; p < size; ++p) {
6265         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);
6266       }
6267 #endif
6268     }
6269     /* Face vertices have 2 + cells*2 supports */
6270     for (f = fStart; f < fEnd; ++f) {
6271       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6272       const PetscInt *cone, *support;
6273       PetscInt       size, s;
6274 
6275       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6276       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6277       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6278       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6279       for (s = 0; s < size; ++s) {
6280         PetscInt r = 0;
6281 
6282         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6283         if      (cone[1] == f) r = 1;
6284         else if (cone[2] == f) r = 2;
6285         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6286         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6287       }
6288       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6289 #if 1
6290       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6291       for (p = 0; p < 2+size*2; ++p) {
6292         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);
6293       }
6294 #endif
6295     }
6296     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6297     break;
6298   case 2:
6299     /* Hex 2D */
6300     /*
6301      3---------2---------2
6302      |         |         |
6303      |    D    2    C    |
6304      |         |         |
6305      3----3----0----1----1
6306      |         |         |
6307      |    A    0    B    |
6308      |         |         |
6309      0---------0---------1
6310      */
6311     /* All cells have 4 faces */
6312     for (c = cStart; c < cEnd; ++c) {
6313       const PetscInt newp = (c - cStart)*4;
6314       const PetscInt *cone, *ornt;
6315       PetscInt       coneNew[4], orntNew[4];
6316 
6317       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6318       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6319       /* A quad */
6320       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6321       orntNew[0] = ornt[0];
6322       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6323       orntNew[1] = 0;
6324       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6325       orntNew[2] = -2;
6326       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6327       orntNew[3] = ornt[3];
6328       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6329       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6330 #if 1
6331       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);
6332       for (p = 0; p < 4; ++p) {
6333         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);
6334       }
6335 #endif
6336       /* B quad */
6337       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6338       orntNew[0] = ornt[0];
6339       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6340       orntNew[1] = ornt[1];
6341       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6342       orntNew[2] = 0;
6343       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6344       orntNew[3] = -2;
6345       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6346       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6347 #if 1
6348       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);
6349       for (p = 0; p < 4; ++p) {
6350         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);
6351       }
6352 #endif
6353       /* C quad */
6354       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6355       orntNew[0] = -2;
6356       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6357       orntNew[1] = ornt[1];
6358       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6359       orntNew[2] = ornt[2];
6360       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6361       orntNew[3] = 0;
6362       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6363       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6364 #if 1
6365       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);
6366       for (p = 0; p < 4; ++p) {
6367         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);
6368       }
6369 #endif
6370       /* D quad */
6371       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6372       orntNew[0] = 0;
6373       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6374       orntNew[1] = -2;
6375       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6376       orntNew[2] = ornt[2];
6377       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6378       orntNew[3] = ornt[3];
6379       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6380       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6381 #if 1
6382       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);
6383       for (p = 0; p < 4; ++p) {
6384         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);
6385       }
6386 #endif
6387     }
6388     /* Split faces have 2 vertices and the same cells as the parent */
6389     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6390     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6391     for (f = fStart; f < fEnd; ++f) {
6392       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6393 
6394       for (r = 0; r < 2; ++r) {
6395         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6396         const PetscInt *cone, *support;
6397         PetscInt       coneNew[2], coneSize, c, supportSize, s;
6398 
6399         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6400         coneNew[0]       = vStartNew + (cone[0] - vStart);
6401         coneNew[1]       = vStartNew + (cone[1] - vStart);
6402         coneNew[(r+1)%2] = newv;
6403         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6404 #if 1
6405         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6406         for (p = 0; p < 2; ++p) {
6407           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);
6408         }
6409 #endif
6410         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6411         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6412         for (s = 0; s < supportSize; ++s) {
6413           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6414           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6415           for (c = 0; c < coneSize; ++c) {
6416             if (cone[c] == f) break;
6417           }
6418           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6419         }
6420         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6421 #if 1
6422         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6423         for (p = 0; p < supportSize; ++p) {
6424           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);
6425         }
6426 #endif
6427       }
6428     }
6429     /* Interior faces have 2 vertices and 2 cells */
6430     for (c = cStart; c < cEnd; ++c) {
6431       const PetscInt *cone;
6432       PetscInt       coneNew[2], supportNew[2];
6433 
6434       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6435       for (r = 0; r < 4; ++r) {
6436         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6437 
6438         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6439         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6440         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6441 #if 1
6442         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6443         for (p = 0; p < 2; ++p) {
6444           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);
6445         }
6446 #endif
6447         supportNew[0] = (c - cStart)*4 + r;
6448         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6449         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6450 #if 1
6451         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6452         for (p = 0; p < 2; ++p) {
6453           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);
6454         }
6455 #endif
6456       }
6457     }
6458     /* Old vertices have identical supports */
6459     for (v = vStart; v < vEnd; ++v) {
6460       const PetscInt newp = vStartNew + (v - vStart);
6461       const PetscInt *support, *cone;
6462       PetscInt       size, s;
6463 
6464       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6465       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6466       for (s = 0; s < size; ++s) {
6467         PetscInt r = 0;
6468 
6469         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6470         if (cone[1] == v) r = 1;
6471         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6472       }
6473       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6474 #if 1
6475       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6476       for (p = 0; p < size; ++p) {
6477         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);
6478       }
6479 #endif
6480     }
6481     /* Face vertices have 2 + cells supports */
6482     for (f = fStart; f < fEnd; ++f) {
6483       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6484       const PetscInt *cone, *support;
6485       PetscInt       size, s;
6486 
6487       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6488       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6489       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6490       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6491       for (s = 0; s < size; ++s) {
6492         PetscInt r = 0;
6493 
6494         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6495         if      (cone[1] == f) r = 1;
6496         else if (cone[2] == f) r = 2;
6497         else if (cone[3] == f) r = 3;
6498         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6499       }
6500       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6501 #if 1
6502       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6503       for (p = 0; p < 2+size; ++p) {
6504         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);
6505       }
6506 #endif
6507     }
6508     /* Cell vertices have 4 supports */
6509     for (c = cStart; c < cEnd; ++c) {
6510       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6511       PetscInt       supportNew[4];
6512 
6513       for (r = 0; r < 4; ++r) {
6514         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6515       }
6516       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6517     }
6518     break;
6519   case 3:
6520     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6521     cMax = PetscMin(cEnd, cMax);
6522     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6523     fMax = PetscMin(fEnd, fMax);
6524     /* Interior cells have 3 faces */
6525     for (c = cStart; c < cMax; ++c) {
6526       const PetscInt newp = cStartNew + (c - cStart)*4;
6527       const PetscInt *cone, *ornt;
6528       PetscInt       coneNew[3], orntNew[3];
6529 
6530       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6531       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6532       /* A triangle */
6533       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6534       orntNew[0] = ornt[0];
6535       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6536       orntNew[1] = -2;
6537       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6538       orntNew[2] = ornt[2];
6539       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6540       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6541 #if 1
6542       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);
6543       for (p = 0; p < 3; ++p) {
6544         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);
6545       }
6546 #endif
6547       /* B triangle */
6548       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6549       orntNew[0] = ornt[0];
6550       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6551       orntNew[1] = ornt[1];
6552       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6553       orntNew[2] = -2;
6554       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6555       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6556 #if 1
6557       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);
6558       for (p = 0; p < 3; ++p) {
6559         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);
6560       }
6561 #endif
6562       /* C triangle */
6563       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6564       orntNew[0] = -2;
6565       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6566       orntNew[1] = ornt[1];
6567       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6568       orntNew[2] = ornt[2];
6569       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6570       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6571 #if 1
6572       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);
6573       for (p = 0; p < 3; ++p) {
6574         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);
6575       }
6576 #endif
6577       /* D triangle */
6578       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6579       orntNew[0] = 0;
6580       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6581       orntNew[1] = 0;
6582       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6583       orntNew[2] = 0;
6584       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6585       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6586 #if 1
6587       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);
6588       for (p = 0; p < 3; ++p) {
6589         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);
6590       }
6591 #endif
6592     }
6593     /*
6594      2----3----3
6595      |         |
6596      |    B    |
6597      |         |
6598      0----4--- 1
6599      |         |
6600      |    A    |
6601      |         |
6602      0----2----1
6603      */
6604     /* Hybrid cells have 4 faces */
6605     for (c = cMax; c < cEnd; ++c) {
6606       const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6607       const PetscInt *cone, *ornt;
6608       PetscInt       coneNew[4], orntNew[4];
6609 
6610       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6611       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6612       /* A quad */
6613       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6614       orntNew[0] = ornt[0];
6615       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6616       orntNew[1] = ornt[1];
6617       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6618       orntNew[2] = 0;
6619       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6620       orntNew[3] = 0;
6621       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6622       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6623 #if 1
6624       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);
6625       for (p = 0; p < 4; ++p) {
6626         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);
6627       }
6628 #endif
6629       /* B quad */
6630       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6631       orntNew[0] = ornt[0];
6632       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6633       orntNew[1] = ornt[1];
6634       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6635       orntNew[2] = 0;
6636       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6637       orntNew[3] = 0;
6638       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6639       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6640 #if 1
6641       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);
6642       for (p = 0; p < 4; ++p) {
6643         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);
6644       }
6645 #endif
6646     }
6647     /* Interior split faces have 2 vertices and the same cells as the parent */
6648     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6649     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6650     for (f = fStart; f < fMax; ++f) {
6651       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6652 
6653       for (r = 0; r < 2; ++r) {
6654         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6655         const PetscInt *cone, *support;
6656         PetscInt       coneNew[2], coneSize, c, supportSize, s;
6657 
6658         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6659         coneNew[0]       = vStartNew + (cone[0] - vStart);
6660         coneNew[1]       = vStartNew + (cone[1] - vStart);
6661         coneNew[(r+1)%2] = newv;
6662         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6663 #if 1
6664         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6665         for (p = 0; p < 2; ++p) {
6666           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);
6667         }
6668 #endif
6669         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6670         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6671         for (s = 0; s < supportSize; ++s) {
6672           if (support[s] >= cMax) {
6673             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6674           } else {
6675             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6676             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6677             for (c = 0; c < coneSize; ++c) {
6678               if (cone[c] == f) break;
6679             }
6680             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6681           }
6682         }
6683         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6684 #if 1
6685         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6686         for (p = 0; p < supportSize; ++p) {
6687           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);
6688         }
6689 #endif
6690       }
6691     }
6692     /* Interior cell faces have 2 vertices and 2 cells */
6693     for (c = cStart; c < cMax; ++c) {
6694       const PetscInt *cone;
6695 
6696       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6697       for (r = 0; r < 3; ++r) {
6698         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6699         PetscInt       coneNew[2];
6700         PetscInt       supportNew[2];
6701 
6702         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6703         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6704         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6705 #if 1
6706         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6707         for (p = 0; p < 2; ++p) {
6708           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);
6709         }
6710 #endif
6711         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6712         supportNew[1] = (c - cStart)*4 + 3;
6713         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6714 #if 1
6715         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6716         for (p = 0; p < 2; ++p) {
6717           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);
6718         }
6719 #endif
6720       }
6721     }
6722     /* Interior hybrid faces have 2 vertices and the same cells */
6723     for (f = fMax; f < fEnd; ++f) {
6724       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6725       const PetscInt *cone;
6726       const PetscInt *support;
6727       PetscInt       coneNew[2];
6728       PetscInt       supportNew[2];
6729       PetscInt       size, s, r;
6730 
6731       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6732       coneNew[0] = vStartNew + (cone[0] - vStart);
6733       coneNew[1] = vStartNew + (cone[1] - vStart);
6734       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6735 #if 1
6736       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6737       for (p = 0; p < 2; ++p) {
6738         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);
6739       }
6740 #endif
6741       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6742       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6743       for (s = 0; s < size; ++s) {
6744         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6745         for (r = 0; r < 2; ++r) {
6746           if (cone[r+2] == f) break;
6747         }
6748         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6749       }
6750       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6751 #if 1
6752       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6753       for (p = 0; p < size; ++p) {
6754         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);
6755       }
6756 #endif
6757     }
6758     /* Cell hybrid faces have 2 vertices and 2 cells */
6759     for (c = cMax; c < cEnd; ++c) {
6760       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6761       const PetscInt *cone;
6762       PetscInt       coneNew[2];
6763       PetscInt       supportNew[2];
6764 
6765       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6766       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6767       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6768       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6769 #if 1
6770       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6771       for (p = 0; p < 2; ++p) {
6772         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);
6773       }
6774 #endif
6775       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6776       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6777       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6778 #if 1
6779       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6780       for (p = 0; p < 2; ++p) {
6781         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);
6782       }
6783 #endif
6784     }
6785     /* Old vertices have identical supports */
6786     for (v = vStart; v < vEnd; ++v) {
6787       const PetscInt newp = vStartNew + (v - vStart);
6788       const PetscInt *support, *cone;
6789       PetscInt       size, s;
6790 
6791       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6792       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6793       for (s = 0; s < size; ++s) {
6794         if (support[s] >= fMax) {
6795           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6796         } else {
6797           PetscInt r = 0;
6798 
6799           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6800           if (cone[1] == v) r = 1;
6801           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6802         }
6803       }
6804       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6805 #if 1
6806       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6807       for (p = 0; p < size; ++p) {
6808         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);
6809       }
6810 #endif
6811     }
6812     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6813     for (f = fStart; f < fMax; ++f) {
6814       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6815       const PetscInt *cone, *support;
6816       PetscInt       size, newSize = 2, s;
6817 
6818       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6819       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6820       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6821       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6822       for (s = 0; s < size; ++s) {
6823         PetscInt r = 0;
6824 
6825         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6826         if (support[s] >= cMax) {
6827           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6828 
6829           newSize += 1;
6830         } else {
6831           if      (cone[1] == f) r = 1;
6832           else if (cone[2] == f) r = 2;
6833           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6834           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6835 
6836           newSize += 2;
6837         }
6838       }
6839       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6840 #if 1
6841       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6842       for (p = 0; p < newSize; ++p) {
6843         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);
6844       }
6845 #endif
6846     }
6847     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6848     break;
6849   default:
6850     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6851   }
6852   PetscFunctionReturn(0);
6853 }
6854 
6855 #undef __FUNCT__
6856 #define __FUNCT__ "CellRefinerSetCoordinates"
6857 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6858 {
6859   PetscSection   coordSection, coordSectionNew;
6860   Vec            coordinates, coordinatesNew;
6861   PetscScalar    *coords, *coordsNew;
6862   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6863   PetscErrorCode ierr;
6864 
6865   PetscFunctionBegin;
6866   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6867   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6868   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6869   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6870   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6871   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6872   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6873   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6874   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6875   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6876   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6877   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6878   if (fMax < 0) fMax = fEnd;
6879   switch (refiner) {
6880   case 1:
6881   case 2:
6882   case 3:
6883     /* Simplicial and Hex 2D */
6884     /* All vertices have the dim coordinates */
6885     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6886       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6887       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6888     }
6889     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6890     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6891     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6892     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6893     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6894     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6895     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6896     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6897     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6898     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6899     /* Old vertices have the same coordinates */
6900     for (v = vStart; v < vEnd; ++v) {
6901       const PetscInt newv = vStartNew + (v - vStart);
6902       PetscInt       off, offnew, d;
6903 
6904       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6905       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6906       for (d = 0; d < dim; ++d) {
6907         coordsNew[offnew+d] = coords[off+d];
6908       }
6909     }
6910     /* Face vertices have the average of endpoint coordinates */
6911     for (f = fStart; f < fMax; ++f) {
6912       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6913       const PetscInt *cone;
6914       PetscInt       coneSize, offA, offB, offnew, d;
6915 
6916       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6917       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6918       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6919       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6920       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6921       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6922       for (d = 0; d < dim; ++d) {
6923         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6924       }
6925     }
6926     /* Just Hex 2D */
6927     if (refiner == 2) {
6928       /* Cell vertices have the average of corner coordinates */
6929       for (c = cStart; c < cEnd; ++c) {
6930         const PetscInt newv  = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6931         PetscInt       *cone = PETSC_NULL;
6932         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6933 
6934         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6935         for (p = 0; p < closureSize*2; p += 2) {
6936           const PetscInt point = cone[p];
6937           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6938         }
6939         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6940         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6941         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6942         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6943         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6944         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6945         for (d = 0; d < dim; ++d) {
6946           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6947         }
6948         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6949       }
6950     }
6951     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6952     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6953     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6954     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6955     break;
6956   default:
6957     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6958   }
6959   PetscFunctionReturn(0);
6960 }
6961 
6962 #undef __FUNCT__
6963 #define __FUNCT__ "DMPlexCreateProcessSF"
6964 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6965 {
6966   PetscInt          numRoots, numLeaves, l;
6967   const PetscInt    *localPoints;
6968   const PetscSFNode *remotePoints;
6969   PetscInt          *localPointsNew;
6970   PetscSFNode       *remotePointsNew;
6971   PetscInt          *ranks, *ranksNew;
6972   PetscErrorCode    ierr;
6973 
6974   PetscFunctionBegin;
6975   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6976   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6977   for (l = 0; l < numLeaves; ++l) {
6978     ranks[l] = remotePoints[l].rank;
6979   }
6980   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6981   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6982   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6983   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6984   for (l = 0; l < numLeaves; ++l) {
6985     ranksNew[l]              = ranks[l];
6986     localPointsNew[l]        = l;
6987     remotePointsNew[l].index = 0;
6988     remotePointsNew[l].rank  = ranksNew[l];
6989   }
6990   ierr = PetscFree(ranks);CHKERRQ(ierr);
6991   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6992   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6993   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6994   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6995   PetscFunctionReturn(0);
6996 }
6997 
6998 #undef __FUNCT__
6999 #define __FUNCT__ "CellRefinerCreateSF"
7000 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7001 {
7002   PetscSF           sf, sfNew, sfProcess;
7003   IS                processRanks;
7004   MPI_Datatype      depthType;
7005   PetscInt          numRoots, numLeaves, numLeavesNew = 0, l, m;
7006   const PetscInt    *localPoints, *neighbors;
7007   const PetscSFNode *remotePoints;
7008   PetscInt          *localPointsNew;
7009   PetscSFNode       *remotePointsNew;
7010   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7011   PetscInt          depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7012   PetscErrorCode    ierr;
7013 
7014   PetscFunctionBegin;
7015   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7016   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7017   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7018   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7019   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7020   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7021   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7022   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7023   switch (refiner) {
7024   case 3:
7025     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7026     cMax = PetscMin(cEnd, cMax);
7027     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7028     fMax = PetscMin(fEnd, fMax);
7029   }
7030   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7031   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7032   /* Caculate size of new SF */
7033   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7034   if (numRoots < 0) PetscFunctionReturn(0);
7035   for (l = 0; l < numLeaves; ++l) {
7036     const PetscInt p = localPoints[l];
7037 
7038     switch (refiner) {
7039     case 1:
7040       /* Simplicial 2D */
7041       if ((p >= vStart) && (p < vEnd)) {
7042         /* Old vertices stay the same */
7043         ++numLeavesNew;
7044       } else if ((p >= fStart) && (p < fEnd)) {
7045         /* Old faces add new faces and vertex */
7046         numLeavesNew += 1 + 2;
7047       } else if ((p >= cStart) && (p < cEnd)) {
7048         /* Old cells add new cells and interior faces */
7049         numLeavesNew += 4 + 3;
7050       }
7051       break;
7052     case 2:
7053       /* Hex 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 + 4;
7063       }
7064       break;
7065     default:
7066       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7067     }
7068   }
7069   /* Communicate depthSizes for each remote rank */
7070   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7071   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7072   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7073   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);
7074   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7075   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7076   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7077   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7078   for (n = 0; n < numNeighbors; ++n) {
7079     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7080   }
7081   depthSizeOld[depth]   = cMax;
7082   depthSizeOld[0]       = vMax;
7083   depthSizeOld[depth-1] = fMax;
7084   depthSizeOld[1]       = eMax;
7085 
7086   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7087   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7088 
7089   depthSizeOld[depth]   = cEnd - cStart;
7090   depthSizeOld[0]       = vEnd - vStart;
7091   depthSizeOld[depth-1] = fEnd - fStart;
7092   depthSizeOld[1]       = eEnd - eStart;
7093 
7094   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7095   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7096   for (n = 0; n < numNeighbors; ++n) {
7097     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7098   }
7099   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7100   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7101   /* Calculate new point SF */
7102   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7103   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7104   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7105   for (l = 0, m = 0; l < numLeaves; ++l) {
7106     PetscInt    p     = localPoints[l];
7107     PetscInt    rp    = remotePoints[l].index, n;
7108     PetscMPIInt rrank = remotePoints[l].rank;
7109 
7110     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7111     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7112     switch (refiner) {
7113     case 1:
7114       /* Simplicial 2D */
7115       if ((p >= vStart) && (p < vEnd)) {
7116         /* Old vertices stay the same */
7117         localPointsNew[m]        = vStartNew     + (p  - vStart);
7118         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7119         remotePointsNew[m].rank  = rrank;
7120         ++m;
7121       } else if ((p >= fStart) && (p < fEnd)) {
7122         /* Old faces add new faces and vertex */
7123         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7124         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7125         remotePointsNew[m].rank  = rrank;
7126         ++m;
7127         for (r = 0; r < 2; ++r, ++m) {
7128           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7129           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7130           remotePointsNew[m].rank  = rrank;
7131         }
7132       } else if ((p >= cStart) && (p < cEnd)) {
7133         /* Old cells add new cells and interior faces */
7134         for (r = 0; r < 4; ++r, ++m) {
7135           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7136           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7137           remotePointsNew[m].rank  = rrank;
7138         }
7139         for (r = 0; r < 3; ++r, ++m) {
7140           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7141           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7142           remotePointsNew[m].rank  = rrank;
7143         }
7144       }
7145       break;
7146     case 2:
7147       /* Hex 2D */
7148       if ((p >= vStart) && (p < vEnd)) {
7149         /* Old vertices stay the same */
7150         localPointsNew[m]        = vStartNew     + (p  - vStart);
7151         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7152         remotePointsNew[m].rank  = rrank;
7153         ++m;
7154       } else if ((p >= fStart) && (p < fEnd)) {
7155         /* Old faces add new faces and vertex */
7156         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7157         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7158         remotePointsNew[m].rank  = rrank;
7159         ++m;
7160         for (r = 0; r < 2; ++r, ++m) {
7161           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7162           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7163           remotePointsNew[m].rank  = rrank;
7164         }
7165       } else if ((p >= cStart) && (p < cEnd)) {
7166         /* Old cells add new cells and interior faces */
7167         for (r = 0; r < 4; ++r, ++m) {
7168           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7169           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7170           remotePointsNew[m].rank  = rrank;
7171         }
7172         for (r = 0; r < 4; ++r, ++m) {
7173           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7174           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7175           remotePointsNew[m].rank  = rrank;
7176         }
7177       }
7178       break;
7179     case 3:
7180       /* Hybrid simplicial 2D */
7181       if ((p >= vStart) && (p < vEnd)) {
7182         /* Old vertices stay the same */
7183         localPointsNew[m]        = vStartNew     + (p  - vStart);
7184         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7185         remotePointsNew[m].rank  = rrank;
7186         ++m;
7187       } else if ((p >= fStart) && (p < fMax)) {
7188         /* Old interior faces add new faces and vertex */
7189         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7190         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7191         remotePointsNew[m].rank  = rrank;
7192         ++m;
7193         for (r = 0; r < 2; ++r, ++m) {
7194           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7195           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7196           remotePointsNew[m].rank  = rrank;
7197         }
7198       } else if ((p >= fMax) && (p < fEnd)) {
7199         /* Old hybrid faces stay the same */
7200         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7201         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7202         remotePointsNew[m].rank  = rrank;
7203         ++m;
7204       } else if ((p >= cStart) && (p < cMax)) {
7205         /* Old interior cells add new cells and interior faces */
7206         for (r = 0; r < 4; ++r, ++m) {
7207           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7208           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7209           remotePointsNew[m].rank  = rrank;
7210         }
7211         for (r = 0; r < 3; ++r, ++m) {
7212           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7213           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7214           remotePointsNew[m].rank  = rrank;
7215         }
7216       } else if ((p >= cStart) && (p < cMax)) {
7217         /* Old hybrid cells add new cells and hybrid face */
7218         for (r = 0; r < 2; ++r, ++m) {
7219           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7220           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7221           remotePointsNew[m].rank  = rrank;
7222         }
7223         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7224         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]);
7225         remotePointsNew[m].rank  = rrank;
7226         ++m;
7227       }
7228       break;
7229     default:
7230       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7231     }
7232   }
7233   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7234   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7235   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7236   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7237   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7238   PetscFunctionReturn(0);
7239 }
7240 
7241 #undef __FUNCT__
7242 #define __FUNCT__ "CellRefinerCreateLabels"
7243 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7244 {
7245   PetscInt       numLabels, l;
7246   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7247   PetscErrorCode ierr;
7248 
7249   PetscFunctionBegin;
7250   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7251   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7252   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7253   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7254 
7255   cStartNew = 0;
7256   vStartNew = depthSize[2];
7257   fStartNew = depthSize[2] + depthSize[0];
7258 
7259   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7260   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7261   switch (refiner) {
7262   case 3:
7263     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7264     cMax = PetscMin(cEnd, cMax);
7265     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7266     fMax = PetscMin(fEnd, fMax);
7267   }
7268   for (l = 0; l < numLabels; ++l) {
7269     DMLabel        label, labelNew;
7270     const char     *lname;
7271     PetscBool      isDepth;
7272     IS             valueIS;
7273     const PetscInt *values;
7274     PetscInt       numValues, val;
7275 
7276     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7277     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7278     if (isDepth) continue;
7279     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7280     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7281     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7282     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7283     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7284     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7285     for (val = 0; val < numValues; ++val) {
7286       IS             pointIS;
7287       const PetscInt *points;
7288       PetscInt       numPoints, n;
7289 
7290       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7291       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7292       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7293       for (n = 0; n < numPoints; ++n) {
7294         const PetscInt p = points[n];
7295         switch (refiner) {
7296         case 1:
7297           /* Simplicial 2D */
7298           if ((p >= vStart) && (p < vEnd)) {
7299             /* Old vertices stay the same */
7300             newp = vStartNew + (p - vStart);
7301             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7302           } else if ((p >= fStart) && (p < fEnd)) {
7303             /* Old faces add new faces and vertex */
7304             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7305             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7306             for (r = 0; r < 2; ++r) {
7307               newp = fStartNew + (p - fStart)*2 + r;
7308               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7309             }
7310           } else if ((p >= cStart) && (p < cEnd)) {
7311             /* Old cells add new cells and interior faces */
7312             for (r = 0; r < 4; ++r) {
7313               newp = cStartNew + (p - cStart)*4 + r;
7314               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7315             }
7316             for (r = 0; r < 3; ++r) {
7317               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7318               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7319             }
7320           }
7321           break;
7322         case 2:
7323           /* Hex 2D */
7324           if ((p >= vStart) && (p < vEnd)) {
7325             /* Old vertices stay the same */
7326             newp = vStartNew + (p - vStart);
7327             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7328           } else if ((p >= fStart) && (p < fEnd)) {
7329             /* Old faces add new faces and vertex */
7330             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7331             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7332             for (r = 0; r < 2; ++r) {
7333               newp = fStartNew + (p - fStart)*2 + r;
7334               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7335             }
7336           } else if ((p >= cStart) && (p < cEnd)) {
7337             /* Old cells add new cells and interior faces and vertex */
7338             for (r = 0; r < 4; ++r) {
7339               newp = cStartNew + (p - cStart)*4 + r;
7340               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7341             }
7342             for (r = 0; r < 4; ++r) {
7343               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7344               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7345             }
7346             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7347             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7348           }
7349           break;
7350         case 3:
7351           /* Hybrid simplicial 2D */
7352           if ((p >= vStart) && (p < vEnd)) {
7353             /* Old vertices stay the same */
7354             newp = vStartNew + (p - vStart);
7355             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7356           } else if ((p >= fStart) && (p < fMax)) {
7357             /* Old interior faces add new faces and vertex */
7358             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7359             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7360             for (r = 0; r < 2; ++r) {
7361               newp = fStartNew + (p - fStart)*2 + r;
7362               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7363             }
7364           } else if ((p >= fMax) && (p < fEnd)) {
7365             /* Old hybrid faces stay the same */
7366             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7367             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7368           } else if ((p >= cStart) && (p < cMax)) {
7369             /* Old interior cells add new cells and interior faces */
7370             for (r = 0; r < 4; ++r) {
7371               newp = cStartNew + (p - cStart)*4 + r;
7372               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7373             }
7374             for (r = 0; r < 3; ++r) {
7375               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7376               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7377             }
7378           } else if ((p >= cMax) && (p < cEnd)) {
7379             /* Old hybrid cells add new cells and hybrid face */
7380             for (r = 0; r < 2; ++r) {
7381               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7382               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7383             }
7384             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7385             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7386           }
7387           break;
7388         default:
7389           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7390         }
7391       }
7392       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7393       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7394     }
7395     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7396     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7397     if (0) {
7398       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7399       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7400       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7401     }
7402   }
7403   PetscFunctionReturn(0);
7404 }
7405 
7406 #undef __FUNCT__
7407 #define __FUNCT__ "DMPlexRefine_Uniform"
7408 /* This will only work for interpolated meshes */
7409 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7410 {
7411   DM             rdm;
7412   PetscInt       *depthSize;
7413   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7414   PetscErrorCode ierr;
7415 
7416   PetscFunctionBegin;
7417   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7418   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7419   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7420   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7421   /* Calculate number of new points of each depth */
7422   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7423   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7424   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7425   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7426   /* Step 1: Set chart */
7427   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7428   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7429   /* Step 2: Set cone/support sizes */
7430   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7431   /* Step 3: Setup refined DM */
7432   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7433   /* Step 4: Set cones and supports */
7434   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7435   /* Step 5: Stratify */
7436   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7437   /* Step 6: Set coordinates for vertices */
7438   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7439   /* Step 7: Create pointSF */
7440   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7441   /* Step 8: Create labels */
7442   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7443   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7444 
7445   *dmRefined = rdm;
7446 #if 0
7447   DM_Plex  *mesh = (DM_Plex*) dm->data;
7448   PetscInt dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7449   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7450 
7451   PetscFunctionBegin;
7452   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7453   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7454   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7455   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7456   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7457 
7458   /* Count number of new cells which are normal and extra */
7459   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7460 
7461   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7462   for (c = cStart; c < cEnd2; ++c) {
7463     PetscInt n;
7464     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7465 
7466     newNumCellsNormal += n;
7467   }
7468   for (c = cEnd2; c < cEnd; ++c) {
7469     PetscInt n;
7470     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7471 
7472     newNumCellsExtra += n;
7473   }
7474   newNumCells = newNumCellsNormal + newNumCellsExtra;
7475   /* Count number of new vertices which are normal and extra */
7476   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7477   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7478   for (c = cStart; c < cEnd; ++c) {
7479     PetscInt *closure = PETSC_NULL;
7480     PetscInt closureSize, numCorners = 0, p;
7481 
7482     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7483     for (p = 0; p < closureSize*2; p += 2) {
7484       const PetscInt point = closure[p];
7485       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
7486     }
7487     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7488     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7489   }
7490   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7491   for (c = cEnd2; c < cEnd; ++c) {
7492     PetscInt *closure = PETSC_NULL;
7493     PetscInt closureSize, numCorners = 0, p;
7494 
7495     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7496     for (p = 0; p < closureSize*2; p += 2) {
7497       const PetscInt point = closure[p];
7498       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
7499     }
7500     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7501     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7502   } /* for */
7503   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7504   newNumVertices      = newNumVerticesNormal + newNumVerticesExtra;
7505 
7506 #if 1
7507   PetscInt oldNumCellsNormal = cEnd2 - cStart;
7508   PetscInt oldNumCellsExtra  = cEnd  - cEnd2;
7509   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7510   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7511   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7512   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7513   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7514   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7515   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7516   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7517   ierr = PetscSynchronizedFlush(comm);
7518 #endif
7519 
7520   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7521   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7522   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7523   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7524   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7525   /* Set cone and support sizes for new normal cells */
7526   PetscInt newCell = 0;
7527   for (c = cStart; c < cEnd2; ++c) {
7528     PetscInt coneSize, n, i;
7529 
7530     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7531     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7532     for (i = 0; i < n; ++i, ++newCell) {
7533       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7534     }
7535 
7536     PetscInt *closure = PETSC_NULL;
7537     PetscInt closureSize, numCorners = 0, p;
7538 
7539     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7540     for (p = 0; p < closureSize*2; p += 2) {
7541       const PetscInt point = closure[p];
7542       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
7543     }
7544     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7545     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7546   }
7547 
7548   /* Reset current new cell value and loop over censored cells. */
7549   curNewCell  = _orderNewMesh->cellsCensored().min();
7550   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7551   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7552     /* Set new cone and support sizes */
7553     cV.clear();
7554     sieve->cone(*c_iter, cV);
7555     const point_type * cone   = cV.getPoints();
7556     const int        coneSize = cV.getSize();
7557 
7558     const point_type * newCells;
7559     int              numNewCells = 0;
7560     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7561 
7562     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7563       newSieve->setConeSize(curNewCell, coneSize);
7564       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7565         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7566       } /* for */
7567     } /* for */
7568   } /* for */
7569   newSieve->allocate();
7570 
7571   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7572 
7573   /* Create refined cells in new sieve. */
7574   curNewCell  = _orderNewMesh->cellsNormal().min();
7575   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7576   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7577     cV.clear();
7578     sieve->cone(*c_iter, cV);
7579     const point_type *cone    = cV.getPoints();
7580     const int        coneSize = cV.getSize();
7581 
7582     const point_type * newCells;
7583     int              numNewCells = 0;
7584     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7585 
7586     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7587       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7588     } /* for */
7589   } /* for */
7590   curNewCell = _orderNewMesh->cellsCensored().min();
7591   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7592   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7593     cV.clear();
7594     sieve->cone(*c_iter, cV);
7595     const point_type *cone    = cV.getPoints();
7596     const int        coneSize = cV.getSize();
7597 
7598     const point_type *newCells;
7599     int              numNewCells = 0;
7600     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7601 
7602     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7603       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7604     } /* for */
7605   } /* for */
7606   newSieve->symmetrize();
7607 
7608   /* Set coordinates in refined mesh. */
7609   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7610   assert(!coordinates.isNull());
7611   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7612   assert(!newCoordinates.isNull());
7613 
7614   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7615   assert(vertices->size() > 0);
7616   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7617   assert(spaceDim > 0);
7618   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7619 
7620   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7621   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7622     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7623   } /* for */
7624   newCoordinates->allocatePoint();
7625 
7626   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7627   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7628     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7629     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7630   } /* for */
7631   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7632   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7633     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7634     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7635   } /* for */
7636 
7637   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7638 
7639   /* Create sensored depth */
7640   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7641   assert(!censoredLabel.isNull());
7642 
7643   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7644 
7645   newSieve->roots(depthVisitor);
7646   while (depthVisitor.isModified()) {
7647     /* FIX: Avoid the copy here somehow by fixing the traversal */
7648     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7649 
7650     depthVisitor.clear();
7651     newSieve->support(modifiedPoints, depthVisitor);
7652   } /* while */
7653 
7654   /* Stratify refined mesh */
7655   /* Calculate new point SF */
7656   _calcNewOverlap(newMesh, mesh, refiner);
7657   /* Calculate new labels */
7658   _createLabels(newMesh, mesh, refiner);
7659 #endif
7660   PetscFunctionReturn(0);
7661 }
7662 
7663 #undef __FUNCT__
7664 #define __FUNCT__ "DMPlexSetRefinementUniform"
7665 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7666 {
7667   DM_Plex *mesh = (DM_Plex*) dm->data;
7668 
7669   PetscFunctionBegin;
7670   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7671   mesh->refinementUniform = refinementUniform;
7672   PetscFunctionReturn(0);
7673 }
7674 
7675 #undef __FUNCT__
7676 #define __FUNCT__ "DMPlexGetRefinementUniform"
7677 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7678 {
7679   DM_Plex *mesh = (DM_Plex*) dm->data;
7680 
7681   PetscFunctionBegin;
7682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7683   PetscValidPointer(refinementUniform,  2);
7684   *refinementUniform = mesh->refinementUniform;
7685   PetscFunctionReturn(0);
7686 }
7687 
7688 #undef __FUNCT__
7689 #define __FUNCT__ "DMPlexSetRefinementLimit"
7690 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7691 {
7692   DM_Plex *mesh = (DM_Plex*) dm->data;
7693 
7694   PetscFunctionBegin;
7695   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7696   mesh->refinementLimit = refinementLimit;
7697   PetscFunctionReturn(0);
7698 }
7699 
7700 #undef __FUNCT__
7701 #define __FUNCT__ "DMPlexGetRefinementLimit"
7702 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7703 {
7704   DM_Plex *mesh = (DM_Plex*) dm->data;
7705 
7706   PetscFunctionBegin;
7707   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7708   PetscValidPointer(refinementLimit,  2);
7709   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7710   *refinementLimit = mesh->refinementLimit;
7711   PetscFunctionReturn(0);
7712 }
7713 
7714 #undef __FUNCT__
7715 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7716 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7717 {
7718   PetscInt       dim, cStart, coneSize, cMax;
7719   PetscErrorCode ierr;
7720 
7721   PetscFunctionBegin;
7722   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7723   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7724   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7725   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7726   switch (dim) {
7727   case 2:
7728     switch (coneSize) {
7729     case 3:
7730       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7731       else *cellRefiner = 1; /* Triangular */
7732       break;
7733     case 4:
7734       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7735       else *cellRefiner = 2; /* Quadrilateral */
7736       break;
7737     default:
7738       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7739     }
7740     break;
7741   default:
7742     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7743   }
7744   PetscFunctionReturn(0);
7745 }
7746 
7747 #undef __FUNCT__
7748 #define __FUNCT__ "DMRefine_Plex"
7749 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7750 {
7751   PetscReal      refinementLimit;
7752   PetscInt       dim, cStart, cEnd;
7753   char           genname[1024], *name = PETSC_NULL;
7754   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7755   PetscErrorCode ierr;
7756 
7757   PetscFunctionBegin;
7758   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7759   if (isUniform) {
7760     CellRefiner cellRefiner;
7761 
7762     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7763     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7764     PetscFunctionReturn(0);
7765   }
7766   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7767   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7768   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7769   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7770   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7771   if (flg) name = genname;
7772   if (name) {
7773     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7774     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7775     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7776   }
7777   switch (dim) {
7778   case 2:
7779     if (!name || isTriangle) {
7780 #if defined(PETSC_HAVE_TRIANGLE)
7781       double   *maxVolumes;
7782       PetscInt c;
7783 
7784       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7785       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7786       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7787 #else
7788       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7789 #endif
7790     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7791     break;
7792   case 3:
7793     if (!name || isCTetgen) {
7794 #if defined(PETSC_HAVE_CTETGEN)
7795       PetscReal *maxVolumes;
7796       PetscInt  c;
7797 
7798       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7799       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7800       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7801 #else
7802       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7803 #endif
7804     } else if (isTetgen) {
7805 #if defined(PETSC_HAVE_TETGEN)
7806       double   *maxVolumes;
7807       PetscInt c;
7808 
7809       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7810       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7811       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7812 #else
7813       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7814 #endif
7815     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7816     break;
7817   default:
7818     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7819   }
7820   PetscFunctionReturn(0);
7821 }
7822 
7823 #undef __FUNCT__
7824 #define __FUNCT__ "DMPlexGetDepth"
7825 /*@
7826   DMPlexGetDepth - get the number of strata
7827 
7828   Not Collective
7829 
7830   Input Parameters:
7831 . dm           - The DMPlex object
7832 
7833   Output Parameters:
7834 . depth - number of strata
7835 
7836   Level: developer
7837 
7838   Notes:
7839   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7840 
7841 .keywords: mesh, points
7842 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7843 @*/
7844 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7845 {
7846   PetscInt       d;
7847   PetscErrorCode ierr;
7848 
7849   PetscFunctionBegin;
7850   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7851   PetscValidPointer(depth, 2);
7852   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7853   *depth = d-1;
7854   PetscFunctionReturn(0);
7855 }
7856 
7857 #undef __FUNCT__
7858 #define __FUNCT__ "DMPlexGetDepthStratum"
7859 /*@
7860   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7861 
7862   Not Collective
7863 
7864   Input Parameters:
7865 + dm           - The DMPlex object
7866 - stratumValue - The requested depth
7867 
7868   Output Parameters:
7869 + start - The first point at this depth
7870 - end   - One beyond the last point at this depth
7871 
7872   Level: developer
7873 
7874 .keywords: mesh, points
7875 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7876 @*/
7877 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7878 {
7879   DM_Plex        *mesh = (DM_Plex*) dm->data;
7880   DMLabel        next  = mesh->labels;
7881   PetscBool      flg   = PETSC_FALSE;
7882   PetscInt       depth;
7883   PetscErrorCode ierr;
7884 
7885   PetscFunctionBegin;
7886   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7887   if (stratumValue < 0) {
7888     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7889     PetscFunctionReturn(0);
7890   } else {
7891     PetscInt pStart, pEnd;
7892 
7893     if (start) *start = 0;
7894     if (end)   *end   = 0;
7895     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7896     if (pStart == pEnd) PetscFunctionReturn(0);
7897   }
7898   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7899   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7900   /* We should have a generic GetLabel() and a Label class */
7901   while (next) {
7902     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7903     if (flg) break;
7904     next = next->next;
7905   }
7906   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7907   depth = stratumValue;
7908   if ((depth < 0) || (depth >= next->numStrata)) {
7909     if (start) *start = 0;
7910     if (end)   *end   = 0;
7911   } else {
7912     if (start) *start = next->points[next->stratumOffsets[depth]];
7913     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7914   }
7915   PetscFunctionReturn(0);
7916 }
7917 
7918 #undef __FUNCT__
7919 #define __FUNCT__ "DMPlexGetHeightStratum"
7920 /*@
7921   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7922 
7923   Not Collective
7924 
7925   Input Parameters:
7926 + dm           - The DMPlex object
7927 - stratumValue - The requested height
7928 
7929   Output Parameters:
7930 + start - The first point at this height
7931 - end   - One beyond the last point at this height
7932 
7933   Level: developer
7934 
7935 .keywords: mesh, points
7936 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7937 @*/
7938 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7939 {
7940   DM_Plex        *mesh = (DM_Plex*) dm->data;
7941   DMLabel        next  = mesh->labels;
7942   PetscBool      flg   = PETSC_FALSE;
7943   PetscInt       depth;
7944   PetscErrorCode ierr;
7945 
7946   PetscFunctionBegin;
7947   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7948   if (stratumValue < 0) {
7949     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7950   } else {
7951     PetscInt pStart, pEnd;
7952 
7953     if (start) *start = 0;
7954     if (end)   *end   = 0;
7955     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7956     if (pStart == pEnd) PetscFunctionReturn(0);
7957   }
7958   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7959   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7960   /* We should have a generic GetLabel() and a Label class */
7961   while (next) {
7962     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7963     if (flg) break;
7964     next = next->next;
7965   }
7966   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7967   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7968   if ((depth < 0) || (depth >= next->numStrata)) {
7969     if (start) *start = 0;
7970     if (end)   *end   = 0;
7971   } else {
7972     if (start) *start = next->points[next->stratumOffsets[depth]];
7973     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7974   }
7975   PetscFunctionReturn(0);
7976 }
7977 
7978 #undef __FUNCT__
7979 #define __FUNCT__ "DMPlexCreateSectionInitial"
7980 /* Set the number of dof on each point and separate by fields */
7981 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7982 {
7983   PetscInt       *numDofTot;
7984   PetscInt       pStart = 0, pEnd = 0;
7985   PetscInt       p, d, f;
7986   PetscErrorCode ierr;
7987 
7988   PetscFunctionBegin;
7989   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7990   for (d = 0; d <= dim; ++d) {
7991     numDofTot[d] = 0;
7992     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7993   }
7994   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7995   if (numFields > 0) {
7996     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7997     if (numComp) {
7998       for (f = 0; f < numFields; ++f) {
7999         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
8000       }
8001     }
8002   }
8003   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8004   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
8005   for (d = 0; d <= dim; ++d) {
8006     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
8007     for (p = pStart; p < pEnd; ++p) {
8008       for (f = 0; f < numFields; ++f) {
8009         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
8010       }
8011       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
8012     }
8013   }
8014   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
8015   PetscFunctionReturn(0);
8016 }
8017 
8018 #undef __FUNCT__
8019 #define __FUNCT__ "DMPlexCreateSectionBCDof"
8020 /* Set the number of dof on each point and separate by fields
8021    If constDof is PETSC_DETERMINE, constrain every dof on the point
8022 */
8023 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
8024 {
8025   PetscInt       numFields;
8026   PetscInt       bc;
8027   PetscErrorCode ierr;
8028 
8029   PetscFunctionBegin;
8030   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8031   for (bc = 0; bc < numBC; ++bc) {
8032     PetscInt       field = 0;
8033     const PetscInt *idx;
8034     PetscInt       n, i;
8035 
8036     if (numFields) field = bcField[bc];
8037     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
8038     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8039     for (i = 0; i < n; ++i) {
8040       const PetscInt p        = idx[i];
8041       PetscInt       numConst = constDof;
8042 
8043       /* Constrain every dof on the point */
8044       if (numConst < 0) {
8045         if (numFields) {
8046           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
8047         } else {
8048           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
8049         }
8050       }
8051       if (numFields) {
8052         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
8053       }
8054       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
8055     }
8056     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8057   }
8058   PetscFunctionReturn(0);
8059 }
8060 
8061 #undef __FUNCT__
8062 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
8063 /* Set the constrained indices on each point and separate by fields */
8064 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
8065 {
8066   PetscInt       *maxConstraints;
8067   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
8068   PetscErrorCode ierr;
8069 
8070   PetscFunctionBegin;
8071   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8072   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8073   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
8074   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
8075   for (p = pStart; p < pEnd; ++p) {
8076     PetscInt cdof;
8077 
8078     if (numFields) {
8079       for (f = 0; f < numFields; ++f) {
8080         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
8081         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
8082       }
8083     } else {
8084       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8085       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
8086     }
8087   }
8088   for (f = 0; f < numFields; ++f) {
8089     maxConstraints[numFields] += maxConstraints[f];
8090   }
8091   if (maxConstraints[numFields]) {
8092     PetscInt *indices;
8093 
8094     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8095     for (p = pStart; p < pEnd; ++p) {
8096       PetscInt cdof, d;
8097 
8098       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8099       if (cdof) {
8100         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
8101         if (numFields) {
8102           PetscInt numConst = 0, foff = 0;
8103 
8104           for (f = 0; f < numFields; ++f) {
8105             PetscInt cfdof, fdof;
8106 
8107             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8108             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
8109             /* Change constraint numbering from absolute local dof number to field relative local dof number */
8110             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
8111             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
8112             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
8113             numConst += cfdof;
8114             foff     += fdof;
8115           }
8116           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8117         } else {
8118           for (d = 0; d < cdof; ++d) indices[d] = d;
8119         }
8120         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8121       }
8122     }
8123     ierr = PetscFree(indices);CHKERRQ(ierr);
8124   }
8125   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
8126   PetscFunctionReturn(0);
8127 }
8128 
8129 #undef __FUNCT__
8130 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
8131 /* Set the constrained field indices on each point */
8132 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
8133 {
8134   const PetscInt *points, *indices;
8135   PetscInt       numFields, maxDof, numPoints, p, numConstraints;
8136   PetscErrorCode ierr;
8137 
8138   PetscFunctionBegin;
8139   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8140   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8141 
8142   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8143   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8144   if (!constraintIndices) {
8145     PetscInt *idx, i;
8146 
8147     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8148     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8149     for (i = 0; i < maxDof; ++i) idx[i] = i;
8150     for (p = 0; p < numPoints; ++p) {
8151       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8152     }
8153     ierr = PetscFree(idx);CHKERRQ(ierr);
8154   } else {
8155     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8156     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8157     for (p = 0; p < numPoints; ++p) {
8158       PetscInt fcdof;
8159 
8160       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8161       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);
8162       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8163     }
8164     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8165   }
8166   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8167   PetscFunctionReturn(0);
8168 }
8169 
8170 #undef __FUNCT__
8171 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8172 /* Set the constrained indices on each point and separate by fields */
8173 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8174 {
8175   PetscInt       *indices;
8176   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8177   PetscErrorCode ierr;
8178 
8179   PetscFunctionBegin;
8180   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8181   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8182   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8183   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8184   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8185   for (p = pStart; p < pEnd; ++p) {
8186     PetscInt cdof, d;
8187 
8188     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8189     if (cdof) {
8190       PetscInt numConst = 0, foff = 0;
8191 
8192       for (f = 0; f < numFields; ++f) {
8193         const PetscInt *fcind;
8194         PetscInt       fdof, fcdof;
8195 
8196         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8197         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8198         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8199         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8200         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
8201         foff     += fdof;
8202         numConst += fcdof;
8203       }
8204       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8205       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8206     }
8207   }
8208   ierr = PetscFree(indices);CHKERRQ(ierr);
8209   PetscFunctionReturn(0);
8210 }
8211 
8212 #undef __FUNCT__
8213 #define __FUNCT__ "DMPlexCreateSection"
8214 /*@C
8215   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8216 
8217   Not Collective
8218 
8219   Input Parameters:
8220 + dm        - The DMPlex object
8221 . dim       - The spatial dimension of the problem
8222 . numFields - The number of fields in the problem
8223 . numComp   - An array of size numFields that holds the number of components for each field
8224 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8225 . numBC     - The number of boundary conditions
8226 . bcField   - An array of size numBC giving the field number for each boundry condition
8227 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8228 
8229   Output Parameter:
8230 . section - The PetscSection object
8231 
8232   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
8233   nubmer of dof for field 0 on each edge.
8234 
8235   Level: developer
8236 
8237 .keywords: mesh, elements
8238 .seealso: DMPlexCreate(), PetscSectionCreate()
8239 @*/
8240 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8241 {
8242   PetscErrorCode ierr;
8243 
8244   PetscFunctionBegin;
8245   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8246   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8247   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8248   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8249   {
8250     PetscBool view = PETSC_FALSE;
8251 
8252     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8253     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8254   }
8255   PetscFunctionReturn(0);
8256 }
8257 
8258 #undef __FUNCT__
8259 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8260 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8261 {
8262   PetscSection   section;
8263   PetscErrorCode ierr;
8264 
8265   PetscFunctionBegin;
8266   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8267   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8268   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8269   PetscFunctionReturn(0);
8270 }
8271 
8272 #undef __FUNCT__
8273 #define __FUNCT__ "DMPlexGetCoordinateSection"
8274 /*@
8275   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8276 
8277   Not Collective
8278 
8279   Input Parameter:
8280 . dm - The DMPlex object
8281 
8282   Output Parameter:
8283 . section - The PetscSection object
8284 
8285   Level: intermediate
8286 
8287 .keywords: mesh, coordinates
8288 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8289 @*/
8290 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8291 {
8292   DM             cdm;
8293   PetscErrorCode ierr;
8294 
8295   PetscFunctionBegin;
8296   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8297   PetscValidPointer(section, 2);
8298   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8299   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8300   PetscFunctionReturn(0);
8301 }
8302 
8303 #undef __FUNCT__
8304 #define __FUNCT__ "DMPlexSetCoordinateSection"
8305 /*@
8306   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8307 
8308   Not Collective
8309 
8310   Input Parameters:
8311 + dm      - The DMPlex object
8312 - section - The PetscSection object
8313 
8314   Level: intermediate
8315 
8316 .keywords: mesh, coordinates
8317 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8318 @*/
8319 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8320 {
8321   DM             cdm;
8322   PetscErrorCode ierr;
8323 
8324   PetscFunctionBegin;
8325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8326   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8327   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8328   PetscFunctionReturn(0);
8329 }
8330 
8331 #undef __FUNCT__
8332 #define __FUNCT__ "DMPlexGetConeSection"
8333 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8334 {
8335   DM_Plex *mesh = (DM_Plex*) dm->data;
8336 
8337   PetscFunctionBegin;
8338   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8339   if (section) *section = mesh->coneSection;
8340   PetscFunctionReturn(0);
8341 }
8342 
8343 #undef __FUNCT__
8344 #define __FUNCT__ "DMPlexGetCones"
8345 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8346 {
8347   DM_Plex *mesh = (DM_Plex*) dm->data;
8348 
8349   PetscFunctionBegin;
8350   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8351   if (cones) *cones = mesh->cones;
8352   PetscFunctionReturn(0);
8353 }
8354 
8355 #undef __FUNCT__
8356 #define __FUNCT__ "DMPlexGetConeOrientations"
8357 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8358 {
8359   DM_Plex *mesh = (DM_Plex*) dm->data;
8360 
8361   PetscFunctionBegin;
8362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8363   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8364   PetscFunctionReturn(0);
8365 }
8366 
8367 #undef __FUNCT__
8368 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8369 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8370 {
8371   const PetscInt embedDim = 2;
8372   PetscReal      x        = PetscRealPart(point[0]);
8373   PetscReal      y        = PetscRealPart(point[1]);
8374   PetscReal      v0[2], J[4], invJ[4], detJ;
8375   PetscReal      xi, eta;
8376   PetscErrorCode ierr;
8377 
8378   PetscFunctionBegin;
8379   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8380   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8381   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8382 
8383   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8384   else *cell = -1;
8385   PetscFunctionReturn(0);
8386 }
8387 
8388 #undef __FUNCT__
8389 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8390 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8391 {
8392   PetscSection      coordSection;
8393   Vec               coordsLocal;
8394   const PetscScalar *coords;
8395   const PetscInt    faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8396   PetscReal         x         = PetscRealPart(point[0]);
8397   PetscReal         y         = PetscRealPart(point[1]);
8398   PetscInt          crossings = 0, f;
8399   PetscErrorCode    ierr;
8400 
8401   PetscFunctionBegin;
8402   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8403   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8404   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8405   for (f = 0; f < 4; ++f) {
8406     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8407     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8408     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8409     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8410     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8411     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8412     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8413     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8414     if ((cond1 || cond2)  && above) ++crossings;
8415   }
8416   if (crossings % 2) *cell = c;
8417   else *cell = -1;
8418   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8419   PetscFunctionReturn(0);
8420 }
8421 
8422 #undef __FUNCT__
8423 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8424 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8425 {
8426   const PetscInt embedDim = 3;
8427   PetscReal      v0[3], J[9], invJ[9], detJ;
8428   PetscReal      x = PetscRealPart(point[0]);
8429   PetscReal      y = PetscRealPart(point[1]);
8430   PetscReal      z = PetscRealPart(point[2]);
8431   PetscReal      xi, eta, zeta;
8432   PetscErrorCode ierr;
8433 
8434   PetscFunctionBegin;
8435   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8436   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8437   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8438   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8439 
8440   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8441   else *cell = -1;
8442   PetscFunctionReturn(0);
8443 }
8444 
8445 #undef __FUNCT__
8446 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8447 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8448 {
8449   PetscSection      coordSection;
8450   Vec               coordsLocal;
8451   const PetscScalar *coords;
8452   const PetscInt    faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8453                                  3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8454   PetscBool         found = PETSC_TRUE;
8455   PetscInt          f;
8456   PetscErrorCode    ierr;
8457 
8458   PetscFunctionBegin;
8459   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8460   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8461   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8462   for (f = 0; f < 6; ++f) {
8463     /* Check the point is under plane */
8464     /*   Get face normal */
8465     PetscReal v_i[3];
8466     PetscReal v_j[3];
8467     PetscReal normal[3];
8468     PetscReal pp[3];
8469     PetscReal dot;
8470 
8471     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8472     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8473     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8474     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8475     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8476     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8477     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8478     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8479     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8480     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8481     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8482     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8483     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8484 
8485     /* Check that projected point is in face (2D location problem) */
8486     if (dot < 0.0) {
8487       found = PETSC_FALSE;
8488       break;
8489     }
8490   }
8491   if (found) *cell = c;
8492   else *cell = -1;
8493   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8494   PetscFunctionReturn(0);
8495 }
8496 
8497 #undef __FUNCT__
8498 #define __FUNCT__ "DMLocatePoints_Plex"
8499 /*
8500  Need to implement using the guess
8501 */
8502 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8503 {
8504   PetscInt       cell = -1 /*, guess = -1*/;
8505   PetscInt       bs, numPoints, p;
8506   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8507   PetscInt       *cells;
8508   PetscScalar    *a;
8509   PetscErrorCode ierr;
8510 
8511   PetscFunctionBegin;
8512   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8513   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8514   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8515   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8516   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8517   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8518   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8519   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);
8520   numPoints /= bs;
8521   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8522   for (p = 0; p < numPoints; ++p) {
8523     const PetscScalar *point = &a[p*bs];
8524 
8525     switch (dim) {
8526     case 2:
8527       for (c = cStart; c < cEnd; ++c) {
8528         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8529         switch (coneSize) {
8530         case 3:
8531           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8532           break;
8533         case 4:
8534           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8535           break;
8536         default:
8537           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8538         }
8539         if (cell >= 0) break;
8540       }
8541       break;
8542     case 3:
8543       for (c = cStart; c < cEnd; ++c) {
8544         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8545         switch (coneSize) {
8546         case 4:
8547           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8548           break;
8549         case 8:
8550           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8551           break;
8552         default:
8553           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8554         }
8555         if (cell >= 0) break;
8556       }
8557       break;
8558     default:
8559       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8560     }
8561     cells[p] = cell;
8562   }
8563   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8564   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8565   PetscFunctionReturn(0);
8566 }
8567 
8568 /******************************** FEM Support **********************************/
8569 
8570 #undef __FUNCT__
8571 #define __FUNCT__ "DMPlexVecGetClosure"
8572 /*@C
8573   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8574 
8575   Not collective
8576 
8577   Input Parameters:
8578 + dm - The DM
8579 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8580 . v - The local vector
8581 - point - The sieve point in the DM
8582 
8583   Output Parameters:
8584 + csize - The number of values in the closure, or PETSC_NULL
8585 - values - The array of values, which is a borrowed array and should not be freed
8586 
8587   Level: intermediate
8588 
8589 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8590 @*/
8591 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8592 {
8593   PetscScalar    *array, *vArray;
8594   PetscInt       *points = PETSC_NULL;
8595   PetscInt       offsets[32];
8596   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8597   PetscErrorCode ierr;
8598 
8599   PetscFunctionBegin;
8600   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8601   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8602   if (!section) {
8603     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8604   }
8605   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8606   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8607   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8608   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8609   /* Compress out points not in the section */
8610   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8611   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8612     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8613       points[q*2]   = points[p];
8614       points[q*2+1] = points[p+1];
8615       ++q;
8616     }
8617   }
8618   numPoints = q;
8619   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8620     PetscInt dof, fdof;
8621 
8622     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8623     for (f = 0; f < numFields; ++f) {
8624       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8625       offsets[f+1] += fdof;
8626     }
8627     size += dof;
8628   }
8629   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8630   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8631   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8632   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8633   for (p = 0; p < numPoints*2; p += 2) {
8634     PetscInt    o = points[p+1];
8635     PetscInt    dof, off, d;
8636     PetscScalar *varr;
8637 
8638     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8639     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8640     varr = &vArray[off];
8641     if (numFields) {
8642       PetscInt fdof, foff, fcomp, f, c;
8643 
8644       for (f = 0, foff = 0; f < numFields; ++f) {
8645         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8646         if (o >= 0) {
8647           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8648             array[offsets[f]] = varr[foff+d];
8649           }
8650         } else {
8651           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8652           for (d = fdof/fcomp-1; d >= 0; --d) {
8653             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8654               array[offsets[f]] = varr[foff+d*fcomp+c];
8655             }
8656           }
8657         }
8658         foff += fdof;
8659       }
8660     } else {
8661       if (o >= 0) {
8662         for (d = 0; d < dof; ++d, ++offsets[0]) {
8663           array[offsets[0]] = varr[d];
8664         }
8665       } else {
8666         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8667           array[offsets[0]] = varr[d];
8668         }
8669       }
8670     }
8671   }
8672   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8673   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8674   if (csize) *csize = size;
8675   *values = array;
8676   PetscFunctionReturn(0);
8677 }
8678 
8679 #undef __FUNCT__
8680 #define __FUNCT__ "DMPlexVecRestoreClosure"
8681 /*@C
8682   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8683 
8684   Not collective
8685 
8686   Input Parameters:
8687 + dm - The DM
8688 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8689 . v - The local vector
8690 . point - The sieve point in the DM
8691 . csize - The number of values in the closure, or PETSC_NULL
8692 - values - The array of values, which is a borrowed array and should not be freed
8693 
8694   Level: intermediate
8695 
8696 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8697 @*/
8698 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8699 {
8700   PetscInt       size = 0;
8701   PetscErrorCode ierr;
8702 
8703   PetscFunctionBegin;
8704   /* Should work without recalculating size */
8705   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8706   PetscFunctionReturn(0);
8707 }
8708 
8709 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8710 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8711 
8712 #undef __FUNCT__
8713 #define __FUNCT__ "updatePoint_private"
8714 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8715 {
8716   PetscInt       cdof;   /* The number of constraints on this point */
8717   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8718   PetscScalar    *a;
8719   PetscInt       off, cind = 0, k;
8720   PetscErrorCode ierr;
8721 
8722   PetscFunctionBegin;
8723   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8724   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8725   a    = &array[off];
8726   if (!cdof || setBC) {
8727     if (orientation >= 0) {
8728       for (k = 0; k < dof; ++k) {
8729         fuse(&a[k], values[k]);
8730       }
8731     } else {
8732       for (k = 0; k < dof; ++k) {
8733         fuse(&a[k], values[dof-k-1]);
8734       }
8735     }
8736   } else {
8737     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8738     if (orientation >= 0) {
8739       for (k = 0; k < dof; ++k) {
8740         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8741         fuse(&a[k], values[k]);
8742       }
8743     } else {
8744       for (k = 0; k < dof; ++k) {
8745         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8746         fuse(&a[k], values[dof-k-1]);
8747       }
8748     }
8749   }
8750   PetscFunctionReturn(0);
8751 }
8752 
8753 #undef __FUNCT__
8754 #define __FUNCT__ "updatePointFields_private"
8755 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8756 {
8757   PetscScalar    *a;
8758   PetscInt       numFields, off, foff, f;
8759   PetscErrorCode ierr;
8760 
8761   PetscFunctionBegin;
8762   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8763   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8764   a    = &array[off];
8765   for (f = 0, foff = 0; f < numFields; ++f) {
8766     PetscInt       fdof, fcomp, fcdof;
8767     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8768     PetscInt       cind = 0, k, c;
8769 
8770     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8771     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8772     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8773     if (!fcdof || setBC) {
8774       if (orientation >= 0) {
8775         for (k = 0; k < fdof; ++k) {
8776           fuse(&a[foff+k], values[foffs[f]+k]);
8777         }
8778       } else {
8779         for (k = fdof/fcomp-1; k >= 0; --k) {
8780           for (c = 0; c < fcomp; ++c) {
8781             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8782           }
8783         }
8784       }
8785     } else {
8786       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8787       if (orientation >= 0) {
8788         for (k = 0; k < fdof; ++k) {
8789           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8790           fuse(&a[foff+k], values[foffs[f]+k]);
8791         }
8792       } else {
8793         for (k = fdof/fcomp-1; k >= 0; --k) {
8794           for (c = 0; c < fcomp; ++c) {
8795             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8796             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8797           }
8798         }
8799       }
8800     }
8801     foff     += fdof;
8802     foffs[f] += fdof;
8803   }
8804   PetscFunctionReturn(0);
8805 }
8806 
8807 #undef __FUNCT__
8808 #define __FUNCT__ "DMPlexVecSetClosure"
8809 /*@C
8810   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8811 
8812   Not collective
8813 
8814   Input Parameters:
8815 + dm - The DM
8816 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8817 . v - The local vector
8818 . point - The sieve point in the DM
8819 . values - The array of values, which is a borrowed array and should not be freed
8820 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8821 
8822   Level: intermediate
8823 
8824 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8825 @*/
8826 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8827 {
8828   PetscScalar    *array;
8829   PetscInt       *points = PETSC_NULL;
8830   PetscInt       offsets[32];
8831   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8832   PetscErrorCode ierr;
8833 
8834   PetscFunctionBegin;
8835   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8836   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8837   if (!section) {
8838     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8839   }
8840   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8841   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8842   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8843   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8844   /* Compress out points not in the section */
8845   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8846   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8847     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8848       points[q*2]   = points[p];
8849       points[q*2+1] = points[p+1];
8850       ++q;
8851     }
8852   }
8853   numPoints = q;
8854   for (p = 0; p < numPoints*2; p += 2) {
8855     PetscInt fdof;
8856 
8857     for (f = 0; f < numFields; ++f) {
8858       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8859       offsets[f+1] += fdof;
8860     }
8861   }
8862   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8863   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8864   if (numFields) {
8865     switch (mode) {
8866     case INSERT_VALUES:
8867       for (p = 0; p < numPoints*2; p += 2) {
8868         PetscInt o = points[p+1];
8869         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8870       } break;
8871     case INSERT_ALL_VALUES:
8872       for (p = 0; p < numPoints*2; p += 2) {
8873         PetscInt o = points[p+1];
8874         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8875       } break;
8876     case ADD_VALUES:
8877       for (p = 0; p < numPoints*2; p += 2) {
8878         PetscInt o = points[p+1];
8879         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8880       } break;
8881     case ADD_ALL_VALUES:
8882       for (p = 0; p < numPoints*2; p += 2) {
8883         PetscInt o = points[p+1];
8884         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8885       } break;
8886     default:
8887       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8888     }
8889   } else {
8890     switch (mode) {
8891     case INSERT_VALUES:
8892       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8893         PetscInt o = points[p+1];
8894         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8895         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8896       } break;
8897     case INSERT_ALL_VALUES:
8898       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8899         PetscInt o = points[p+1];
8900         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8901         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8902       } break;
8903     case ADD_VALUES:
8904       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8905         PetscInt o = points[p+1];
8906         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8907         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8908       } break;
8909     case ADD_ALL_VALUES:
8910       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8911         PetscInt o = points[p+1];
8912         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8913         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8914       } break;
8915     default:
8916       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8917     }
8918   }
8919   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8920   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8921   PetscFunctionReturn(0);
8922 }
8923 
8924 #undef __FUNCT__
8925 #define __FUNCT__ "DMPlexPrintMatSetValues"
8926 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8927 {
8928   PetscMPIInt    rank;
8929   PetscInt       i, j;
8930   PetscErrorCode ierr;
8931 
8932   PetscFunctionBegin;
8933   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8934   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8935   for (i = 0; i < numIndices; i++) {
8936     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8937   }
8938   for (i = 0; i < numIndices; i++) {
8939     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8940     for (j = 0; j < numIndices; j++) {
8941 #if defined(PETSC_USE_COMPLEX)
8942       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8943 #else
8944       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8945 #endif
8946     }
8947     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8948   }
8949   PetscFunctionReturn(0);
8950 }
8951 
8952 #undef __FUNCT__
8953 #define __FUNCT__ "indicesPoint_private"
8954 /* . off - The global offset of this point */
8955 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8956 {
8957   PetscInt       cdof;   /* The number of constraints on this point */
8958   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8959   PetscInt       cind = 0, k;
8960   PetscErrorCode ierr;
8961 
8962   PetscFunctionBegin;
8963   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8964   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8965   if (!cdof || setBC) {
8966     if (orientation >= 0) {
8967       for (k = 0; k < dof; ++k) indices[k] = off+k;
8968     } else {
8969       for (k = 0; k < dof; ++k) indices[dof-k-1] = off+k;
8970     }
8971   } else {
8972     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8973     if (orientation >= 0) {
8974       for (k = 0; k < dof; ++k) {
8975         if ((cind < cdof) && (k == cdofs[cind])) {
8976           /* Insert check for returning constrained indices */
8977           indices[k] = -(off+k+1);
8978           ++cind;
8979         } else {
8980           indices[k] = off+k-cind;
8981         }
8982       }
8983     } else {
8984       for (k = 0; k < dof; ++k) {
8985         if ((cind < cdof) && (k == cdofs[cind])) {
8986           /* Insert check for returning constrained indices */
8987           indices[dof-k-1] = -(off+k+1);
8988           ++cind;
8989         } else {
8990           indices[dof-k-1] = off+k-cind;
8991         }
8992       }
8993     }
8994   }
8995   PetscFunctionReturn(0);
8996 }
8997 
8998 #undef __FUNCT__
8999 #define __FUNCT__ "indicesPointFields_private"
9000 /* . off - The global offset of this point */
9001 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
9002 {
9003   PetscInt       numFields, foff, f;
9004   PetscErrorCode ierr;
9005 
9006   PetscFunctionBegin;
9007   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9008   for (f = 0, foff = 0; f < numFields; ++f) {
9009     PetscInt        fdof, fcomp, cfdof;
9010     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
9011     PetscInt        cind = 0, k, c;
9012 
9013     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
9014     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
9015     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
9016     if (!cfdof || setBC) {
9017       if (orientation >= 0) {
9018         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
9019       } else {
9020         for (k = fdof/fcomp-1; k >= 0; --k) {
9021           for (c = 0; c < fcomp; ++c) {
9022             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
9023           }
9024         }
9025       }
9026     } else {
9027       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
9028       if (orientation >= 0) {
9029         for (k = 0; k < fdof; ++k) {
9030           if ((cind < cfdof) && (k == fcdofs[cind])) {
9031             indices[foffs[f]+k] = -(off+foff+k+1);
9032             ++cind;
9033           } else {
9034             indices[foffs[f]+k] = off+foff+k-cind;
9035           }
9036         }
9037       } else {
9038         for (k = fdof/fcomp-1; k >= 0; --k) {
9039           for (c = 0; c < fcomp; ++c) {
9040             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
9041               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
9042               ++cind;
9043             } else {
9044               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
9045             }
9046           }
9047         }
9048       }
9049     }
9050     foff     += fdof - cfdof;
9051     foffs[f] += fdof;
9052   }
9053   PetscFunctionReturn(0);
9054 }
9055 
9056 #undef __FUNCT__
9057 #define __FUNCT__ "DMPlexMatSetClosure"
9058 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
9059 {
9060   DM_Plex        *mesh   = (DM_Plex*) dm->data;
9061   PetscInt       *points = PETSC_NULL;
9062   PetscInt       *indices;
9063   PetscInt       offsets[32];
9064   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
9065   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
9066   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
9067   PetscErrorCode ierr;
9068 
9069   PetscFunctionBegin;
9070   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9071   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
9072   if (useDefault) {
9073     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9074   }
9075   if (useGlobalDefault) {
9076     if (useDefault) {
9077       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
9078     } else {
9079       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9080     }
9081   }
9082   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9083   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
9084   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
9085   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9086   /* Compress out points not in the section */
9087   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
9088   for (p = 0, q = 0; p < numPoints*2; p += 2) {
9089     if ((points[p] >= pStart) && (points[p] < pEnd)) {
9090       points[q*2]   = points[p];
9091       points[q*2+1] = points[p+1];
9092       ++q;
9093     }
9094   }
9095   numPoints = q;
9096   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
9097     PetscInt fdof;
9098 
9099     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
9100     for (f = 0; f < numFields; ++f) {
9101       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
9102       offsets[f+1] += fdof;
9103     }
9104     numIndices += dof;
9105   }
9106   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
9107 
9108   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
9109   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9110   if (numFields) {
9111     for (p = 0; p < numPoints*2; p += 2) {
9112       PetscInt o = points[p+1];
9113       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9114       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
9115     }
9116   } else {
9117     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
9118       PetscInt o = points[p+1];
9119       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9120       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
9121     }
9122   }
9123   if (useGlobalDefault && !useDefault) {
9124     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9125   }
9126   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
9127   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9128   if (ierr) {
9129     PetscMPIInt    rank;
9130     PetscErrorCode ierr2;
9131 
9132     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
9133     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9134     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9135     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9136     CHKERRQ(ierr);
9137   }
9138   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9139   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9140   PetscFunctionReturn(0);
9141 }
9142 
9143 #undef __FUNCT__
9144 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9145 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9146 {
9147   PetscSection      coordSection;
9148   Vec               coordinates;
9149   const PetscScalar *coords;
9150   const PetscInt    dim = 2;
9151   PetscInt          d, f;
9152   PetscErrorCode    ierr;
9153 
9154   PetscFunctionBegin;
9155   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9156   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9157   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9158   if (v0) {
9159     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9160   }
9161   if (J) {
9162     for (d = 0; d < dim; d++) {
9163       for (f = 0; f < dim; f++) {
9164         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9165       }
9166     }
9167     *detJ = J[0]*J[3] - J[1]*J[2];
9168 #if 0
9169     if (detJ < 0.0) {
9170       const PetscReal xLength = mesh->periodicity[0];
9171 
9172       if (xLength != 0.0) {
9173         PetscReal v0x = coords[0*dim+0];
9174 
9175         if (v0x == 0.0) v0x = v0[0] = xLength;
9176         for (f = 0; f < dim; f++) {
9177           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9178 
9179           J[0*dim+f] = 0.5*(px - v0x);
9180         }
9181       }
9182       detJ = J[0]*J[3] - J[1]*J[2];
9183     }
9184 #endif
9185     PetscLogFlops(8.0 + 3.0);
9186   }
9187   if (invJ) {
9188     const PetscReal invDet = 1.0/(*detJ);
9189 
9190     invJ[0] =  invDet*J[3];
9191     invJ[1] = -invDet*J[1];
9192     invJ[2] = -invDet*J[2];
9193     invJ[3] =  invDet*J[0];
9194     PetscLogFlops(5.0);
9195   }
9196   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9197   PetscFunctionReturn(0);
9198 }
9199 
9200 #undef __FUNCT__
9201 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9202 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9203 {
9204   PetscSection      coordSection;
9205   Vec               coordinates;
9206   const PetscScalar *coords;
9207   const PetscInt    dim = 2;
9208   PetscInt          d, f;
9209   PetscErrorCode    ierr;
9210 
9211   PetscFunctionBegin;
9212   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9213   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9214   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9215   if (v0) {
9216     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9217   }
9218   if (J) {
9219     for (d = 0; d < dim; d++) {
9220       for (f = 0; f < dim; f++) {
9221         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9222       }
9223     }
9224     *detJ = J[0]*J[3] - J[1]*J[2];
9225     PetscLogFlops(8.0 + 3.0);
9226   }
9227   if (invJ) {
9228     const PetscReal invDet = 1.0/(*detJ);
9229 
9230     invJ[0] =  invDet*J[3];
9231     invJ[1] = -invDet*J[1];
9232     invJ[2] = -invDet*J[2];
9233     invJ[3] =  invDet*J[0];
9234     PetscLogFlops(5.0);
9235   }
9236   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9237   PetscFunctionReturn(0);
9238 }
9239 
9240 #undef __FUNCT__
9241 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9242 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9243 {
9244   PetscSection      coordSection;
9245   Vec               coordinates;
9246   const PetscScalar *coords;
9247   const PetscInt    dim = 3;
9248   PetscInt          d, f;
9249   PetscErrorCode    ierr;
9250 
9251   PetscFunctionBegin;
9252   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9253   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9254   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9255   if (v0) {
9256     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9257   }
9258   if (J) {
9259     for (d = 0; d < dim; d++) {
9260       for (f = 0; f < dim; f++) {
9261         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9262       }
9263     }
9264     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9265     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9266              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9267              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9268     PetscLogFlops(18.0 + 12.0);
9269   }
9270   if (invJ) {
9271     const PetscReal invDet = 1.0/(*detJ);
9272 
9273     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9274     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9275     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9276     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9277     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9278     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9279     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9280     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9281     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9282     PetscLogFlops(37.0);
9283   }
9284   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9285   PetscFunctionReturn(0);
9286 }
9287 
9288 #undef __FUNCT__
9289 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9290 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9291 {
9292   PetscSection      coordSection;
9293   Vec               coordinates;
9294   const PetscScalar *coords;
9295   const PetscInt    dim = 3;
9296   PetscInt          d;
9297   PetscErrorCode    ierr;
9298 
9299   PetscFunctionBegin;
9300   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9301   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9302   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9303   if (v0) {
9304     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9305   }
9306   if (J) {
9307     for (d = 0; d < dim; d++) {
9308       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9309       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9310       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9311     }
9312     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9313              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9314              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9315     PetscLogFlops(18.0 + 12.0);
9316   }
9317   if (invJ) {
9318     const PetscReal invDet = -1.0/(*detJ);
9319 
9320     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9321     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9322     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9323     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9324     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9325     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9326     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9327     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9328     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9329     PetscLogFlops(37.0);
9330   }
9331   *detJ *= 8.0;
9332   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9333   PetscFunctionReturn(0);
9334 }
9335 
9336 #undef __FUNCT__
9337 #define __FUNCT__ "DMPlexComputeCellGeometry"
9338 /*@C
9339   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9340 
9341   Collective on DM
9342 
9343   Input Arguments:
9344 + dm   - the DM
9345 - cell - the cell
9346 
9347   Output Arguments:
9348 + v0   - the translation part of this affine transform
9349 . J    - the Jacobian of the transform to the reference element
9350 . invJ - the inverse of the Jacobian
9351 - detJ - the Jacobian determinant
9352 
9353   Level: advanced
9354 
9355 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9356 @*/
9357 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9358 {
9359   PetscInt       dim, coneSize;
9360   PetscErrorCode ierr;
9361 
9362   PetscFunctionBegin;
9363   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9364   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9365   switch (dim) {
9366   case 2:
9367     switch (coneSize) {
9368     case 3:
9369       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9370       break;
9371     case 4:
9372       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9373       break;
9374     default:
9375       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9376     }
9377     break;
9378   case 3:
9379     switch (coneSize) {
9380     case 4:
9381       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9382       break;
9383     case 8:
9384       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9385       break;
9386     default:
9387       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9388     }
9389     break;
9390   default:
9391     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9392   }
9393   PetscFunctionReturn(0);
9394 }
9395 
9396 #undef __FUNCT__
9397 #define __FUNCT__ "DMPlexGetFaceOrientation"
9398 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9399 {
9400   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9401   PetscBool      posOrient = PETSC_FALSE;
9402   const PetscInt debug     = 0;
9403   PetscInt       cellDim, faceSize, f;
9404   PetscErrorCode ierr;
9405 
9406   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9407   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9408 
9409   if (cellDim == numCorners-1) {
9410     /* Simplices */
9411     faceSize  = numCorners-1;
9412     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9413   } else if (cellDim == 1 && numCorners == 3) {
9414     /* Quadratic line */
9415     faceSize  = 1;
9416     posOrient = PETSC_TRUE;
9417   } else if (cellDim == 2 && numCorners == 4) {
9418     /* Quads */
9419     faceSize = 2;
9420     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9421       posOrient = PETSC_TRUE;
9422     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9423       posOrient = PETSC_TRUE;
9424     } else {
9425       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9426         posOrient = PETSC_FALSE;
9427       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9428     }
9429   } else if (cellDim == 2 && numCorners == 6) {
9430     /* Quadratic triangle (I hate this) */
9431     /* Edges are determined by the first 2 vertices (corners of edges) */
9432     const PetscInt faceSizeTri = 3;
9433     PetscInt       sortedIndices[3], i, iFace;
9434     PetscBool      found                    = PETSC_FALSE;
9435     PetscInt       faceVerticesTriSorted[9] = {
9436       0, 3,  4, /* bottom */
9437       1, 4,  5, /* right */
9438       2, 3,  5, /* left */
9439     };
9440     PetscInt       faceVerticesTri[9] = {
9441       0, 3,  4, /* bottom */
9442       1, 4,  5, /* right */
9443       2, 5,  3, /* left */
9444     };
9445 
9446     faceSize = faceSizeTri;
9447     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9448     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9449     for (iFace = 0; iFace < 3; ++iFace) {
9450       const PetscInt ii = iFace*faceSizeTri;
9451       PetscInt       fVertex, cVertex;
9452 
9453       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9454           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9455         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9456           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9457             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9458               faceVertices[fVertex] = origVertices[cVertex];
9459               break;
9460             }
9461           }
9462         }
9463         found = PETSC_TRUE;
9464         break;
9465       }
9466     }
9467     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9468     if (posOriented) *posOriented = PETSC_TRUE;
9469     PetscFunctionReturn(0);
9470   } else if (cellDim == 2 && numCorners == 9) {
9471     /* Quadratic quad (I hate this) */
9472     /* Edges are determined by the first 2 vertices (corners of edges) */
9473     const PetscInt faceSizeQuad = 3;
9474     PetscInt       sortedIndices[3], i, iFace;
9475     PetscBool      found                      = PETSC_FALSE;
9476     PetscInt       faceVerticesQuadSorted[12] = {
9477       0, 1,  4, /* bottom */
9478       1, 2,  5, /* right */
9479       2, 3,  6, /* top */
9480       0, 3,  7, /* left */
9481     };
9482     PetscInt       faceVerticesQuad[12] = {
9483       0, 1,  4, /* bottom */
9484       1, 2,  5, /* right */
9485       2, 3,  6, /* top */
9486       3, 0,  7, /* left */
9487     };
9488 
9489     faceSize = faceSizeQuad;
9490     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9491     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9492     for (iFace = 0; iFace < 4; ++iFace) {
9493       const PetscInt ii = iFace*faceSizeQuad;
9494       PetscInt       fVertex, cVertex;
9495 
9496       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9497           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9498         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9499           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9500             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9501               faceVertices[fVertex] = origVertices[cVertex];
9502               break;
9503             }
9504           }
9505         }
9506         found = PETSC_TRUE;
9507         break;
9508       }
9509     }
9510     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9511     if (posOriented) *posOriented = PETSC_TRUE;
9512     PetscFunctionReturn(0);
9513   } else if (cellDim == 3 && numCorners == 8) {
9514     /* Hexes
9515        A hex is two oriented quads with the normal of the first
9516        pointing up at the second.
9517 
9518           7---6
9519          /|  /|
9520         4---5 |
9521         | 3-|-2
9522         |/  |/
9523         0---1
9524 
9525         Faces are determined by the first 4 vertices (corners of faces) */
9526     const PetscInt faceSizeHex = 4;
9527     PetscInt       sortedIndices[4], i, iFace;
9528     PetscBool      found                     = PETSC_FALSE;
9529     PetscInt       faceVerticesHexSorted[24] = {
9530       0, 1, 2, 3,  /* bottom */
9531       4, 5, 6, 7,  /* top */
9532       0, 1, 4, 5,  /* front */
9533       1, 2, 5, 6,  /* right */
9534       2, 3, 6, 7,  /* back */
9535       0, 3, 4, 7,  /* left */
9536     };
9537     PetscInt       faceVerticesHex[24] = {
9538       3, 2, 1, 0,  /* bottom */
9539       4, 5, 6, 7,  /* top */
9540       0, 1, 5, 4,  /* front */
9541       1, 2, 6, 5,  /* right */
9542       2, 3, 7, 6,  /* back */
9543       3, 0, 4, 7,  /* left */
9544     };
9545 
9546     faceSize = faceSizeHex;
9547     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9548     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9549     for (iFace = 0; iFace < 6; ++iFace) {
9550       const PetscInt ii = iFace*faceSizeHex;
9551       PetscInt       fVertex, cVertex;
9552 
9553       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9554           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9555           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9556           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9557         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9558           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9559             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9560               faceVertices[fVertex] = origVertices[cVertex];
9561               break;
9562             }
9563           }
9564         }
9565         found = PETSC_TRUE;
9566         break;
9567       }
9568     }
9569     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9570     if (posOriented) *posOriented = PETSC_TRUE;
9571     PetscFunctionReturn(0);
9572   } else if (cellDim == 3 && numCorners == 10) {
9573     /* Quadratic tet */
9574     /* Faces are determined by the first 3 vertices (corners of faces) */
9575     const PetscInt faceSizeTet = 6;
9576     PetscInt       sortedIndices[6], i, iFace;
9577     PetscBool      found                     = PETSC_FALSE;
9578     PetscInt       faceVerticesTetSorted[24] = {
9579       0, 1, 2,  6, 7, 8, /* bottom */
9580       0, 3, 4,  6, 7, 9,  /* front */
9581       1, 4, 5,  7, 8, 9,  /* right */
9582       2, 3, 5,  6, 8, 9,  /* left */
9583     };
9584     PetscInt       faceVerticesTet[24] = {
9585       0, 1, 2,  6, 7, 8, /* bottom */
9586       0, 4, 3,  6, 7, 9,  /* front */
9587       1, 5, 4,  7, 8, 9,  /* right */
9588       2, 3, 5,  8, 6, 9,  /* left */
9589     };
9590 
9591     faceSize = faceSizeTet;
9592     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9593     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9594     for (iFace=0; iFace < 4; ++iFace) {
9595       const PetscInt ii = iFace*faceSizeTet;
9596       PetscInt       fVertex, cVertex;
9597 
9598       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9599           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9600           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9601           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9602         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9603           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9604             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9605               faceVertices[fVertex] = origVertices[cVertex];
9606               break;
9607             }
9608           }
9609         }
9610         found = PETSC_TRUE;
9611         break;
9612       }
9613     }
9614     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9615     if (posOriented) *posOriented = PETSC_TRUE;
9616     PetscFunctionReturn(0);
9617   } else if (cellDim == 3 && numCorners == 27) {
9618     /* Quadratic hexes (I hate this)
9619        A hex is two oriented quads with the normal of the first
9620        pointing up at the second.
9621 
9622          7---6
9623         /|  /|
9624        4---5 |
9625        | 3-|-2
9626        |/  |/
9627        0---1
9628 
9629        Faces are determined by the first 4 vertices (corners of faces) */
9630     const PetscInt faceSizeQuadHex = 9;
9631     PetscInt       sortedIndices[9], i, iFace;
9632     PetscBool      found                         = PETSC_FALSE;
9633     PetscInt       faceVerticesQuadHexSorted[54] = {
9634       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9635       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9636       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9637       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9638       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9639       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9640     };
9641     PetscInt       faceVerticesQuadHex[54] = {
9642       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9643       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9644       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9645       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9646       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9647       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9648     };
9649 
9650     faceSize = faceSizeQuadHex;
9651     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9652     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9653     for (iFace = 0; iFace < 6; ++iFace) {
9654       const PetscInt ii = iFace*faceSizeQuadHex;
9655       PetscInt       fVertex, cVertex;
9656 
9657       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9658           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9659           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9660           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9661         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9662           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9663             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9664               faceVertices[fVertex] = origVertices[cVertex];
9665               break;
9666             }
9667           }
9668         }
9669         found = PETSC_TRUE;
9670         break;
9671       }
9672     }
9673     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9674     if (posOriented) *posOriented = PETSC_TRUE;
9675     PetscFunctionReturn(0);
9676   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9677   if (!posOrient) {
9678     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9679     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize-1 - f];
9680   } else {
9681     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9682     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f];
9683   }
9684   if (posOriented) *posOriented = posOrient;
9685   PetscFunctionReturn(0);
9686 }
9687 
9688 #undef __FUNCT__
9689 #define __FUNCT__ "DMPlexGetOrientedFace"
9690 /*
9691     Given a cell and a face, as a set of vertices,
9692       return the oriented face, as a set of vertices, in faceVertices
9693     The orientation is such that the face normal points out of the cell
9694 */
9695 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9696 {
9697   const PetscInt *cone = PETSC_NULL;
9698   PetscInt       coneSize, v, f, v2;
9699   PetscInt       oppositeVertex = -1;
9700   PetscErrorCode ierr;
9701 
9702   PetscFunctionBegin;
9703   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9704   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9705   for (v = 0, v2 = 0; v < coneSize; ++v) {
9706     PetscBool found = PETSC_FALSE;
9707 
9708     for (f = 0; f < faceSize; ++f) {
9709       if (face[f] == cone[v]) {
9710         found = PETSC_TRUE; break;
9711       }
9712     }
9713     if (found) {
9714       indices[v2]      = v;
9715       origVertices[v2] = cone[v];
9716       ++v2;
9717     } else {
9718       oppositeVertex = v;
9719     }
9720   }
9721   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9722   PetscFunctionReturn(0);
9723 }
9724 
9725 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9726 {
9727   switch (i) {
9728   case 0:
9729     switch (j) {
9730     case 0: return 0;
9731     case 1:
9732       switch (k) {
9733       case 0: return 0;
9734       case 1: return 0;
9735       case 2: return 1;
9736       }
9737     case 2:
9738       switch (k) {
9739       case 0: return 0;
9740       case 1: return -1;
9741       case 2: return 0;
9742       }
9743     }
9744   case 1:
9745     switch (j) {
9746     case 0:
9747       switch (k) {
9748       case 0: return 0;
9749       case 1: return 0;
9750       case 2: return -1;
9751       }
9752     case 1: return 0;
9753     case 2:
9754       switch (k) {
9755       case 0: return 1;
9756       case 1: return 0;
9757       case 2: return 0;
9758       }
9759     }
9760   case 2:
9761     switch (j) {
9762     case 0:
9763       switch (k) {
9764       case 0: return 0;
9765       case 1: return 1;
9766       case 2: return 0;
9767       }
9768     case 1:
9769       switch (k) {
9770       case 0: return -1;
9771       case 1: return 0;
9772       case 2: return 0;
9773       }
9774     case 2: return 0;
9775     }
9776   }
9777   return 0;
9778 }
9779 
9780 #undef __FUNCT__
9781 #define __FUNCT__ "DMPlexCreateRigidBody"
9782 /*@C
9783   DMPlexCreateRigidBody - create rigid body modes from coordinates
9784 
9785   Collective on DM
9786 
9787   Input Arguments:
9788 + dm - the DM
9789 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9790 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9791 
9792   Output Argument:
9793 . sp - the null space
9794 
9795   Note: This is necessary to take account of Dirichlet conditions on the displacements
9796 
9797   Level: advanced
9798 
9799 .seealso: MatNullSpaceCreate()
9800 @*/
9801 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9802 {
9803   MPI_Comm       comm = ((PetscObject) dm)->comm;
9804   Vec            coordinates, localMode, mode[6];
9805   PetscSection   coordSection;
9806   PetscScalar    *coords;
9807   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9808   PetscErrorCode ierr;
9809 
9810   PetscFunctionBegin;
9811   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9812   if (dim == 1) {
9813     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9814     PetscFunctionReturn(0);
9815   }
9816   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9817   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9818   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9819   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9820   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9821   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9822   m    = (dim*(dim+1))/2;
9823   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9824   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9825   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9826   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9827   /* Assume P1 */
9828   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9829   for (d = 0; d < dim; ++d) {
9830     PetscScalar values[3] = {0.0, 0.0, 0.0};
9831 
9832     values[d] = 1.0;
9833     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9834     for (v = vStart; v < vEnd; ++v) {
9835       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9836     }
9837     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9838     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9839   }
9840   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9841   for (d = dim; d < dim*(dim+1)/2; ++d) {
9842     PetscInt i, j, k = dim > 2 ? d - dim : d;
9843 
9844     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9845     for (v = vStart; v < vEnd; ++v) {
9846       PetscScalar values[3] = {0.0, 0.0, 0.0};
9847       PetscInt    off;
9848 
9849       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9850       for (i = 0; i < dim; ++i) {
9851         for (j = 0; j < dim; ++j) {
9852           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9853         }
9854       }
9855       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9856     }
9857     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9858     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9859   }
9860   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9861   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9862   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9863   /* Orthonormalize system */
9864   for (i = dim; i < m; ++i) {
9865     PetscScalar dots[6];
9866 
9867     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9868     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9869     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9870     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9871   }
9872   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9873   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9874   PetscFunctionReturn(0);
9875 }
9876 
9877 #undef __FUNCT__
9878 #define __FUNCT__ "DMPlexGetHybridBounds"
9879 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9880 {
9881   DM_Plex        *mesh = (DM_Plex*) dm->data;
9882   PetscInt       dim;
9883   PetscErrorCode ierr;
9884 
9885   PetscFunctionBegin;
9886   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9887   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9888   if (cMax) *cMax = mesh->hybridPointMax[dim];
9889   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9890   if (eMax) *eMax = mesh->hybridPointMax[1];
9891   if (vMax) *vMax = mesh->hybridPointMax[0];
9892   PetscFunctionReturn(0);
9893 }
9894 
9895 #undef __FUNCT__
9896 #define __FUNCT__ "DMPlexSetHybridBounds"
9897 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9898 {
9899   DM_Plex        *mesh = (DM_Plex*) dm->data;
9900   PetscInt       dim;
9901   PetscErrorCode ierr;
9902 
9903   PetscFunctionBegin;
9904   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9905   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9906   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9907   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9908   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9909   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9910   PetscFunctionReturn(0);
9911 }
9912 
9913 #undef __FUNCT__
9914 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9915 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9916 {
9917   DM_Plex *mesh = (DM_Plex*) dm->data;
9918 
9919   PetscFunctionBegin;
9920   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9921   PetscValidPointer(cellHeight, 2);
9922   *cellHeight = mesh->vtkCellHeight;
9923   PetscFunctionReturn(0);
9924 }
9925 
9926 #undef __FUNCT__
9927 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9928 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9929 {
9930   DM_Plex *mesh = (DM_Plex*) dm->data;
9931 
9932   PetscFunctionBegin;
9933   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9934   mesh->vtkCellHeight = cellHeight;
9935   PetscFunctionReturn(0);
9936 }
9937 
9938 #undef __FUNCT__
9939 #define __FUNCT__ "DMPlexInsertFace_Private"
9940 /*
9941   DMPlexInsertFace_Private - Puts a face into the mesh
9942 
9943   Not collective
9944 
9945   Input Parameters:
9946   + dm              - The DMPlex
9947   . numFaceVertex   - The number of vertices in the face
9948   . faceVertices    - The vertices in the face for dm
9949   . subfaceVertices - The vertices in the face for subdm
9950   . numCorners      - The number of vertices in the cell
9951   . cell            - A cell in dm containing the face
9952   . subcell         - A cell in subdm containing the face
9953   . firstFace       - First face in the mesh
9954   - newFacePoint    - Next face in the mesh
9955 
9956   Output Parameters:
9957   . newFacePoint - Contains next face point number on input, updated on output
9958 
9959   Level: developer
9960 */
9961 PetscErrorCode DMPlexInsertFace_Private(DM dm, DM subdm, PetscInt numFaceVertices, const PetscInt faceVertices[], const PetscInt subfaceVertices[], PetscInt numCorners, PetscInt cell, PetscInt subcell, PetscInt firstFace, PetscInt *newFacePoint)
9962 {
9963   MPI_Comm       comm     = ((PetscObject) dm)->comm;
9964   DM_Plex        *submesh = (DM_Plex*) subdm->data;
9965   const PetscInt *faces;
9966   PetscInt       numFaces, coneSize;
9967   PetscErrorCode ierr;
9968 
9969   PetscFunctionBegin;
9970   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9971   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9972 #if 0
9973   /* Cannot use this because support() has not been constructed yet */
9974   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9975 #else
9976   {
9977     PetscInt f;
9978 
9979     numFaces = 0;
9980     ierr     = DMGetWorkArray(subdm, 1, PETSC_INT, (void**) &faces);CHKERRQ(ierr);
9981     for (f = firstFace; f < *newFacePoint; ++f) {
9982       PetscInt dof, off, d;
9983 
9984       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9985       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9986       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9987       for (d = 0; d < dof; ++d) {
9988         const PetscInt p = submesh->cones[off+d];
9989         PetscInt       v;
9990 
9991         for (v = 0; v < numFaceVertices; ++v) {
9992           if (subfaceVertices[v] == p) break;
9993         }
9994         if (v == numFaceVertices) break;
9995       }
9996       if (d == dof) {
9997         numFaces               = 1;
9998         ((PetscInt*) faces)[0] = f;
9999       }
10000     }
10001   }
10002 #endif
10003   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
10004   else if (numFaces == 1) {
10005     /* Add the other cell neighbor for this face */
10006     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
10007   } else {
10008     PetscInt  *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
10009     PetscBool posOriented;
10010 
10011     ierr                = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10012     origVertices        = &orientedVertices[numFaceVertices];
10013     indices             = &orientedVertices[numFaceVertices*2];
10014     orientedSubVertices = &orientedVertices[numFaceVertices*3];
10015     ierr                = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
10016     /* TODO: I know that routine should return a permutation, not the indices */
10017     for (v = 0; v < numFaceVertices; ++v) {
10018       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
10019       for (ov = 0; ov < numFaceVertices; ++ov) {
10020         if (orientedVertices[ov] == vertex) {
10021           orientedSubVertices[ov] = subvertex;
10022           break;
10023         }
10024       }
10025       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
10026     }
10027     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
10028     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
10029     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10030     ++(*newFacePoint);
10031   }
10032   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10033   PetscFunctionReturn(0);
10034 }
10035 
10036 #undef __FUNCT__
10037 #define __FUNCT__ "DMPlexCreateSubmesh"
10038 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
10039 {
10040   MPI_Comm       comm = ((PetscObject) dm)->comm;
10041   DM_Plex        *submesh;
10042   PetscBool      boundaryFaces = PETSC_FALSE;
10043   PetscSection   coordSection, subCoordSection;
10044   Vec            coordinates, subCoordinates;
10045   PetscScalar    *coords, *subCoords;
10046   IS             labelIS;
10047   const PetscInt *subVertices;
10048   PetscInt       *subVerticesActive, *tmpPoints;
10049   PetscInt       *subCells = PETSC_NULL;
10050   PetscInt       numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
10051   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
10052   PetscInt       dim;  /* Right now, do not specify dimension */
10053   PetscInt       cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
10054   PetscErrorCode ierr;
10055 
10056   PetscFunctionBegin;
10057   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10058   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10059   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10060   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
10061   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10062   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
10063   if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
10064   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10065 
10066   subface = &face[maxConeSize];
10067 
10068   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
10069   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10070   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10071   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
10072   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
10073   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
10074 
10075   maxSubCells = numSubVertices;
10076 
10077   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
10078   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
10079   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
10080   for (v = 0; v < numSubVertices; ++v) {
10081     const PetscInt vertex = subVertices[v];
10082     PetscInt       *star  = PETSC_NULL;
10083     PetscInt       starSize, numCells = 0;
10084 
10085     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10086     for (p = 0; p < starSize*2; p += 2) {
10087       const PetscInt point = star[p];
10088       if ((point >= cStart) && (point < cEnd)) star[numCells++] = point;
10089     }
10090     numOldSubCells = numSubCells;
10091     for (c = 0; c < numCells; ++c) {
10092       const PetscInt cell     = star[c];
10093       PetscInt       *closure = PETSC_NULL;
10094       PetscInt       closureSize, numCorners = 0, faceSize = 0;
10095       PetscInt       cellLoc;
10096 
10097       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
10098       if (cellLoc >= 0) continue;
10099       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10100       for (p = 0; p < closureSize*2; p += 2) {
10101         const PetscInt point = closure[p];
10102         if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
10103       }
10104       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
10105       for (corner = 0; corner < numCorners; ++corner) {
10106         const PetscInt cellVertex = closure[corner];
10107         PetscInt       subVertex;
10108 
10109         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
10110         if (subVertex >= 0) { /* contains submesh vertex */
10111           for (i = 0; i < faceSize; ++i) {
10112             if (cellVertex == face[i]) break;
10113           }
10114           if (i == faceSize) {
10115             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
10116             face[faceSize]    = cellVertex;
10117             subface[faceSize] = subVertex;
10118             ++faceSize;
10119           }
10120         }
10121       }
10122       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10123       if (faceSize >= nFV) {
10124         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10125         if (numSubCells >= maxSubCells) {
10126           PetscInt *tmpCells;
10127           maxSubCells *= 2;
10128           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
10129           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
10130           ierr = PetscFree(subCells);CHKERRQ(ierr);
10131 
10132           subCells = tmpCells;
10133         }
10134         /* TOOD: Maybe overestimate then squeeze out empty faces */
10135         if (faceSize > nFV) {
10136           /* TODO: This is tricky. Maybe just add all faces */
10137           numSubFaces++;
10138         } else {
10139           numSubFaces++;
10140         }
10141         for (f = 0; f < faceSize; ++f) {
10142           subVerticesActive[subface[f]] = 1;
10143         }
10144         subCells[numSubCells++] = cell;
10145       }
10146     }
10147     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10148     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
10149   }
10150   /* Pick out active subvertices */
10151   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
10152     if (subVerticesActive[v]) {
10153       subVerticesActive[numSubVerticesActive++] = subVertices[v];
10154     }
10155   }
10156   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
10157   /* Set cone sizes */
10158   firstSubVertex = numSubCells;
10159   firstSubFace   = numSubCells+numSubVerticesActive;
10160   newFacePoint   = firstSubFace;
10161   for (c = 0; c < numSubCells; ++c) {
10162     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
10163   }
10164   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
10165     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
10166   }
10167   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
10168   /* Create face cones */
10169   for (c = 0; c < numSubCells; ++c) {
10170     const PetscInt cell     = subCells[c];
10171     PetscInt       *closure = PETSC_NULL;
10172     PetscInt       closureSize, numCorners = 0, faceSize = 0;
10173 
10174     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10175     for (p = 0; p < closureSize*2; p += 2) {
10176       const PetscInt point = closure[p];
10177       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
10178     }
10179     for (corner = 0; corner < numCorners; ++corner) {
10180       const PetscInt cellVertex = closure[corner];
10181       PetscInt       subVertex;
10182 
10183       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
10184       if (subVertex >= 0) { /* contains submesh vertex */
10185         for (i = 0; i < faceSize; ++i) {
10186           if (cellVertex == face[i]) break;
10187         }
10188         if (i == faceSize) {
10189           face[faceSize]    = cellVertex;
10190           subface[faceSize] = numSubCells+subVertex;
10191           ++faceSize;
10192         }
10193       }
10194     }
10195     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10196     if (faceSize >= nFV) {
10197       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10198       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
10199       /*   We have to take all the faces, and discard those in the interior */
10200       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
10201 #if 0
10202       /* This object just calls insert on each face that comes from subsets() */
10203       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
10204       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
10205       PointArray                          faceVec(face->begin(), face->end());
10206 
10207       subsets(faceVec, nFV, inserter);
10208 #endif
10209       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10210     }
10211   }
10212   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
10213   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
10214   /* Build coordinates */
10215   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10216   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10217   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
10218   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10219   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10220     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10221   }
10222   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10223   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10224   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
10225   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10226   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10227   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10228   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10229   for (v = 0; v < numSubVerticesActive; ++v) {
10230     const PetscInt vertex    = subVerticesActive[v];
10231     const PetscInt subVertex = firstSubVertex+v;
10232     PetscInt       dof, off, sdof, soff;
10233 
10234     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10235     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10236     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10237     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10238     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10239     for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
10240   }
10241   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10242   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10243   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
10244   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10245 
10246   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
10247   /* Create map from submesh points to original mesh points */
10248   submesh = (DM_Plex*) (*subdm)->data;
10249   ierr    = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10250   for (c = 0; c < numSubCells; ++c) tmpPoints[c] = subCells[c];
10251   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
10252     tmpPoints[v] = subVerticesActive[v-numSubCells];
10253   }
10254   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
10255 
10256   ierr = PetscFree(subCells);CHKERRQ(ierr);
10257   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10258   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10259   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10260   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10261   PetscFunctionReturn(0);
10262 }
10263 
10264 #undef __FUNCT__
10265 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10266 /* We can easily have a form that takes an IS instead */
10267 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10268 {
10269   PetscSection   section, globalSection;
10270   PetscInt       *numbers, p;
10271   PetscErrorCode ierr;
10272 
10273   PetscFunctionBegin;
10274   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10275   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10276   for (p = pStart; p < pEnd; ++p) {
10277     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10278   }
10279   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10280   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10281   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10282   for (p = pStart; p < pEnd; ++p) {
10283     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10284   }
10285   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10286   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10287   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10288   PetscFunctionReturn(0);
10289 }
10290 
10291 #undef __FUNCT__
10292 #define __FUNCT__ "DMPlexGetCellNumbering"
10293 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10294 {
10295   DM_Plex        *mesh = (DM_Plex*) dm->data;
10296   PetscInt       cellHeight, cStart, cEnd, cMax;
10297   PetscErrorCode ierr;
10298 
10299   PetscFunctionBegin;
10300   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10301   if (!mesh->globalCellNumbers) {
10302     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10303     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10304     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10305     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
10306     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10307   }
10308   *globalCellNumbers = mesh->globalCellNumbers;
10309   PetscFunctionReturn(0);
10310 }
10311 
10312 #undef __FUNCT__
10313 #define __FUNCT__ "DMPlexGetVertexNumbering"
10314 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10315 {
10316   DM_Plex        *mesh = (DM_Plex*) dm->data;
10317   PetscInt       vStart, vEnd, vMax;
10318   PetscErrorCode ierr;
10319 
10320   PetscFunctionBegin;
10321   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10322   if (!mesh->globalVertexNumbers) {
10323     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10324     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10325     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
10326     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10327   }
10328   *globalVertexNumbers = mesh->globalVertexNumbers;
10329   PetscFunctionReturn(0);
10330 }
10331 
10332 #undef __FUNCT__
10333 #define __FUNCT__ "DMPlexGetSubpointMap"
10334 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10335 {
10336   DM_Plex *mesh = (DM_Plex*) dm->data;
10337 
10338   PetscFunctionBegin;
10339   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10340   PetscValidPointer(subpointMap, 2);
10341   *subpointMap = mesh->subpointMap;
10342   PetscFunctionReturn(0);
10343 }
10344 
10345 #undef __FUNCT__
10346 #define __FUNCT__ "DMPlexSetSubpointMap"
10347 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10348 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10349 {
10350   DM_Plex *mesh = (DM_Plex*) dm->data;
10351 
10352   PetscFunctionBegin;
10353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10354   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10355   mesh->subpointMap = subpointMap;
10356   PetscFunctionReturn(0);
10357 }
10358 
10359 #undef __FUNCT__
10360 #define __FUNCT__ "DMPlexGetScale"
10361 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10362 {
10363   DM_Plex *mesh = (DM_Plex*) dm->data;
10364 
10365   PetscFunctionBegin;
10366   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10367   PetscValidPointer(scale, 3);
10368   *scale = mesh->scale[unit];
10369   PetscFunctionReturn(0);
10370 }
10371 
10372 #undef __FUNCT__
10373 #define __FUNCT__ "DMPlexSetScale"
10374 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10375 {
10376   DM_Plex *mesh = (DM_Plex*) dm->data;
10377 
10378   PetscFunctionBegin;
10379   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10380   mesh->scale[unit] = scale;
10381   PetscFunctionReturn(0);
10382 }
10383 
10384 
10385 /*******************************************************************************
10386 This should be in a separate Discretization object, but I am not sure how to lay
10387 it out yet, so I am stuffing things here while I experiment.
10388 *******************************************************************************/
10389 #undef __FUNCT__
10390 #define __FUNCT__ "DMPlexSetFEMIntegration"
10391 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10392                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10393                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10394                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10395                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10396                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10397                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10398                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10399                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10400                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10401                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10402                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10403                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10404                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10405                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10406                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10407                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10408 {
10409   DM_Plex *mesh = (DM_Plex*) dm->data;
10410 
10411   PetscFunctionBegin;
10412   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10413   mesh->integrateResidualFEM       = integrateResidualFEM;
10414   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10415   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10416   PetscFunctionReturn(0);
10417 }
10418 
10419 #undef __FUNCT__
10420 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10421 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10422 {
10423   Vec            coordinates;
10424   PetscSection   section, cSection;
10425   PetscInt       dim, vStart, vEnd, v, c, d;
10426   PetscScalar    *values, *cArray;
10427   PetscReal      *coords;
10428   PetscErrorCode ierr;
10429 
10430   PetscFunctionBegin;
10431   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10432   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10433   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10434   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10435   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10436   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10437   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10438   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10439   for (v = vStart; v < vEnd; ++v) {
10440     PetscInt dof, off;
10441 
10442     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10443     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10444     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10445     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
10446     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10447     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10448   }
10449   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10450   /* Temporary, must be replaced by a projection on the finite element basis */
10451   {
10452     PetscInt eStart = 0, eEnd = 0, e, depth;
10453 
10454     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10455     --depth;
10456     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10457     for (e = eStart; e < eEnd; ++e) {
10458       const PetscInt *cone = PETSC_NULL;
10459       PetscInt       coneSize, d;
10460       PetscScalar    *coordsA, *coordsB;
10461 
10462       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10463       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10464       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10465       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10466       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10467       for (d = 0; d < dim; ++d) {
10468         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10469       }
10470       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10471       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10472     }
10473   }
10474 
10475   ierr = PetscFree(coords);CHKERRQ(ierr);
10476   ierr = PetscFree(values);CHKERRQ(ierr);
10477 #if 0
10478   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10479   PetscReal      detJ;
10480 
10481   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10482   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10483   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10484 
10485   for (PetscInt c = cStart; c < cEnd; ++c) {
10486     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10487     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10488     const int                         oSize    = pV.getSize();
10489     int                               v        = 0;
10490 
10491     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10492     for (PetscInt cl = 0; cl < oSize; ++cl) {
10493       const PetscInt fDim;
10494 
10495       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10496       if (pointDim) {
10497         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10498           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10499         }
10500       }
10501     }
10502     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10503     pV.clear();
10504   }
10505   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10506   ierr = PetscFree(values);CHKERRQ(ierr);
10507 #endif
10508   PetscFunctionReturn(0);
10509 }
10510 
10511 #undef __FUNCT__
10512 #define __FUNCT__ "DMPlexProjectFunction"
10513 /*@C
10514   DMPlexProjectFunction - This projects the given function into the function space provided.
10515 
10516   Input Parameters:
10517 + dm      - The DM
10518 . numComp - The number of components (functions)
10519 . funcs   - The coordinate functions to evaluate
10520 - mode    - The insertion mode for values
10521 
10522   Output Parameter:
10523 . X - vector
10524 
10525   Level: developer
10526 
10527   Note:
10528   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10529   We will eventually fix it.
10530 
10531 ,seealso: DMPlexComputeL2Diff()
10532 */
10533 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10534 {
10535   Vec            localX;
10536   PetscErrorCode ierr;
10537 
10538   PetscFunctionBegin;
10539   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10540   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10541   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10542   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10543   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10544   PetscFunctionReturn(0);
10545 }
10546 
10547 #undef __FUNCT__
10548 #define __FUNCT__ "DMPlexComputeL2Diff"
10549 /*@C
10550   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10551 
10552   Input Parameters:
10553 + dm    - The DM
10554 . quad  - The PetscQuadrature object for each field
10555 . funcs - The functions to evaluate for each field component
10556 - X     - The coefficient vector u_h
10557 
10558   Output Parameter:
10559 . diff - The diff ||u - u_h||_2
10560 
10561   Level: developer
10562 
10563 .seealso: DMPlexProjectFunction()
10564 */
10565 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10566 {
10567   const PetscInt debug = 0;
10568   PetscSection   section;
10569   Vec            localX;
10570   PetscReal      *coords, *v0, *J, *invJ, detJ;
10571   PetscReal      localDiff = 0.0;
10572   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10573   PetscErrorCode ierr;
10574 
10575   PetscFunctionBegin;
10576   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10577   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10578   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10579   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10580   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10581   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10582   for (field = 0; field < numFields; ++field) {
10583     numComponents += quad[field].numComponents;
10584   }
10585   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10586   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10587   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10588   for (c = cStart; c < cEnd; ++c) {
10589     const PetscScalar *x;
10590     PetscReal         elemDiff = 0.0;
10591 
10592     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10593     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10594     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10595 
10596     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10597       const PetscInt  numQuadPoints = quad[field].numQuadPoints;
10598       const PetscReal *quadPoints   = quad[field].quadPoints;
10599       const PetscReal *quadWeights  = quad[field].quadWeights;
10600       const PetscInt  numBasisFuncs = quad[field].numBasisFuncs;
10601       const PetscInt  numBasisComps = quad[field].numComponents;
10602       const PetscReal *basis        = quad[field].basis;
10603       PetscInt        q, d, e, fc, f;
10604 
10605       if (debug) {
10606         char title[1024];
10607         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10608         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10609       }
10610       for (q = 0; q < numQuadPoints; ++q) {
10611         for (d = 0; d < dim; d++) {
10612           coords[d] = v0[d];
10613           for (e = 0; e < dim; e++) {
10614             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10615           }
10616         }
10617         for (fc = 0; fc < numBasisComps; ++fc) {
10618           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10619           PetscReal       interpolant = 0.0;
10620           for (f = 0; f < numBasisFuncs; ++f) {
10621             const PetscInt fidx = f*numBasisComps+fc;
10622             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10623           }
10624           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10625           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10626         }
10627       }
10628       comp        += numBasisComps;
10629       fieldOffset += numBasisFuncs*numBasisComps;
10630     }
10631     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10632     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10633     localDiff += elemDiff;
10634   }
10635   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10636   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10637   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10638   *diff = PetscSqrtReal(*diff);
10639   PetscFunctionReturn(0);
10640 }
10641 
10642 #undef __FUNCT__
10643 #define __FUNCT__ "DMPlexComputeResidualFEM"
10644 /*@
10645   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10646 
10647   Input Parameters:
10648 + dm - The mesh
10649 . X  - Local input vector
10650 - user - The user context
10651 
10652   Output Parameter:
10653 . F  - Local output vector
10654 
10655   Note:
10656   The second member of the user context must be an FEMContext.
10657 
10658   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10659   like a GPU, or vectorize on a multicore machine.
10660 
10661 .seealso: DMPlexComputeJacobianActionFEM()
10662 */
10663 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10664 {
10665   DM_Plex         *mesh = (DM_Plex*) dm->data;
10666   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10667   PetscQuadrature *quad = fem->quad;
10668   PetscSection    section;
10669   PetscReal       *v0, *J, *invJ, *detJ;
10670   PetscScalar     *elemVec, *u;
10671   PetscInt        dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10672   PetscInt        cellDof = 0, numComponents = 0;
10673   PetscErrorCode  ierr;
10674 
10675   PetscFunctionBegin;
10676   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10677   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10678   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10679   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10680   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10681   numCells = cEnd - cStart;
10682   for (field = 0; field < numFields; ++field) {
10683     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10684     numComponents += quad[field].numComponents;
10685   }
10686   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10687   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10688   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);
10689   for (c = cStart; c < cEnd; ++c) {
10690     const PetscScalar *x;
10691     PetscInt          i;
10692 
10693     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10694     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10695     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10696 
10697     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10698     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10699   }
10700   for (field = 0; field < numFields; ++field) {
10701     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10702     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10703     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10704     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10705     /* Conforming batches */
10706     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10707     PetscInt numBlocks  = 1;
10708     PetscInt batchSize  = numBlocks * blockSize;
10709     PetscInt numBatches = numBatchesTmp;
10710     PetscInt numChunks  = numCells / (numBatches*batchSize);
10711     /* Remainder */
10712     PetscInt numRemainder = numCells % (numBatches * batchSize);
10713     PetscInt offset       = numCells - numRemainder;
10714 
10715     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10716     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10717                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10718   }
10719   for (c = cStart; c < cEnd; ++c) {
10720     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10721     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10722   }
10723   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10724   if (mesh->printFEM) {
10725     PetscMPIInt rank, numProcs;
10726     PetscInt    p;
10727 
10728     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10729     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10730     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10731     for (p = 0; p < numProcs; ++p) {
10732       if (p == rank) {
10733         Vec f;
10734 
10735         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10736         ierr = VecCopy(F, f);CHKERRQ(ierr);
10737         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10738         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10739         ierr = VecDestroy(&f);CHKERRQ(ierr);
10740         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10741       }
10742       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10743     }
10744   }
10745   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10746   PetscFunctionReturn(0);
10747 }
10748 
10749 #undef __FUNCT__
10750 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10751 /*@C
10752   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10753 
10754   Input Parameters:
10755 + dm - The mesh
10756 . J  - The Jacobian shell matrix
10757 . X  - Local input vector
10758 - user - The user context
10759 
10760   Output Parameter:
10761 . F  - Local output vector
10762 
10763   Note:
10764   The second member of the user context must be an FEMContext.
10765 
10766   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10767   like a GPU, or vectorize on a multicore machine.
10768 
10769 .seealso: DMPlexComputeResidualFEM()
10770 */
10771 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10772 {
10773   DM_Plex         *mesh = (DM_Plex*) dm->data;
10774   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10775   PetscQuadrature *quad = fem->quad;
10776   PetscSection    section;
10777   JacActionCtx    *jctx;
10778   PetscReal       *v0, *J, *invJ, *detJ;
10779   PetscScalar     *elemVec, *u, *a;
10780   PetscInt        dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10781   PetscInt        cellDof = 0;
10782   PetscErrorCode  ierr;
10783 
10784   PetscFunctionBegin;
10785   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10786   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10787   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10788   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10789   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10790   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10791   numCells = cEnd - cStart;
10792   for (field = 0; field < numFields; ++field) {
10793     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10794   }
10795   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10796   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);
10797   for (c = cStart; c < cEnd; ++c) {
10798     const PetscScalar *x;
10799     PetscInt          i;
10800 
10801     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10802     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10803     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10804     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10805     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10806     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10807     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
10808     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10809   }
10810   for (field = 0; field < numFields; ++field) {
10811     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10812     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10813     /* Conforming batches */
10814     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10815     PetscInt numBlocks  = 1;
10816     PetscInt batchSize  = numBlocks * blockSize;
10817     PetscInt numBatches = numBatchesTmp;
10818     PetscInt numChunks  = numCells / (numBatches*batchSize);
10819     /* Remainder */
10820     PetscInt numRemainder = numCells % (numBatches * batchSize);
10821     PetscInt offset       = numCells - numRemainder;
10822 
10823     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);
10824     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],
10825                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10826   }
10827   for (c = cStart; c < cEnd; ++c) {
10828     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10829     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10830   }
10831   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10832   if (mesh->printFEM) {
10833     PetscMPIInt rank, numProcs;
10834     PetscInt    p;
10835 
10836     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10837     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10838     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10839     for (p = 0; p < numProcs; ++p) {
10840       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10841       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10842     }
10843   }
10844   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10845   PetscFunctionReturn(0);
10846 }
10847 
10848 #undef __FUNCT__
10849 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10850 /*@
10851   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10852 
10853   Input Parameters:
10854 + dm - The mesh
10855 . X  - Local input vector
10856 - user - The user context
10857 
10858   Output Parameter:
10859 . Jac  - Jacobian matrix
10860 
10861   Note:
10862   The second member of the user context must be an FEMContext.
10863 
10864   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10865   like a GPU, or vectorize on a multicore machine.
10866 
10867 .seealso: FormFunctionLocal()
10868 */
10869 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10870 {
10871   DM_Plex         *mesh = (DM_Plex*) dm->data;
10872   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10873   PetscQuadrature *quad = fem->quad;
10874   PetscSection    section;
10875   PetscReal       *v0, *J, *invJ, *detJ;
10876   PetscScalar     *elemMat, *u;
10877   PetscInt        dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10878   PetscInt        cellDof = 0, numComponents = 0;
10879   PetscBool       isShell;
10880   PetscErrorCode  ierr;
10881 
10882   PetscFunctionBegin;
10883   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10884   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10885   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10886   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10887   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10888   numCells = cEnd - cStart;
10889   for (field = 0; field < numFields; ++field) {
10890     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10891     numComponents += quad[field].numComponents;
10892   }
10893   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10894   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10895   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);
10896   for (c = cStart; c < cEnd; ++c) {
10897     const PetscScalar *x;
10898     PetscInt          i;
10899 
10900     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10901     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10902     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10903 
10904     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10905     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10906   }
10907   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10908   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10909     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10910     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10911     PetscInt       fieldJ;
10912 
10913     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10914       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10915       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10916       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10917       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10918       /* Conforming batches */
10919       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10920       PetscInt numBlocks  = 1;
10921       PetscInt batchSize  = numBlocks * blockSize;
10922       PetscInt numBatches = numBatchesTmp;
10923       PetscInt numChunks  = numCells / (numBatches*batchSize);
10924       /* Remainder */
10925       PetscInt numRemainder = numCells % (numBatches * batchSize);
10926       PetscInt offset       = numCells - numRemainder;
10927 
10928       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10929       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10930                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10931     }
10932   }
10933   for (c = cStart; c < cEnd; ++c) {
10934     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10935     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10936   }
10937   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10938 
10939   /* Assemble matrix, using the 2-step process:
10940        MatAssemblyBegin(), MatAssemblyEnd(). */
10941   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10942   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10943 
10944   if (mesh->printFEM) {
10945     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10946     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10947     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10948   }
10949   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10950   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10951   if (isShell) {
10952     JacActionCtx *jctx;
10953 
10954     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10955     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10956   }
10957   *str = SAME_NONZERO_PATTERN;
10958   PetscFunctionReturn(0);
10959 }
10960 
10961 
10962 #undef __FUNCT__
10963 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10964 /*@C
10965   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10966   the local section and an SF describing the section point overlap.
10967 
10968   Input Parameters:
10969   + s - The PetscSection for the local field layout
10970   . sf - The SF describing parallel layout of the section points
10971   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10972   . label - The label specifying the points
10973   - labelValue - The label stratum specifying the points
10974 
10975   Output Parameter:
10976   . gsection - The PetscSection for the global field layout
10977 
10978   Note: This gives negative sizes and offsets to points not owned by this process
10979 
10980   Level: developer
10981 
10982 .seealso: PetscSectionCreate()
10983 @*/
10984 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10985 {
10986   PetscInt       *neg;
10987   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10988   PetscErrorCode ierr;
10989 
10990   PetscFunctionBegin;
10991   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10992   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10993   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10994   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10995   /* Mark ghost points with negative dof */
10996   for (p = pStart; p < pEnd; ++p) {
10997     PetscInt value;
10998 
10999     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11000     if (value != labelValue) continue;
11001     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11002     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11003     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11004     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11005     neg[p-pStart] = -(dof+1);
11006   }
11007   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11008   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11009   if (nroots >= 0) {
11010     if (nroots > pEnd - pStart) {
11011       PetscInt *tmpDof;
11012       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11013       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11014       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11015       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11016       for (p = pStart; p < pEnd; ++p) {
11017         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
11018       }
11019       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11020     } else {
11021       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11022       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11023     }
11024   }
11025   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11026   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11027     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11028 
11029     (*gsection)->atlasOff[p] = off;
11030 
11031     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11032   }
11033   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11034   globalOff -= off;
11035   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11036     (*gsection)->atlasOff[p] += globalOff;
11037 
11038     neg[p] = -((*gsection)->atlasOff[p]+1);
11039   }
11040   /* Put in negative offsets for ghost points */
11041   if (nroots >= 0) {
11042     if (nroots > pEnd - pStart) {
11043       PetscInt *tmpOff;
11044       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11045       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11046       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11047       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11048       for (p = pStart; p < pEnd; ++p) {
11049         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
11050       }
11051       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11052     } else {
11053       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11054       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11055     }
11056   }
11057   ierr = PetscFree(neg);CHKERRQ(ierr);
11058   PetscFunctionReturn(0);
11059 }
11060