xref: /petsc/src/dm/impls/plex/plex.c (revision 0dd27c6cfae9dc1af950b720382efbc5314fd943)
1 #include <petsc-private/pleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 
4 /* Logging support */
5 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
6 
7 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
8 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "VecView_Plex_Local"
12 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
13 {
14   DM             dm;
15   PetscBool      isvtk;
16   PetscErrorCode ierr;
17 
18   PetscFunctionBegin;
19   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
20   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
21   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
22   if (isvtk) {
23     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
24     PetscSection            section;
25     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
26 
27     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
28     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
29     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, PETSC_NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, PETSC_NULL);CHKERRQ(ierr);
32     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
33     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
34     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
35     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
36     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
37     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
38       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
39     } else if (cdof && vdof) {
40       SETERRQ(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
41     } else if (cdof) {
42       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
43        * vector or just happens to have the same number of dofs as the dimension. */
44       if (cdof == dim) {
45         ft = PETSC_VTK_CELL_VECTOR_FIELD;
46       } else {
47         ft = PETSC_VTK_CELL_FIELD;
48       }
49     } else if (vdof) {
50       if (vdof == dim) {
51         ft = PETSC_VTK_POINT_VECTOR_FIELD;
52       } else {
53         ft = PETSC_VTK_POINT_FIELD;
54       }
55     } else SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
56 
57     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
58     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
59     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
60   } else {
61     PetscBool isseq;
62 
63     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
64     if (isseq) {
65       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
66     } else {
67       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "VecView_Plex"
75 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
76 {
77   DM             dm;
78   PetscBool      isvtk;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
83   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
84   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
85   if (isvtk) {
86     Vec         locv;
87     const char *name;
88 
89     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
90     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
91     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
92     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
95     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
96   } else {
97     PetscBool isseq;
98 
99     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
100     if (isseq) {
101       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
102     } else {
103       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
104     }
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "DMPlexView_Ascii"
111 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
112 {
113   DM_Plex       *mesh = (DM_Plex *) dm->data;
114   DM                cdm;
115   DMLabel           markers;
116   PetscSection      coordSection;
117   Vec               coordinates;
118   PetscViewerFormat format;
119   PetscErrorCode    ierr;
120 
121   PetscFunctionBegin;
122   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
123   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
124   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
125   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
126   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
127     const char *name;
128     PetscInt    maxConeSize, maxSupportSize;
129     PetscInt    pStart, pEnd, p;
130     PetscMPIInt rank, size;
131 
132     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
133     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
134     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
135     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
136     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
137     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
138     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
142     for (p = pStart; p < pEnd; ++p) {
143       PetscInt dof, off, s;
144 
145       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
146       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
147       for (s = off; s < off+dof; ++s) {
148         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
149       }
150     }
151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
152     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
153     for (p = pStart; p < pEnd; ++p) {
154       PetscInt dof, off, c;
155 
156       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
157       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
158       for (c = off; c < off+dof; ++c) {
159         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
160       }
161     }
162     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
163     ierr = PetscSectionGetChart(coordSection, &pStart, PETSC_NULL);CHKERRQ(ierr);
164     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
165     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
166     if (markers) {
167       ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
168     }
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors = 3;
180     PetscReal    scale = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = PETSC_NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm = ((PetscObject) dm)->comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscMPIInt size;
282 
283     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
284     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
285     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
286     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
287     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
288     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
289     if (depth == 1) {
290       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
291       pEnd = pEnd - pStart;
292       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
293       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
294       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
295       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
296       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
297       pEnd = pEnd - pStart;
298       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
299       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
300       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
301       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
302     } else {
303       for (d = 0; d <= dim; d++) {
304         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
305         pEnd = pEnd - pStart;
306         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
307         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
308         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
309         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
310       }
311     }
312     ierr = PetscFree(sizes);CHKERRQ(ierr);
313   }
314   PetscFunctionReturn(0);
315 }
316 
317 #undef __FUNCT__
318 #define __FUNCT__ "DMView_Plex"
319 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
320 {
321   PetscBool      iascii, isbinary;
322   PetscErrorCode ierr;
323 
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
326   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
327   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
329   if (iascii) {
330     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
331 #if 0
332   } else if (isbinary) {
333     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
334 #endif
335   } else SETERRQ1(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"Viewer type %s not supported by this mesh object", ((PetscObject)viewer)->type_name);
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "DMDestroy_Plex"
341 PetscErrorCode DMDestroy_Plex(DM dm)
342 {
343   DM_Plex    *mesh = (DM_Plex *) dm->data;
344   DMLabel        next = mesh->labels;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   if (--mesh->refct > 0) {PetscFunctionReturn(0);}
349   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
350   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
352   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
353   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
355   while (next) {
356     DMLabel tmp = next->next;
357 
358     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
359     next = tmp;
360   }
361   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
362   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
364   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
365   ierr = PetscFree(mesh);CHKERRQ(ierr);
366   PetscFunctionReturn(0);
367 }
368 
369 #undef __FUNCT__
370 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
371 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
372 {
373   const PetscInt *support = PETSC_NULL;
374   PetscInt        numAdj  = 0, maxAdjSize = *adjSize, supportSize, s;
375   PetscErrorCode  ierr;
376 
377   PetscFunctionBegin;
378   if (useClosure) {
379     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
380     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
381     for (s = 0; s < supportSize; ++s) {
382       const PetscInt *cone = PETSC_NULL;
383       PetscInt        coneSize, c, q;
384 
385       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
386       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
387       for (c = 0; c < coneSize; ++c) {
388         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
389           if (cone[c] == adj[q]) break;
390         }
391         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
392       }
393     }
394   } else {
395     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
396     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
397     for (s = 0; s < supportSize; ++s) {
398       const PetscInt *cone = PETSC_NULL;
399       PetscInt        coneSize, c, q;
400 
401       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
402       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
403       for (c = 0; c < coneSize; ++c) {
404         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
405           if (cone[c] == adj[q]) break;
406         }
407         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
408       }
409     }
410   }
411   *adjSize = numAdj;
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "DMPlexGetAdjacency_Private"
417 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
418 {
419   const PetscInt *star   = tmpClosure;
420   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
421   PetscErrorCode  ierr;
422 
423   PetscFunctionBegin;
424   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt **) &star);CHKERRQ(ierr);
425   for (s = 2; s < starSize*2; s += 2) {
426     const PetscInt *closure = PETSC_NULL;
427     PetscInt        closureSize, c, q;
428 
429     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
430     for (c = 0; c < closureSize*2; c += 2) {
431       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
432         if (closure[c] == adj[q]) break;
433       }
434       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
435     }
436     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
437   }
438   *adjSize = numAdj;
439   PetscFunctionReturn(0);
440 }
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
444 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
445 {
446   DM_Plex *mesh = (DM_Plex *) dm->data;
447 
448   PetscFunctionBegin;
449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
450   mesh->preallocCenterDim = preallocCenterDim;
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "DMPlexPreallocateOperator"
456 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
457 {
458   DM_Plex        *mesh = (DM_Plex *) dm->data;
459   MPI_Comm           comm = ((PetscObject) dm)->comm;
460   PetscSF            sf, sfDof, sfAdj;
461   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
462   PetscInt           nleaves, l, p;
463   const PetscInt    *leaves;
464   const PetscSFNode *remotes;
465   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
466   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
467   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
468   PetscLayout        rLayout;
469   PetscInt           locRows, rStart, rEnd, r;
470   PetscMPIInt        size;
471   PetscBool          useClosure, debug = PETSC_FALSE;
472   PetscErrorCode     ierr;
473 
474   PetscFunctionBegin;
475   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
476   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
477   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
478   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
479   /* Create dof SF based on point SF */
480   if (debug) {
481     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
487   }
488   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
489   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
490   if (debug) {
491     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
492     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
493   }
494   /* Create section for dof adjacency (dof ==> # adj dof) */
495   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
496   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
497   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
498   if (mesh->preallocCenterDim == dim) {
499     useClosure = PETSC_FALSE;
500   } else if (mesh->preallocCenterDim == 0) {
501     useClosure = PETSC_TRUE;
502   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
503 
504   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
505   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
510   /*   Fill in the ghost dofs on the interface */
511   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
512   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
513   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
514   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
515   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
516   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
517 
518   /*
519    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
520     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
521        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
522     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
523        Create sfAdj connecting rootSectionAdj and leafSectionAdj
524     3. Visit unowned points on interface, write adjacencies to adj
525        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
526     4. Visit owned points on interface, write adjacencies to rootAdj
527        Remove redundancy in rootAdj
528    ** The last two traversals use transitive closure
529     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
530        Allocate memory addressed by sectionAdj (cols)
531     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
532    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
533   */
534 
535   for (l = 0; l < nleaves; ++l) {
536     PetscInt dof, off, d, q;
537     PetscInt p = leaves[l], numAdj = maxAdjSize;
538 
539     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
540     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
541     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
542     for (q = 0; q < numAdj; ++q) {
543       PetscInt ndof, ncdof;
544 
545       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
546       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
547       for (d = off; d < off+dof; ++d) {
548         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
549       }
550     }
551   }
552   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
553   if (debug) {
554     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
555     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
556   }
557   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
558   if (size > 1) {
559     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
560     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561   }
562   if (debug) {
563     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
564     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
565   }
566   /* Add in local adjacency sizes for owned dofs on interface (roots) */
567   for (p = pStart; p < pEnd; ++p) {
568     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
569 
570     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
571     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
572     if (!dof) continue;
573     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
574     if (adof <= 0) continue;
575     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
576     for (q = 0; q < numAdj; ++q) {
577       PetscInt ndof, ncdof;
578 
579       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
580       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
581       for (d = off; d < off+dof; ++d) {
582         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
583       }
584     }
585   }
586   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
587   if (debug) {
588     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
589     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
590   }
591   /* Create adj SF based on dof SF */
592   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
593   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
596     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
597   }
598   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
599   /* Create leaf adjacency */
600   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
601   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
602   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
603   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
604   for (l = 0; l < nleaves; ++l) {
605     PetscInt dof, off, d, q;
606     PetscInt p = leaves[l], numAdj = maxAdjSize;
607 
608     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
609     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
610     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
611     for (d = off; d < off+dof; ++d) {
612       PetscInt aoff, i = 0;
613 
614       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
615       for (q = 0; q < numAdj; ++q) {
616         PetscInt  ndof, ncdof, ngoff, nd;
617 
618         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
619         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
620         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
621         for (nd = 0; nd < ndof-ncdof; ++nd) {
622           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
623           ++i;
624         }
625       }
626     }
627   }
628   /* Debugging */
629   if (debug) {
630     IS tmp;
631     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
632     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
633     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
634   }
635   /* Gather adjacenct indices to root */
636   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
637   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
638   for (r = 0; r < adjSize; ++r) {
639     rootAdj[r] = -1;
640   }
641   if (size > 1) {
642     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
643     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
644   }
645   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
646   ierr = PetscFree(adj);CHKERRQ(ierr);
647   /* Debugging */
648   if (debug) {
649     IS tmp;
650     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
651     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
652     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
653   }
654   /* Add in local adjacency indices for owned dofs on interface (roots) */
655   for (p = pStart; p < pEnd; ++p) {
656     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
657 
658     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
659     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
660     if (!dof) continue;
661     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
662     if (adof <= 0) continue;
663     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
664     for (d = off; d < off+dof; ++d) {
665       PetscInt adof, aoff, i;
666 
667       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
668       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
669       i    = adof-1;
670       for (q = 0; q < numAdj; ++q) {
671         PetscInt ndof, ncdof, ngoff, nd;
672 
673         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
674         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
675         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
676         for (nd = 0; nd < ndof-ncdof; ++nd) {
677           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
678           --i;
679         }
680       }
681     }
682   }
683   /* Debugging */
684   if (debug) {
685     IS tmp;
686     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
687     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
688     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
689   }
690   /* Compress indices */
691   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
692   for (p = pStart; p < pEnd; ++p) {
693     PetscInt dof, cdof, off, d;
694     PetscInt adof, aoff;
695 
696     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
697     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
698     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
699     if (!dof) continue;
700     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
701     if (adof <= 0) continue;
702     for (d = off; d < off+dof-cdof; ++d) {
703       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
704       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
705       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
706       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
707     }
708   }
709   /* Debugging */
710   if (debug) {
711     IS tmp;
712     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
713     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
714     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
715     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
716     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
717   }
718   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
719   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
720   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
721   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
722   for (p = pStart; p < pEnd; ++p) {
723     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
724     PetscBool found  = PETSC_TRUE;
725 
726     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
727     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
728     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
729     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
730     for (d = 0; d < dof-cdof; ++d) {
731       PetscInt ldof, rdof;
732 
733       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
734       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
735       if (ldof > 0) {
736         /* We do not own this point */
737       } else if (rdof > 0) {
738         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
739       } else {
740         found = PETSC_FALSE;
741       }
742     }
743     if (found) continue;
744     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
745     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
746     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
747     for (q = 0; q < numAdj; ++q) {
748       PetscInt ndof, ncdof, noff;
749 
750       /* Adjacent points may not be in the section chart */
751       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
752       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
753       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
754       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
755       for (d = goff; d < goff+dof-cdof; ++d) {
756         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
757       }
758     }
759   }
760   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
761   if (debug) {
762     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
763     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
764   }
765   /* Get adjacent indices */
766   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
767   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
768   for (p = pStart; p < pEnd; ++p) {
769     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
770     PetscBool found  = PETSC_TRUE;
771 
772     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
773     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
774     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
775     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
776     for (d = 0; d < dof-cdof; ++d) {
777       PetscInt ldof, rdof;
778 
779       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
780       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
781       if (ldof > 0) {
782         /* We do not own this point */
783       } else if (rdof > 0) {
784         PetscInt aoff, roff;
785 
786         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
787         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
788         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
789       } else {
790         found = PETSC_FALSE;
791       }
792     }
793     if (found) continue;
794     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
795     for (d = goff; d < goff+dof-cdof; ++d) {
796       PetscInt adof, aoff, i = 0;
797 
798       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
799       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
800       for (q = 0; q < numAdj; ++q) {
801         PetscInt        ndof, ncdof, ngoff, nd;
802         const PetscInt *ncind;
803 
804         /* Adjacent points may not be in the section chart */
805         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
806         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
807         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
808         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
809         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
810         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
811           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
812         }
813       }
814       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
815     }
816   }
817   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
818   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
819   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
820   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
821   /* Debugging */
822   if (debug) {
823     IS tmp;
824     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
825     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
826     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
827   }
828   /* Create allocation vectors from adjacency graph */
829   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
830   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
831   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
832   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
833   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
834   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
835   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
836   /* Only loop over blocks of rows */
837   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
838   for (r = rStart/bs; r < rEnd/bs; ++r) {
839     const PetscInt row = r*bs;
840     PetscInt numCols, cStart, c;
841 
842     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
843     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
844     for (c = cStart; c < cStart+numCols; ++c) {
845       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
846         ++dnz[r-rStart];
847         if (cols[c] >= row) {++dnzu[r-rStart];}
848       } else {
849         ++onz[r-rStart];
850         if (cols[c] >= row) {++onzu[r-rStart];}
851       }
852     }
853   }
854   if (bs > 1) {
855     for (r = 0; r < locRows/bs; ++r) {
856       dnz[r]  /= bs;
857       onz[r]  /= bs;
858       dnzu[r] /= bs;
859       onzu[r] /= bs;
860     }
861   }
862   /* Set matrix pattern */
863   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
864   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
865   /* Fill matrix with zeros */
866   if (fillMatrix) {
867     PetscScalar *values;
868     PetscInt     maxRowLen = 0;
869 
870     for (r = rStart; r < rEnd; ++r) {
871       PetscInt len;
872 
873       ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
874       maxRowLen = PetscMax(maxRowLen, len);
875     }
876     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
877     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
878     for (r = rStart; r < rEnd; ++r) {
879       PetscInt numCols, cStart;
880 
881       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
882       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
883       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
884     }
885     ierr = PetscFree(values);CHKERRQ(ierr);
886     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
887     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
888   }
889   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
890   ierr = PetscFree(cols);CHKERRQ(ierr);
891   PetscFunctionReturn(0);
892 }
893 
894 #if 0
895 #undef __FUNCT__
896 #define __FUNCT__ "DMPlexPreallocateOperator_2"
897 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
898 {
899   PetscErrorCode ierr;
900   PetscInt c,cStart,cEnd,pStart,pEnd;
901   PetscInt *tmpClosure,*tmpAdj,*visits;
902 
903   PetscFunctionBegin;
904   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
905   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
906   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
907   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
908   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
911   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
912   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
914   for (c=cStart; c<cEnd; c++) {
915     PetscInt *support = tmpClosure;
916     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
917     for (p=0; p<supportSize; p++) {
918       lvisits[support[p]]++;
919     }
920   }
921   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
923   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
925 
926   ierr = PetscSFGetRanks();CHKERRQ(ierr);
927 
928 
929   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
930   for (c=cStart; c<cEnd; c++) {
931     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
932     /*
933      Depth-first walk of transitive closure.
934      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
935      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
936      */
937   }
938 
939   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
940   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
941   PetscFunctionReturn(0);
942 }
943 #endif
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "DMCreateMatrix_Plex"
947 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
948 {
949   PetscSection   section, sectionGlobal;
950   PetscInt       bs = -1;
951   PetscInt       localSize;
952   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
953   PetscErrorCode ierr;
954 
955   PetscFunctionBegin;
956 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
957   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
958 #endif
959   if (!mtype) mtype = MATAIJ;
960   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
961   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
962   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
963   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
964   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
965   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
966   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
967   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
975   /* Check for symmetric storage */
976   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
977   if (isSymmetric) {
978     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
979   }
980   if (!isShell) {
981     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
982     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal;
983 
984     if (bs < 0) {
985       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
986         PetscInt pStart, pEnd, p, dof;
987 
988         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
989         for (p = pStart; p < pEnd; ++p) {
990           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
991           if (dof) {
992             bs = dof;
993             break;
994           }
995         }
996       } else {
997         bs = 1;
998       }
999       /* Must have same blocksize on all procs (some might have no points) */
1000       bsLocal = bs;
1001       ierr = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1002     }
1003     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1004     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1005     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1006     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1007     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1008     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1009     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1010   }
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 #undef __FUNCT__
1015 #define __FUNCT__ "DMPlexGetDimension"
1016 /*@
1017   DMPlexGetDimension - Return the topological mesh dimension
1018 
1019   Not collective
1020 
1021   Input Parameter:
1022 . mesh - The DMPlex
1023 
1024   Output Parameter:
1025 . dim - The topological mesh dimension
1026 
1027   Level: beginner
1028 
1029 .seealso: DMPlexCreate()
1030 @*/
1031 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1032 {
1033   DM_Plex *mesh = (DM_Plex *) dm->data;
1034 
1035   PetscFunctionBegin;
1036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1037   PetscValidPointer(dim, 2);
1038   *dim = mesh->dim;
1039   PetscFunctionReturn(0);
1040 }
1041 
1042 #undef __FUNCT__
1043 #define __FUNCT__ "DMPlexSetDimension"
1044 /*@
1045   DMPlexSetDimension - Set the topological mesh dimension
1046 
1047   Collective on mesh
1048 
1049   Input Parameters:
1050 + mesh - The DMPlex
1051 - dim - The topological mesh dimension
1052 
1053   Level: beginner
1054 
1055 .seealso: DMPlexCreate()
1056 @*/
1057 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1058 {
1059   DM_Plex *mesh = (DM_Plex *) dm->data;
1060 
1061   PetscFunctionBegin;
1062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1063   PetscValidLogicalCollectiveInt(dm, dim, 2);
1064   mesh->dim = dim;
1065   mesh->preallocCenterDim = dim;
1066   PetscFunctionReturn(0);
1067 }
1068 
1069 #undef __FUNCT__
1070 #define __FUNCT__ "DMPlexGetChart"
1071 /*@
1072   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1073 
1074   Not collective
1075 
1076   Input Parameter:
1077 . mesh - The DMPlex
1078 
1079   Output Parameters:
1080 + pStart - The first mesh point
1081 - pEnd   - The upper bound for mesh points
1082 
1083   Level: beginner
1084 
1085 .seealso: DMPlexCreate(), DMPlexSetChart()
1086 @*/
1087 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1088 {
1089   DM_Plex    *mesh = (DM_Plex *) dm->data;
1090   PetscErrorCode ierr;
1091 
1092   PetscFunctionBegin;
1093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1094   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1095   PetscFunctionReturn(0);
1096 }
1097 
1098 #undef __FUNCT__
1099 #define __FUNCT__ "DMPlexSetChart"
1100 /*@
1101   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1102 
1103   Not collective
1104 
1105   Input Parameters:
1106 + mesh - The DMPlex
1107 . pStart - The first mesh point
1108 - pEnd   - The upper bound for mesh points
1109 
1110   Output Parameters:
1111 
1112   Level: beginner
1113 
1114 .seealso: DMPlexCreate(), DMPlexGetChart()
1115 @*/
1116 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1117 {
1118   DM_Plex    *mesh = (DM_Plex *) dm->data;
1119   PetscErrorCode ierr;
1120 
1121   PetscFunctionBegin;
1122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1123   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1124   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 #undef __FUNCT__
1129 #define __FUNCT__ "DMPlexGetConeSize"
1130 /*@
1131   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1132 
1133   Not collective
1134 
1135   Input Parameters:
1136 + mesh - The DMPlex
1137 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1138 
1139   Output Parameter:
1140 . size - The cone size for point p
1141 
1142   Level: beginner
1143 
1144 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1145 @*/
1146 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1147 {
1148   DM_Plex    *mesh = (DM_Plex *) dm->data;
1149   PetscErrorCode ierr;
1150 
1151   PetscFunctionBegin;
1152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1153   PetscValidPointer(size, 3);
1154   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1155   PetscFunctionReturn(0);
1156 }
1157 
1158 #undef __FUNCT__
1159 #define __FUNCT__ "DMPlexSetConeSize"
1160 /*@
1161   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1162 
1163   Not collective
1164 
1165   Input Parameters:
1166 + mesh - The DMPlex
1167 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1168 - size - The cone size for point p
1169 
1170   Output Parameter:
1171 
1172   Note:
1173   This should be called after DMPlexSetChart().
1174 
1175   Level: beginner
1176 
1177 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1178 @*/
1179 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1180 {
1181   DM_Plex    *mesh = (DM_Plex *) dm->data;
1182   PetscErrorCode ierr;
1183 
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1186   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1187   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1188   PetscFunctionReturn(0);
1189 }
1190 
1191 #undef __FUNCT__
1192 #define __FUNCT__ "DMPlexGetCone"
1193 /*@C
1194   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1195 
1196   Not collective
1197 
1198   Input Parameters:
1199 + mesh - The DMPlex
1200 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1201 
1202   Output Parameter:
1203 . cone - An array of points which are on the in-edges for point p
1204 
1205   Level: beginner
1206 
1207   Note:
1208   This routine is not available in Fortran.
1209 
1210 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1211 @*/
1212 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1213 {
1214   DM_Plex    *mesh = (DM_Plex *) dm->data;
1215   PetscInt       off;
1216   PetscErrorCode ierr;
1217 
1218   PetscFunctionBegin;
1219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1220   PetscValidPointer(cone, 3);
1221   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1222   *cone = &mesh->cones[off];
1223   PetscFunctionReturn(0);
1224 }
1225 
1226 #undef __FUNCT__
1227 #define __FUNCT__ "DMPlexSetCone"
1228 /*@
1229   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1230 
1231   Not collective
1232 
1233   Input Parameters:
1234 + mesh - The DMPlex
1235 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1236 - cone - An array of points which are on the in-edges for point p
1237 
1238   Output Parameter:
1239 
1240   Note:
1241   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1242 
1243   Level: beginner
1244 
1245 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1246 @*/
1247 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1248 {
1249   DM_Plex    *mesh = (DM_Plex *) dm->data;
1250   PetscInt       pStart, pEnd;
1251   PetscInt       dof, off, c;
1252   PetscErrorCode ierr;
1253 
1254   PetscFunctionBegin;
1255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1256   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1257   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1258   if (dof) PetscValidPointer(cone, 3);
1259   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1260   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1261   for (c = 0; c < dof; ++c) {
1262     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1263     mesh->cones[off+c] = cone[c];
1264   }
1265   PetscFunctionReturn(0);
1266 }
1267 
1268 #undef __FUNCT__
1269 #define __FUNCT__ "DMPlexGetConeOrientation"
1270 /*@C
1271   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1272 
1273   Not collective
1274 
1275   Input Parameters:
1276 + mesh - The DMPlex
1277 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1278 
1279   Output Parameter:
1280 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1281                     integer giving the prescription for cone traversal. If it is negative, the cone is
1282                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1283                     the index of the cone point on which to start.
1284 
1285   Level: beginner
1286 
1287   Note:
1288   This routine is not available in Fortran.
1289 
1290 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1291 @*/
1292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1293 {
1294   DM_Plex    *mesh = (DM_Plex *) dm->data;
1295   PetscInt       off;
1296   PetscErrorCode ierr;
1297 
1298   PetscFunctionBegin;
1299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1300 #if defined(PETSC_USE_DEBUG)
1301   {
1302     PetscInt dof;
1303     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1304     if (dof) PetscValidPointer(coneOrientation, 3);
1305   }
1306 #endif
1307   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1308   *coneOrientation = &mesh->coneOrientations[off];
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 #undef __FUNCT__
1313 #define __FUNCT__ "DMPlexSetConeOrientation"
1314 /*@
1315   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1316 
1317   Not collective
1318 
1319   Input Parameters:
1320 + mesh - The DMPlex
1321 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1322 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1323                     integer giving the prescription for cone traversal. If it is negative, the cone is
1324                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1325                     the index of the cone point on which to start.
1326 
1327   Output Parameter:
1328 
1329   Note:
1330   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1331 
1332   Level: beginner
1333 
1334 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1335 @*/
1336 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1337 {
1338   DM_Plex    *mesh = (DM_Plex *) dm->data;
1339   PetscInt       pStart, pEnd;
1340   PetscInt       dof, off, c;
1341   PetscErrorCode ierr;
1342 
1343   PetscFunctionBegin;
1344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1345   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1346   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1347   if (dof) PetscValidPointer(coneOrientation, 3);
1348   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1349   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1350   for (c = 0; c < dof; ++c) {
1351     PetscInt cdof, o = coneOrientation[c];
1352 
1353     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1354     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1355     mesh->coneOrientations[off+c] = o;
1356   }
1357   PetscFunctionReturn(0);
1358 }
1359 
1360 #undef __FUNCT__
1361 #define __FUNCT__ "DMPlexInsertCone"
1362 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1363 {
1364   DM_Plex    *mesh = (DM_Plex *) dm->data;
1365   PetscInt       pStart, pEnd;
1366   PetscInt       dof, off;
1367   PetscErrorCode ierr;
1368 
1369   PetscFunctionBegin;
1370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1371   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1372   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1373   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1374   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1375   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1376   if (conePos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1377   mesh->cones[off+conePos] = conePoint;
1378   PetscFunctionReturn(0);
1379 }
1380 
1381 #undef __FUNCT__
1382 #define __FUNCT__ "DMPlexGetSupportSize"
1383 /*@
1384   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1385 
1386   Not collective
1387 
1388   Input Parameters:
1389 + mesh - The DMPlex
1390 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1391 
1392   Output Parameter:
1393 . size - The support size for point p
1394 
1395   Level: beginner
1396 
1397 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1398 @*/
1399 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1400 {
1401   DM_Plex    *mesh = (DM_Plex *) dm->data;
1402   PetscErrorCode ierr;
1403 
1404   PetscFunctionBegin;
1405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1406   PetscValidPointer(size, 3);
1407   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1408   PetscFunctionReturn(0);
1409 }
1410 
1411 #undef __FUNCT__
1412 #define __FUNCT__ "DMPlexSetSupportSize"
1413 /*@
1414   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1415 
1416   Not collective
1417 
1418   Input Parameters:
1419 + mesh - The DMPlex
1420 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1421 - size - The support size for point p
1422 
1423   Output Parameter:
1424 
1425   Note:
1426   This should be called after DMPlexSetChart().
1427 
1428   Level: beginner
1429 
1430 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1431 @*/
1432 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1433 {
1434   DM_Plex    *mesh = (DM_Plex *) dm->data;
1435   PetscErrorCode ierr;
1436 
1437   PetscFunctionBegin;
1438   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1439   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1440   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1441   PetscFunctionReturn(0);
1442 }
1443 
1444 #undef __FUNCT__
1445 #define __FUNCT__ "DMPlexGetSupport"
1446 /*@C
1447   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1448 
1449   Not collective
1450 
1451   Input Parameters:
1452 + mesh - The DMPlex
1453 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1454 
1455   Output Parameter:
1456 . support - An array of points which are on the out-edges for point p
1457 
1458   Level: beginner
1459 
1460 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1461 @*/
1462 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1463 {
1464   DM_Plex    *mesh = (DM_Plex *) dm->data;
1465   PetscInt       off;
1466   PetscErrorCode ierr;
1467 
1468   PetscFunctionBegin;
1469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1470   PetscValidPointer(support, 3);
1471   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1472   *support = &mesh->supports[off];
1473   PetscFunctionReturn(0);
1474 }
1475 
1476 #undef __FUNCT__
1477 #define __FUNCT__ "DMPlexSetSupport"
1478 /*@
1479   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1480 
1481   Not collective
1482 
1483   Input Parameters:
1484 + mesh - The DMPlex
1485 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1486 - support - An array of points which are on the in-edges for point p
1487 
1488   Output Parameter:
1489 
1490   Note:
1491   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1492 
1493   Level: beginner
1494 
1495 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1496 @*/
1497 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1498 {
1499   DM_Plex    *mesh = (DM_Plex *) dm->data;
1500   PetscInt       pStart, pEnd;
1501   PetscInt       dof, off, c;
1502   PetscErrorCode ierr;
1503 
1504   PetscFunctionBegin;
1505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1506   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1507   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1508   if (dof) PetscValidPointer(support, 3);
1509   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1510   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1511   for (c = 0; c < dof; ++c) {
1512     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1513     mesh->supports[off+c] = support[c];
1514   }
1515   PetscFunctionReturn(0);
1516 }
1517 
1518 #undef __FUNCT__
1519 #define __FUNCT__ "DMPlexInsertSupport"
1520 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1521 {
1522   DM_Plex    *mesh = (DM_Plex *) dm->data;
1523   PetscInt       pStart, pEnd;
1524   PetscInt       dof, off;
1525   PetscErrorCode ierr;
1526 
1527   PetscFunctionBegin;
1528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1529   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1530   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1531   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1532   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1533   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1534   if (supportPos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1535   mesh->supports[off+supportPos] = supportPoint;
1536   PetscFunctionReturn(0);
1537 }
1538 
1539 #undef __FUNCT__
1540 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1541 /*@C
1542   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1543 
1544   Not collective
1545 
1546   Input Parameters:
1547 + mesh - The DMPlex
1548 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1549 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1550 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1551 
1552   Output Parameters:
1553 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1554 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1555 
1556   Note:
1557   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1558 
1559   Level: beginner
1560 
1561 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1562 @*/
1563 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1564 {
1565   DM_Plex     *mesh = (DM_Plex *) dm->data;
1566   PetscInt       *closure, *fifo;
1567   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1568   PetscInt        tmpSize, t;
1569   PetscInt        depth = 0, maxSize;
1570   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1571   PetscErrorCode  ierr;
1572 
1573   PetscFunctionBegin;
1574   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1575   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1576   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1577   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1578   if (*points) {
1579     closure = *points;
1580   } else {
1581     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1582   }
1583   closure[0] = p; closure[1] = 0;
1584   /* This is only 1-level */
1585   if (useCone) {
1586     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1587     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1588     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1589   } else {
1590     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1591     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1592   }
1593   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1594     const PetscInt cp = tmp[t];
1595     const PetscInt co = tmpO ? tmpO[t] : 0;
1596 
1597     closure[closureSize]   = cp;
1598     closure[closureSize+1] = co;
1599     fifo[fifoSize]         = cp;
1600     fifo[fifoSize+1]       = co;
1601   }
1602   while (fifoSize - fifoStart) {
1603     const PetscInt q   = fifo[fifoStart];
1604     const PetscInt o   = fifo[fifoStart+1];
1605     const PetscInt rev = o >= 0 ? 0 : 1;
1606     const PetscInt off = rev ? -(o+1) : o;
1607 
1608     if (useCone) {
1609       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1610       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1611       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1612     } else {
1613       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1614       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1615       tmpO = PETSC_NULL;
1616     }
1617     for (t = 0; t < tmpSize; ++t) {
1618       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1619       const PetscInt cp = tmp[i];
1620       /* Must propogate orientation */
1621       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1622       PetscInt       c;
1623 
1624       /* Check for duplicate */
1625       for (c = 0; c < closureSize; c += 2) {
1626         if (closure[c] == cp) break;
1627       }
1628       if (c == closureSize) {
1629         closure[closureSize]   = cp;
1630         closure[closureSize+1] = co;
1631         fifo[fifoSize]         = cp;
1632         fifo[fifoSize+1]       = co;
1633         closureSize += 2;
1634         fifoSize    += 2;
1635       }
1636     }
1637     fifoStart += 2;
1638   }
1639   if (numPoints) *numPoints = closureSize/2;
1640   if (points)    *points    = closure;
1641   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1642   PetscFunctionReturn(0);
1643 }
1644 
1645 #undef __FUNCT__
1646 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1647 /*@C
1648   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1649 
1650   Not collective
1651 
1652   Input Parameters:
1653 + mesh - The DMPlex
1654 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1655 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1656 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1657 
1658   Output Parameters:
1659 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1660 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1661 
1662   Note:
1663   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1664 
1665   Level: beginner
1666 
1667 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1668 @*/
1669 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1670 {
1671   PetscErrorCode  ierr;
1672 
1673   PetscFunctionBegin;
1674   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1675   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1676   PetscFunctionReturn(0);
1677 }
1678 
1679 #undef __FUNCT__
1680 #define __FUNCT__ "DMPlexGetFaces"
1681 /*
1682   DMPlexGetFaces -
1683 
1684   Note: This will only work for cell-vertex meshes.
1685 */
1686 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1687 {
1688   DM_Plex     *mesh  = (DM_Plex *) dm->data;
1689   const PetscInt *cone  = PETSC_NULL;
1690   PetscInt        depth = 0, dim, coneSize;
1691   PetscErrorCode  ierr;
1692 
1693   PetscFunctionBegin;
1694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1695   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1696   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1697   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1698   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1699   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1700   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1701   switch (dim) {
1702   case 2:
1703     switch (coneSize) {
1704     case 3:
1705       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1706       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1707       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1708       *numFaces = 3;
1709       *faceSize = 2;
1710       *faces    = mesh->facesTmp;
1711       break;
1712     case 4:
1713       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1714       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1715       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1716       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1717       *numFaces = 4;
1718       *faceSize = 2;
1719       *faces    = mesh->facesTmp;
1720       break;
1721     default:
1722       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1723     }
1724     break;
1725   case 3:
1726     switch (coneSize) {
1727     case 3:
1728       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1729       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1730       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1731       *numFaces = 3;
1732       *faceSize = 2;
1733       *faces    = mesh->facesTmp;
1734       break;
1735     case 4:
1736       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1737       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1738       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1739       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1740       *numFaces = 4;
1741       *faceSize = 3;
1742       *faces    = mesh->facesTmp;
1743       break;
1744     default:
1745       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1746     }
1747     break;
1748   default:
1749     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1750   }
1751   PetscFunctionReturn(0);
1752 }
1753 
1754 #undef __FUNCT__
1755 #define __FUNCT__ "DMPlexGetMaxSizes"
1756 /*@
1757   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1758 
1759   Not collective
1760 
1761   Input Parameter:
1762 . mesh - The DMPlex
1763 
1764   Output Parameters:
1765 + maxConeSize - The maximum number of in-edges
1766 - maxSupportSize - The maximum number of out-edges
1767 
1768   Level: beginner
1769 
1770 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1771 @*/
1772 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1773 {
1774   DM_Plex *mesh = (DM_Plex *) dm->data;
1775 
1776   PetscFunctionBegin;
1777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1778   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1779   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1780   PetscFunctionReturn(0);
1781 }
1782 
1783 #undef __FUNCT__
1784 #define __FUNCT__ "DMSetUp_Plex"
1785 PetscErrorCode DMSetUp_Plex(DM dm)
1786 {
1787   DM_Plex    *mesh = (DM_Plex *) dm->data;
1788   PetscInt       size;
1789   PetscErrorCode ierr;
1790 
1791   PetscFunctionBegin;
1792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1793   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1794   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1795   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1796   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1797   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1798   if (mesh->maxSupportSize) {
1799     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1800     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1801     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1802   }
1803   PetscFunctionReturn(0);
1804 }
1805 
1806 #undef __FUNCT__
1807 #define __FUNCT__ "DMCreateSubDM_Plex"
1808 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1809 {
1810   PetscSection   section, sectionGlobal;
1811   PetscInt      *subIndices;
1812   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1813   PetscErrorCode ierr;
1814 
1815   PetscFunctionBegin;
1816   if (!numFields) PetscFunctionReturn(0);
1817   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1818   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1819   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1820   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1821   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1822   if (numFields > nF) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1823   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1824   for (p = pStart; p < pEnd; ++p) {
1825     PetscInt gdof;
1826 
1827     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1828     if (gdof > 0) {
1829       for (f = 0; f < numFields; ++f) {
1830         PetscInt fdof, fcdof;
1831 
1832         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1833         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1834         subSize += fdof-fcdof;
1835       }
1836     }
1837   }
1838   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1839   for (p = pStart; p < pEnd; ++p) {
1840     PetscInt gdof, goff;
1841 
1842     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1843     if (gdof > 0) {
1844       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1845       for (f = 0; f < numFields; ++f) {
1846         PetscInt fdof, fcdof, fc, f2, poff = 0;
1847 
1848         /* Can get rid of this loop by storing field information in the global section */
1849         for (f2 = 0; f2 < fields[f]; ++f2) {
1850           ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1851           ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1852           poff += fdof-fcdof;
1853         }
1854         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1855         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1856         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1857           subIndices[subOff] = goff+poff+fc;
1858         }
1859       }
1860     }
1861   }
1862   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1863   if (subdm) {
1864     PetscSection subsection;
1865     PetscBool    haveNull = PETSC_FALSE;
1866     PetscInt     f, nf = 0;
1867 
1868     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1869     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1870     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1871     for (f = 0; f < numFields; ++f) {
1872       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1873       if ((*subdm)->nullspaceConstructors[f]) {
1874         haveNull = PETSC_TRUE;
1875         nf       = f;
1876       }
1877     }
1878     if (haveNull) {
1879       MatNullSpace nullSpace;
1880 
1881       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1882       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1883       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1884     }
1885     if (dm->fields) {
1886       if (nF != dm->numFields) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1887       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1888       for (f = 0; f < numFields; ++f) {
1889         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1890       }
1891       if (numFields == 1) {
1892         MatNullSpace space;
1893         Mat          pmat;
1894 
1895         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject *) &space);CHKERRQ(ierr);
1896         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1897         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject *) &space);CHKERRQ(ierr);
1898         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1899         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject *) &pmat);CHKERRQ(ierr);
1900         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1901       }
1902     }
1903   }
1904   PetscFunctionReturn(0);
1905 }
1906 
1907 #undef __FUNCT__
1908 #define __FUNCT__ "DMPlexSymmetrize"
1909 /*@
1910   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1911 
1912   Not collective
1913 
1914   Input Parameter:
1915 . mesh - The DMPlex
1916 
1917   Output Parameter:
1918 
1919   Note:
1920   This should be called after all calls to DMPlexSetCone()
1921 
1922   Level: beginner
1923 
1924 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1925 @*/
1926 PetscErrorCode DMPlexSymmetrize(DM dm)
1927 {
1928   DM_Plex    *mesh = (DM_Plex *) dm->data;
1929   PetscInt      *offsets;
1930   PetscInt       supportSize;
1931   PetscInt       pStart, pEnd, p;
1932   PetscErrorCode ierr;
1933 
1934   PetscFunctionBegin;
1935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1936   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1937   /* Calculate support sizes */
1938   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1939   for (p = pStart; p < pEnd; ++p) {
1940     PetscInt dof, off, c;
1941 
1942     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1943     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1944     for (c = off; c < off+dof; ++c) {
1945       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1946     }
1947   }
1948   for (p = pStart; p < pEnd; ++p) {
1949     PetscInt dof;
1950 
1951     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1952     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1953   }
1954   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1955   /* Calculate supports */
1956   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1957   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1958   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1959   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1960   for (p = pStart; p < pEnd; ++p) {
1961     PetscInt dof, off, c;
1962 
1963     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1964     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1965     for (c = off; c < off+dof; ++c) {
1966       const PetscInt q = mesh->cones[c];
1967       PetscInt       offS;
1968 
1969       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1970       mesh->supports[offS+offsets[q]] = p;
1971       ++offsets[q];
1972     }
1973   }
1974   ierr = PetscFree(offsets);CHKERRQ(ierr);
1975   PetscFunctionReturn(0);
1976 }
1977 
1978 #undef __FUNCT__
1979 #define __FUNCT__ "DMPlexSetDepth_Private"
1980 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1981 {
1982   PetscInt       d;
1983   PetscErrorCode ierr;
1984 
1985   PetscFunctionBegin;
1986   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1987   if (d < 0) {
1988     /* We are guaranteed that the point has a cone since the depth was not yet set */
1989     const PetscInt *cone = PETSC_NULL;
1990     PetscInt        dCone;
1991 
1992     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1993     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1994     d    = dCone+1;
1995     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1996   }
1997   *depth = d;
1998   PetscFunctionReturn(0);
1999 }
2000 
2001 #undef __FUNCT__
2002 #define __FUNCT__ "DMPlexStratify"
2003 /*@
2004   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2005   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2006   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2007   the DAG.
2008 
2009   Not collective
2010 
2011   Input Parameter:
2012 . mesh - The DMPlex
2013 
2014   Output Parameter:
2015 
2016   Notes:
2017   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2018   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2019 
2020   This should be called after all calls to DMPlexSymmetrize()
2021 
2022   Level: beginner
2023 
2024 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2025 @*/
2026 PetscErrorCode DMPlexStratify(DM dm)
2027 {
2028   DM_Plex    *mesh = (DM_Plex *) dm->data;
2029   PetscInt       pStart, pEnd, p;
2030   PetscInt       numRoots = 0, numLeaves = 0;
2031   PetscErrorCode ierr;
2032 
2033   PetscFunctionBegin;
2034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2035   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2036   /* Calculate depth */
2037   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2038   /* Initialize roots and count leaves */
2039   for (p = pStart; p < pEnd; ++p) {
2040     PetscInt coneSize, supportSize;
2041 
2042     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2043     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2044     if (!coneSize && supportSize) {
2045       ++numRoots;
2046       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2047     } else if (!supportSize && coneSize) {
2048       ++numLeaves;
2049     } else if (!supportSize && !coneSize) {
2050       /* Isolated points */
2051       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2052     }
2053   }
2054   if (numRoots + numLeaves == (pEnd - pStart)) {
2055     for (p = pStart; p < pEnd; ++p) {
2056       PetscInt coneSize, supportSize;
2057 
2058       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2059       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2060       if (!supportSize && coneSize) {
2061         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2062       }
2063     }
2064   } else {
2065     /* This might be slow since lookup is not fast */
2066     for (p = pStart; p < pEnd; ++p) {
2067       PetscInt depth;
2068 
2069       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2070     }
2071   }
2072   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2073   PetscFunctionReturn(0);
2074 }
2075 
2076 #undef __FUNCT__
2077 #define __FUNCT__ "DMPlexGetJoin"
2078 /*@C
2079   DMPlexGetJoin - Get an array for the join of the set of points
2080 
2081   Not Collective
2082 
2083   Input Parameters:
2084 + dm - The DMPlex object
2085 . numPoints - The number of input points for the join
2086 - points - The input points
2087 
2088   Output Parameters:
2089 + numCoveredPoints - The number of points in the join
2090 - coveredPoints - The points in the join
2091 
2092   Level: intermediate
2093 
2094   Note: Currently, this is restricted to a single level join
2095 
2096 .keywords: mesh
2097 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2098 @*/
2099 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2100 {
2101   DM_Plex    *mesh = (DM_Plex *) dm->data;
2102   PetscInt      *join[2];
2103   PetscInt       joinSize, i = 0;
2104   PetscInt       dof, off, p, c, m;
2105   PetscErrorCode ierr;
2106 
2107   PetscFunctionBegin;
2108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2109   PetscValidPointer(points, 2);
2110   PetscValidPointer(numCoveredPoints, 3);
2111   PetscValidPointer(coveredPoints, 4);
2112   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2113   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2114   /* Copy in support of first point */
2115   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2116   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2117   for (joinSize = 0; joinSize < dof; ++joinSize) {
2118     join[i][joinSize] = mesh->supports[off+joinSize];
2119   }
2120   /* Check each successive support */
2121   for (p = 1; p < numPoints; ++p) {
2122     PetscInt newJoinSize = 0;
2123 
2124     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2125     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2126     for (c = 0; c < dof; ++c) {
2127       const PetscInt point = mesh->supports[off+c];
2128 
2129       for (m = 0; m < joinSize; ++m) {
2130         if (point == join[i][m]) {
2131           join[1-i][newJoinSize++] = point;
2132           break;
2133         }
2134       }
2135     }
2136     joinSize = newJoinSize;
2137     i = 1-i;
2138   }
2139   *numCoveredPoints = joinSize;
2140   *coveredPoints    = join[i];
2141   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2142   PetscFunctionReturn(0);
2143 }
2144 
2145 #undef __FUNCT__
2146 #define __FUNCT__ "DMPlexRestoreJoin"
2147 /*@C
2148   DMPlexRestoreJoin - Restore an array for the join of the set of points
2149 
2150   Not Collective
2151 
2152   Input Parameters:
2153 + dm - The DMPlex object
2154 . numPoints - The number of input points for the join
2155 - points - The input points
2156 
2157   Output Parameters:
2158 + numCoveredPoints - The number of points in the join
2159 - coveredPoints - The points in the join
2160 
2161   Level: intermediate
2162 
2163 .keywords: mesh
2164 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2165 @*/
2166 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2167 {
2168   PetscErrorCode ierr;
2169 
2170   PetscFunctionBegin;
2171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2172   PetscValidPointer(coveredPoints, 4);
2173   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2174   PetscFunctionReturn(0);
2175 }
2176 
2177 #undef __FUNCT__
2178 #define __FUNCT__ "DMPlexGetFullJoin"
2179 /*@C
2180   DMPlexGetFullJoin - Get an array for the join of the set of points
2181 
2182   Not Collective
2183 
2184   Input Parameters:
2185 + dm - The DMPlex object
2186 . numPoints - The number of input points for the join
2187 - points - The input points
2188 
2189   Output Parameters:
2190 + numCoveredPoints - The number of points in the join
2191 - coveredPoints - The points in the join
2192 
2193   Level: intermediate
2194 
2195 .keywords: mesh
2196 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2197 @*/
2198 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2199 {
2200   DM_Plex    *mesh = (DM_Plex *) dm->data;
2201   PetscInt      *offsets, **closures;
2202   PetscInt      *join[2];
2203   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2204   PetscInt       p, d, c, m;
2205   PetscErrorCode ierr;
2206 
2207   PetscFunctionBegin;
2208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2209   PetscValidPointer(points, 2);
2210   PetscValidPointer(numCoveredPoints, 3);
2211   PetscValidPointer(coveredPoints, 4);
2212 
2213   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2214   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2215   ierr = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2216   ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2217   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2218   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2219   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2220 
2221   for (p = 0; p < numPoints; ++p) {
2222     PetscInt closureSize;
2223 
2224     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2225     offsets[p*(depth+2)+0] = 0;
2226     for (d = 0; d < depth+1; ++d) {
2227       PetscInt pStart, pEnd, i;
2228 
2229       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2230       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2231         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2232           offsets[p*(depth+2)+d+1] = i;
2233           break;
2234         }
2235       }
2236       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2237     }
2238     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2239   }
2240   for (d = 0; d < depth+1; ++d) {
2241     PetscInt dof;
2242 
2243     /* Copy in support of first point */
2244     dof = offsets[d+1] - offsets[d];
2245     for (joinSize = 0; joinSize < dof; ++joinSize) {
2246       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2247     }
2248     /* Check each successive cone */
2249     for (p = 1; p < numPoints && joinSize; ++p) {
2250       PetscInt newJoinSize = 0;
2251 
2252       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2253       for (c = 0; c < dof; ++c) {
2254         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2255 
2256         for (m = 0; m < joinSize; ++m) {
2257           if (point == join[i][m]) {
2258             join[1-i][newJoinSize++] = point;
2259             break;
2260           }
2261         }
2262       }
2263       joinSize = newJoinSize;
2264       i = 1-i;
2265     }
2266     if (joinSize) break;
2267   }
2268   *numCoveredPoints = joinSize;
2269   *coveredPoints    = join[i];
2270   for (p = 0; p < numPoints; ++p) {
2271     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2272   }
2273   ierr = PetscFree(closures);CHKERRQ(ierr);
2274   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2275   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2276   PetscFunctionReturn(0);
2277 }
2278 
2279 #undef __FUNCT__
2280 #define __FUNCT__ "DMPlexGetMeet"
2281 /*@C
2282   DMPlexGetMeet - Get an array for the meet of the set of points
2283 
2284   Not Collective
2285 
2286   Input Parameters:
2287 + dm - The DMPlex object
2288 . numPoints - The number of input points for the meet
2289 - points - The input points
2290 
2291   Output Parameters:
2292 + numCoveredPoints - The number of points in the meet
2293 - coveredPoints - The points in the meet
2294 
2295   Level: intermediate
2296 
2297   Note: Currently, this is restricted to a single level meet
2298 
2299 .keywords: mesh
2300 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2301 @*/
2302 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2303 {
2304   DM_Plex    *mesh = (DM_Plex *) dm->data;
2305   PetscInt      *meet[2];
2306   PetscInt       meetSize, i = 0;
2307   PetscInt       dof, off, p, c, m;
2308   PetscErrorCode ierr;
2309 
2310   PetscFunctionBegin;
2311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2312   PetscValidPointer(points, 2);
2313   PetscValidPointer(numCoveringPoints, 3);
2314   PetscValidPointer(coveringPoints, 4);
2315   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2316   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2317   /* Copy in cone of first point */
2318   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2319   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2320   for (meetSize = 0; meetSize < dof; ++meetSize) {
2321     meet[i][meetSize] = mesh->cones[off+meetSize];
2322   }
2323   /* Check each successive cone */
2324   for (p = 1; p < numPoints; ++p) {
2325     PetscInt newMeetSize = 0;
2326 
2327     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2328     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2329     for (c = 0; c < dof; ++c) {
2330       const PetscInt point = mesh->cones[off+c];
2331 
2332       for (m = 0; m < meetSize; ++m) {
2333         if (point == meet[i][m]) {
2334           meet[1-i][newMeetSize++] = point;
2335           break;
2336         }
2337       }
2338     }
2339     meetSize = newMeetSize;
2340     i = 1-i;
2341   }
2342   *numCoveringPoints = meetSize;
2343   *coveringPoints    = meet[i];
2344   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2345   PetscFunctionReturn(0);
2346 }
2347 
2348 #undef __FUNCT__
2349 #define __FUNCT__ "DMPlexRestoreMeet"
2350 /*@C
2351   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2352 
2353   Not Collective
2354 
2355   Input Parameters:
2356 + dm - The DMPlex object
2357 . numPoints - The number of input points for the meet
2358 - points - The input points
2359 
2360   Output Parameters:
2361 + numCoveredPoints - The number of points in the meet
2362 - coveredPoints - The points in the meet
2363 
2364   Level: intermediate
2365 
2366 .keywords: mesh
2367 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2368 @*/
2369 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2370 {
2371   PetscErrorCode ierr;
2372 
2373   PetscFunctionBegin;
2374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2375   PetscValidPointer(coveredPoints, 4);
2376   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2377   PetscFunctionReturn(0);
2378 }
2379 
2380 #undef __FUNCT__
2381 #define __FUNCT__ "DMPlexGetFullMeet"
2382 /*@C
2383   DMPlexGetFullMeet - Get an array for the meet of the set of points
2384 
2385   Not Collective
2386 
2387   Input Parameters:
2388 + dm - The DMPlex object
2389 . numPoints - The number of input points for the meet
2390 - points - The input points
2391 
2392   Output Parameters:
2393 + numCoveredPoints - The number of points in the meet
2394 - coveredPoints - The points in the meet
2395 
2396   Level: intermediate
2397 
2398 .keywords: mesh
2399 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2400 @*/
2401 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2402 {
2403   DM_Plex    *mesh = (DM_Plex *) dm->data;
2404   PetscInt      *offsets, **closures;
2405   PetscInt      *meet[2];
2406   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2407   PetscInt       p, h, c, m;
2408   PetscErrorCode ierr;
2409 
2410   PetscFunctionBegin;
2411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2412   PetscValidPointer(points, 2);
2413   PetscValidPointer(numCoveredPoints, 3);
2414   PetscValidPointer(coveredPoints, 4);
2415 
2416   ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2417   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2418   ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2419   maxSize = PetscPowInt(mesh->maxConeSize,height);
2420   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2421   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2422 
2423   for (p = 0; p < numPoints; ++p) {
2424     PetscInt closureSize;
2425 
2426     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2427     offsets[p*(height+2)+0] = 0;
2428     for (h = 0; h < height+1; ++h) {
2429       PetscInt pStart, pEnd, i;
2430 
2431       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2432       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2433         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2434           offsets[p*(height+2)+h+1] = i;
2435           break;
2436         }
2437       }
2438       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2439     }
2440     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2441   }
2442   for (h = 0; h < height+1; ++h) {
2443     PetscInt dof;
2444 
2445     /* Copy in cone of first point */
2446     dof = offsets[h+1] - offsets[h];
2447     for (meetSize = 0; meetSize < dof; ++meetSize) {
2448       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2449     }
2450     /* Check each successive cone */
2451     for (p = 1; p < numPoints && meetSize; ++p) {
2452       PetscInt newMeetSize = 0;
2453 
2454       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2455       for (c = 0; c < dof; ++c) {
2456         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2457 
2458         for (m = 0; m < meetSize; ++m) {
2459           if (point == meet[i][m]) {
2460             meet[1-i][newMeetSize++] = point;
2461             break;
2462           }
2463         }
2464       }
2465       meetSize = newMeetSize;
2466       i = 1-i;
2467     }
2468     if (meetSize) break;
2469   }
2470   *numCoveredPoints = meetSize;
2471   *coveredPoints    = meet[i];
2472   for (p = 0; p < numPoints; ++p) {
2473     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2474   }
2475   ierr = PetscFree(closures);CHKERRQ(ierr);
2476   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2477   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2478   PetscFunctionReturn(0);
2479 }
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2483 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2484 {
2485   MPI_Comm       comm = ((PetscObject) dm)->comm;
2486   PetscInt       cellDim;
2487   PetscErrorCode ierr;
2488 
2489   PetscFunctionBegin;
2490   PetscValidPointer(numFaceVertices,3);
2491   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2492   switch (cellDim) {
2493   case 0:
2494     *numFaceVertices = 0;
2495     break;
2496   case 1:
2497     *numFaceVertices = 1;
2498     break;
2499   case 2:
2500     switch (numCorners) {
2501     case 3: /* triangle */
2502       *numFaceVertices = 2; /* Edge has 2 vertices */
2503       break;
2504     case 4: /* quadrilateral */
2505       *numFaceVertices = 2; /* Edge has 2 vertices */
2506       break;
2507     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2508       *numFaceVertices = 3; /* Edge has 3 vertices */
2509       break;
2510     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2511       *numFaceVertices = 3; /* Edge has 3 vertices */
2512       break;
2513     default:
2514       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2515     }
2516     break;
2517   case 3:
2518     switch (numCorners) {
2519     case 4: /* tetradehdron */
2520       *numFaceVertices = 3; /* Face has 3 vertices */
2521       break;
2522     case 6: /* tet cohesive cells */
2523       *numFaceVertices = 4; /* Face has 4 vertices */
2524       break;
2525     case 8: /* hexahedron */
2526       *numFaceVertices = 4; /* Face has 4 vertices */
2527       break;
2528     case 9: /* tet cohesive Lagrange cells */
2529       *numFaceVertices = 6; /* Face has 6 vertices */
2530       break;
2531     case 10: /* quadratic tetrahedron */
2532       *numFaceVertices = 6; /* Face has 6 vertices */
2533       break;
2534     case 12: /* hex cohesive Lagrange cells */
2535       *numFaceVertices = 6; /* Face has 6 vertices */
2536       break;
2537     case 18: /* quadratic tet cohesive Lagrange cells */
2538       *numFaceVertices = 6; /* Face has 6 vertices */
2539       break;
2540     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2541       *numFaceVertices = 9; /* Face has 9 vertices */
2542       break;
2543     default:
2544       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2545     }
2546     break;
2547   default:
2548     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2549   }
2550   PetscFunctionReturn(0);
2551 }
2552 
2553 #undef __FUNCT__
2554 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2555 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2556 {
2557   const PetscInt maxFaceCases = 30;
2558   PetscInt       numFaceCases = 0;
2559   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2560   PetscInt      *off, *adj;
2561   PetscInt      *neighborCells, *tmpClosure;
2562   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2563   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2564   PetscErrorCode ierr;
2565 
2566   PetscFunctionBegin;
2567   /* For parallel partitioning, I think you have to communicate supports */
2568   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2569   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2570   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2571   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2572   if (cEnd - cStart == 0) {
2573     if (numVertices) *numVertices = 0;
2574     if (offsets)     *offsets     = PETSC_NULL;
2575     if (adjacency)   *adjacency   = PETSC_NULL;
2576     PetscFunctionReturn(0);
2577   }
2578   numCells = cEnd - cStart;
2579   /* Setup face recognition */
2580   {
2581     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
2582 
2583     for (c = cStart; c < cEnd; ++c) {
2584       PetscInt corners;
2585 
2586       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2587       if (!cornersSeen[corners]) {
2588         PetscInt nFV;
2589 
2590         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2591         cornersSeen[corners] = 1;
2592         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2593         numFaceVertices[numFaceCases++] = nFV;
2594       }
2595     }
2596   }
2597   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2598   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2599   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2600   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2601   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2602   /* Count neighboring cells */
2603   for (cell = cStart; cell < cEnd; ++cell) {
2604     PetscInt numNeighbors = maxNeighbors, n;
2605 
2606     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2607     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2608     for (n = 0; n < numNeighbors; ++n) {
2609       PetscInt        cellPair[2] = {cell, neighborCells[n]};
2610       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2611       PetscInt        meetSize    = 0;
2612       const PetscInt *meet        = PETSC_NULL;
2613 
2614       if (cellPair[0] == cellPair[1]) continue;
2615       if (!found) {
2616         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2617         if (meetSize) {
2618           PetscInt f;
2619 
2620           for (f = 0; f < numFaceCases; ++f) {
2621             if (numFaceVertices[f] == meetSize) {
2622               found = PETSC_TRUE;
2623               break;
2624             }
2625           }
2626         }
2627         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2628       }
2629       if (found) {
2630         ++off[cell-cStart+1];
2631       }
2632     }
2633   }
2634   /* Prefix sum */
2635   for (cell = 1; cell <= numCells; ++cell) {
2636     off[cell] += off[cell-1];
2637   }
2638   if (adjacency) {
2639     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2640     /* Get neighboring cells */
2641     for (cell = cStart; cell < cEnd; ++cell) {
2642       PetscInt numNeighbors = maxNeighbors, n;
2643       PetscInt cellOffset   = 0;
2644 
2645       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2646       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2647       for (n = 0; n < numNeighbors; ++n) {
2648         PetscInt        cellPair[2] = {cell, neighborCells[n]};
2649         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2650         PetscInt        meetSize    = 0;
2651         const PetscInt *meet        = PETSC_NULL;
2652 
2653         if (cellPair[0] == cellPair[1]) continue;
2654         if (!found) {
2655           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2656           if (meetSize) {
2657             PetscInt f;
2658 
2659             for (f = 0; f < numFaceCases; ++f) {
2660               if (numFaceVertices[f] == meetSize) {
2661                 found = PETSC_TRUE;
2662                 break;
2663               }
2664             }
2665           }
2666           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2667         }
2668         if (found) {
2669           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2670           ++cellOffset;
2671         }
2672       }
2673     }
2674   }
2675   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2676   if (numVertices) *numVertices = numCells;
2677   if (offsets)     *offsets     = off;
2678   if (adjacency)   *adjacency   = adj;
2679   PetscFunctionReturn(0);
2680 }
2681 
2682 #if defined(PETSC_HAVE_CHACO)
2683 #if defined(PETSC_HAVE_UNISTD_H)
2684 #include <unistd.h>
2685 #endif
2686 /* Chaco does not have an include file */
2687 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2688                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2689                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2690                        int mesh_dims[3], double *goal, int global_method, int local_method,
2691                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2692 
2693 extern int FREE_GRAPH;
2694 
2695 #undef __FUNCT__
2696 #define __FUNCT__ "DMPlexPartition_Chaco"
2697 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2698 {
2699   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2700   MPI_Comm comm = ((PetscObject) dm)->comm;
2701   int nvtxs = numVertices;                /* number of vertices in full graph */
2702   int *vwgts = NULL;                      /* weights for all vertices */
2703   float *ewgts = NULL;                    /* weights for all edges */
2704   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2705   char *outassignname = NULL;             /*  name of assignment output file */
2706   char *outfilename = NULL;               /* output file name */
2707   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2708   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2709   int mesh_dims[3];                       /* dimensions of mesh of processors */
2710   double *goal = NULL;                    /* desired set sizes for each set */
2711   int global_method = 1;                  /* global partitioning algorithm */
2712   int local_method = 1;                   /* local partitioning algorithm */
2713   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2714   int vmax = 200;                         /* how many vertices to coarsen down to? */
2715   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2716   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2717   long seed = 123636512;                  /* for random graph mutations */
2718   short int *assignment;                  /* Output partition */
2719   int fd_stdout, fd_pipe[2];
2720   PetscInt      *points;
2721   PetscMPIInt    commSize;
2722   int            i, v, p;
2723   PetscErrorCode ierr;
2724 
2725   PetscFunctionBegin;
2726   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2727   if (!numVertices) {
2728     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2729     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2730     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2731     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2732     PetscFunctionReturn(0);
2733   }
2734   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2735   for (i = 0; i < start[numVertices]; ++i) {
2736     ++adjacency[i];
2737   }
2738   if (global_method == INERTIAL_METHOD) {
2739     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2740     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2741   }
2742   mesh_dims[0] = commSize;
2743   mesh_dims[1] = 1;
2744   mesh_dims[2] = 1;
2745   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2746   /* Chaco outputs to stdout. We redirect this to a buffer. */
2747   /* TODO: check error codes for UNIX calls */
2748 #if defined(PETSC_HAVE_UNISTD_H)
2749   {
2750     int piperet;
2751     piperet = pipe(fd_pipe);
2752     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2753     fd_stdout = dup(1);
2754     close(1);
2755     dup2(fd_pipe[1], 1);
2756   }
2757 #endif
2758   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2759                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2760                    vmax, ndims, eigtol, seed);
2761 #if defined(PETSC_HAVE_UNISTD_H)
2762   {
2763     char msgLog[10000];
2764     int  count;
2765 
2766     fflush(stdout);
2767     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2768     if (count < 0) count = 0;
2769     msgLog[count] = 0;
2770     close(1);
2771     dup2(fd_stdout, 1);
2772     close(fd_stdout);
2773     close(fd_pipe[0]);
2774     close(fd_pipe[1]);
2775     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2776   }
2777 #endif
2778   /* Convert to PetscSection+IS */
2779   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2780   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2781   for (v = 0; v < nvtxs; ++v) {
2782     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2783   }
2784   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2785   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2786   for (p = 0, i = 0; p < commSize; ++p) {
2787     for (v = 0; v < nvtxs; ++v) {
2788       if (assignment[v] == p) points[i++] = v;
2789     }
2790   }
2791   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2792   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2793   if (global_method == INERTIAL_METHOD) {
2794     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2795   }
2796   ierr = PetscFree(assignment);CHKERRQ(ierr);
2797   for (i = 0; i < start[numVertices]; ++i) {
2798     --adjacency[i];
2799   }
2800   PetscFunctionReturn(0);
2801 }
2802 #endif
2803 
2804 #if defined(PETSC_HAVE_PARMETIS)
2805 #undef __FUNCT__
2806 #define __FUNCT__ "DMPlexPartition_ParMetis"
2807 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2808 {
2809   PetscFunctionBegin;
2810   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2811   PetscFunctionReturn(0);
2812 }
2813 #endif
2814 
2815 #undef __FUNCT__
2816 #define __FUNCT__ "DMPlexEnlargePartition"
2817 /* Expand the partition by BFS on the adjacency graph */
2818 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2819 {
2820   PetscHashI      h;
2821   const PetscInt *points;
2822   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2823   PetscInt        pStart, pEnd, part, q;
2824   PetscErrorCode  ierr;
2825 
2826   PetscFunctionBegin;
2827   PetscHashICreate(h);
2828   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2829   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2830   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2831   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2832   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2833   for (part = pStart; part < pEnd; ++part) {
2834     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2835 
2836     PetscHashIClear(h);
2837     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2838     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2839     /* Add all existing points to h */
2840     for (p = 0; p < numPoints; ++p) {
2841       const PetscInt point = points[off+p];
2842       PetscHashIAdd(h, point, 1);
2843     }
2844     PetscHashISize(h, nP);
2845     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2846     /* Add all points in next BFS level */
2847     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2848     for (p = 0; p < numPoints; ++p) {
2849       const PetscInt point = points[off+p];
2850       PetscInt s = start[point], e = start[point+1], a;
2851 
2852       for (a = s; a < e; ++a) {
2853         PetscHashIAdd(h, adjacency[a], 1);
2854       }
2855     }
2856     PetscHashISize(h, numNewPoints);
2857     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2858     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2859     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2860     totPoints += numNewPoints;
2861   }
2862   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2863   PetscHashIDestroy(h);
2864   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2865   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2866   for (part = pStart, q = 0; part < pEnd; ++part) {
2867     PetscInt numPoints, p;
2868 
2869     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2870     for (p = 0; p < numPoints; ++p, ++q) {
2871       newPoints[q] = tmpPoints[part][p];
2872     }
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   *origPartSection = PETSC_NULL;
2910   *origPartition   = PETSC_NULL;
2911   if (size == 1) {
2912     PetscInt *points;
2913     PetscInt  cStart, cEnd, c;
2914 
2915     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2916     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2917     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2918     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2919     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2920     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2921     for (c = cStart; c < cEnd; ++c) {
2922       points[c] = c;
2923     }
2924     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2925     PetscFunctionReturn(0);
2926   }
2927   if (height == 0) {
2928     PetscInt  numVertices;
2929     PetscInt *start     = PETSC_NULL;
2930     PetscInt *adjacency = PETSC_NULL;
2931 
2932     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2933     if (1) {
2934 #if defined(PETSC_HAVE_CHACO)
2935       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2936 #endif
2937     } else {
2938 #if defined(PETSC_HAVE_PARMETIS)
2939       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2940 #endif
2941     }
2942     if (enlarge) {
2943       *origPartSection = *partSection;
2944       *origPartition   = *partition;
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         partPoints = tmpPoints;
2998       }
2999       for (c = 0; c < closureSize; ++c) {
3000         partPoints[partSize+c] = closure[c*2];
3001       }
3002       partSize += closureSize;
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) {
3026         partPoints[partSize+c] = closure[c*2];
3027       }
3028       partSize += closureSize;
3029       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3030       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3031     }
3032     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3033     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3034   }
3035   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3036   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3037   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3038   PetscFunctionReturn(0);
3039 }
3040 
3041 #undef __FUNCT__
3042 #define __FUNCT__ "DMPlexDistributeField"
3043 /*
3044   Input Parameters:
3045 . originalSection
3046 , originalVec
3047 
3048   Output Parameters:
3049 . newSection
3050 . newVec
3051 */
3052 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3053 {
3054   PetscSF         fieldSF;
3055   PetscInt       *remoteOffsets, fieldSize;
3056   PetscScalar    *originalValues, *newValues;
3057   PetscErrorCode  ierr;
3058 
3059   PetscFunctionBegin;
3060   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3061 
3062   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3063   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3064   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3065 
3066   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3067   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3068   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3069   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3070   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3071   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3072   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3073   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3074   PetscFunctionReturn(0);
3075 }
3076 
3077 #undef __FUNCT__
3078 #define __FUNCT__ "DMPlexDistribute"
3079 /*@C
3080   DMPlexDistribute - Distributes the mesh and any associated sections.
3081 
3082   Not Collective
3083 
3084   Input Parameter:
3085 + dm  - The original DMPlex object
3086 . partitioner - The partitioning package, or NULL for the default
3087 - overlap - The overlap of partitions, 0 is the default
3088 
3089   Output Parameter:
3090 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3091 
3092   Note: If the mesh was not distributed, the return value is PETSC_NULL
3093 
3094   Level: intermediate
3095 
3096 .keywords: mesh, elements
3097 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3098 @*/
3099 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3100 {
3101   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3102   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3103   const PetscInt height = 0;
3104   PetscInt       dim, numRemoteRanks;
3105   IS             origCellPart,        cellPart,        part;
3106   PetscSection   origCellPartSection, cellPartSection, partSection;
3107   PetscSFNode   *remoteRanks;
3108   PetscSF        partSF, pointSF, coneSF;
3109   ISLocalToGlobalMapping renumbering;
3110   PetscSection   originalConeSection, newConeSection;
3111   PetscInt      *remoteOffsets;
3112   PetscInt      *cones, *newCones, newConesSize;
3113   PetscBool      flg;
3114   PetscMPIInt    rank, numProcs, p;
3115   PetscErrorCode ierr;
3116 
3117   PetscFunctionBegin;
3118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3119   PetscValidPointer(dmParallel,4);
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   *dmParallel = PETSC_NULL;
3124   if (numProcs == 1) PetscFunctionReturn(0);
3125 
3126   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3127   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3128   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3129   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3130   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3131   if (!rank) {
3132     numRemoteRanks = numProcs;
3133   } else {
3134     numRemoteRanks = 0;
3135   }
3136   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3137   for (p = 0; p < numRemoteRanks; ++p) {
3138     remoteRanks[p].rank  = p;
3139     remoteRanks[p].index = 0;
3140   }
3141   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3142   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3143   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3144   if (flg) {
3145     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3146     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3147     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3148     if (origCellPart) {
3149       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3150       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3151       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3152     }
3153     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3154   }
3155   /* Close the partition over the mesh */
3156   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3157   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3158   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3159   /* Create new mesh */
3160   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3161   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3162   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3163   pmesh = (DM_Plex *) (*dmParallel)->data;
3164   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3165   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3166   if (flg) {
3167     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3168     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3169     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3170     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3171     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3172     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3173   }
3174   /* Distribute cone section */
3175   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3176   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3177   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3178   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3179   {
3180     PetscInt pStart, pEnd, p;
3181 
3182     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3183     for (p = pStart; p < pEnd; ++p) {
3184       PetscInt coneSize;
3185       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3186       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3187     }
3188   }
3189   /* Communicate and renumber cones */
3190   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3191   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3192   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3193   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3194   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3195   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3196   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3197   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3198   if (flg) {
3199     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3200     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3201     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3202     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3203     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3204   }
3205   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3206   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3207   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3208   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3209   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3210   /* Create supports and stratify sieve */
3211   {
3212     PetscInt pStart, pEnd;
3213 
3214     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3215     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3216   }
3217   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3218   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3219   /* Distribute Coordinates */
3220   {
3221     PetscSection originalCoordSection, newCoordSection;
3222     Vec          originalCoordinates, newCoordinates;
3223     const char  *name;
3224 
3225     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3226     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3227     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3228     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3229     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3230     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3231 
3232     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3233     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3234     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3235   }
3236   /* Distribute labels */
3237   {
3238     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3239     PetscInt   numLabels = 0, l;
3240 
3241     /* Bcast number of labels */
3242     while (next) {++numLabels; next = next->next;}
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) {
3353         newNext->next = newLabel;
3354       } else {
3355         pmesh->labels = newLabel;
3356       }
3357       newNext = newLabel;
3358       if (!rank) {next = next->next;}
3359     }
3360   }
3361   /* Cleanup Partition */
3362   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3363   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3364   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3365   ierr = ISDestroy(&part);CHKERRQ(ierr);
3366   /* Create point SF for parallel mesh */
3367   {
3368     const PetscInt *leaves;
3369     PetscSFNode    *remotePoints, *rowners, *lowners;
3370     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3371     PetscInt        pStart, pEnd;
3372 
3373     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3374     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3375     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3376     for (p=0; p<numRoots; p++) {
3377       rowners[p].rank = -1;
3378       rowners[p].index = -1;
3379     }
3380     if (origCellPart) {
3381       /* Make sure cells in the original partition are not assigned to other procs */
3382       const PetscInt *origCells;
3383 
3384       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3385       for (p = 0; p < numProcs; ++p) {
3386         PetscInt dof, off, d;
3387 
3388         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3389         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3390         for (d = off; d < off+dof; ++d) {
3391           rowners[origCells[d]].rank = p;
3392         }
3393       }
3394       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3395     }
3396     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3397     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3398 
3399     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3400     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3401     for (p = 0; p < numLeaves; ++p) {
3402       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3403         lowners[p].rank = rank;
3404         lowners[p].index = leaves ? leaves[p] : p;
3405       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3406         lowners[p].rank = -2;
3407         lowners[p].index = -2;
3408       }
3409     }
3410     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3411       rowners[p].rank = -3;
3412       rowners[p].index = -3;
3413     }
3414     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3415     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3416     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3417     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3418     for (p = 0; p < numLeaves; ++p) {
3419       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3420       if (lowners[p].rank != rank) ++numGhostPoints;
3421     }
3422     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3423     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3424     for (p = 0, gp = 0; p < numLeaves; ++p) {
3425       if (lowners[p].rank != rank) {
3426         ghostPoints[gp]       = leaves ? leaves[p] : p;
3427         remotePoints[gp].rank  = lowners[p].rank;
3428         remotePoints[gp].index = lowners[p].index;
3429         ++gp;
3430       }
3431     }
3432     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3433     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3434     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3435   }
3436   /* Cleanup */
3437   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3438   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3439   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3440   PetscFunctionReturn(0);
3441 }
3442 
3443 #undef __FUNCT__
3444 #define __FUNCT__ "DMPlexRenumber_Private"
3445 /*
3446   Reasons to renumber:
3447 
3448   1) Permute points, e.g. bandwidth reduction (Renumber)
3449 
3450     a) Must not mix strata
3451 
3452   2) Shift numbers for point insertion (Shift)
3453 
3454     a) Want operation brken into parts so that insertion can be interleaved
3455 
3456   renumbering - An IS which provides the new numbering
3457 */
3458 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3459 {
3460   PetscFunctionBegin;
3461   PetscFunctionReturn(0);
3462 }
3463 
3464 #undef __FUNCT__
3465 #define __FUNCT__ "DMPlexShiftPoint_Private"
3466 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3467 {
3468   if (depth < 0) return p;
3469   /* Cells    */ if (p < depthEnd[depth])   return p;
3470   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3471   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3472   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3473 }
3474 
3475 #undef __FUNCT__
3476 #define __FUNCT__ "DMPlexShiftSizes_Private"
3477 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3478 {
3479   PetscInt      *depthEnd;
3480   PetscInt       depth = 0, d, pStart, pEnd, p;
3481   PetscErrorCode ierr;
3482 
3483   PetscFunctionBegin;
3484   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3485   if (depth < 0) PetscFunctionReturn(0);
3486   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3487   /* Step 1: Expand chart */
3488   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3489   for (d = 0; d <= depth; ++d) {
3490     pEnd += depthShift[d];
3491     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3492   }
3493   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3494   /* Step 2: Set cone and support sizes */
3495   for (d = 0; d <= depth; ++d) {
3496     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3497     for (p = pStart; p < pEnd; ++p) {
3498       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3499       PetscInt size;
3500 
3501       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3502       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3503       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3504       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3505     }
3506   }
3507   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3508   PetscFunctionReturn(0);
3509 }
3510 
3511 #undef __FUNCT__
3512 #define __FUNCT__ "DMPlexShiftPoints_Private"
3513 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3514 {
3515   PetscInt      *depthEnd, *newpoints;
3516   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3517   PetscErrorCode ierr;
3518 
3519   PetscFunctionBegin;
3520   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3521   if (depth < 0) PetscFunctionReturn(0);
3522   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3523   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3524   for (d = 0; d <= depth; ++d) {
3525     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3526   }
3527   /* Step 5: Set cones and supports */
3528   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3529   for (p = pStart; p < pEnd; ++p) {
3530     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3531     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3532 
3533     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3534     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3535     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3536     for (i = 0; i < size; ++i) {
3537       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3538     }
3539     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3540     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3541     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3542     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3543     for (i = 0; i < size; ++i) {
3544       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3545     }
3546     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3547   }
3548   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3549   PetscFunctionReturn(0);
3550 }
3551 
3552 #undef __FUNCT__
3553 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3554 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3555 {
3556   PetscSection   coordSection, newCoordSection;
3557   Vec            coordinates, newCoordinates;
3558   PetscScalar   *coords, *newCoords;
3559   PetscInt      *depthEnd, coordSize;
3560   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3561   PetscErrorCode ierr;
3562 
3563   PetscFunctionBegin;
3564   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3565   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3566   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3567   for (d = 0; d <= depth; ++d) {
3568     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3569   }
3570   /* Step 8: Convert coordinates */
3571   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3572   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3573   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3574   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3575   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3576   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3577   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3578   for (v = vStartNew; v < vEndNew; ++v) {
3579     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3580     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3581   }
3582   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3583   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3584   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3585   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3586   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3587   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3588   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3589   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3590   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3591   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3592   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3593   for (v = vStart; v < vEnd; ++v) {
3594     PetscInt dof, off, noff, d;
3595 
3596     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3597     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3598     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3599     for (d = 0; d < dof; ++d) {
3600       newCoords[noff+d] = coords[off+d];
3601     }
3602   }
3603   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3604   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3605   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3606   PetscFunctionReturn(0);
3607 }
3608 
3609 #undef __FUNCT__
3610 #define __FUNCT__ "DMPlexShiftSF_Private"
3611 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3612 {
3613   PetscInt          *depthEnd;
3614   PetscInt           depth = 0, d;
3615   PetscSF            sfPoint, sfPointNew;
3616   const PetscSFNode *remotePoints;
3617   PetscSFNode       *gremotePoints;
3618   const PetscInt    *localPoints;
3619   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3620   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3621   PetscMPIInt        numProcs;
3622   PetscErrorCode     ierr;
3623 
3624   PetscFunctionBegin;
3625   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3626   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3627   for (d = 0; d <= depth; ++d) {
3628     totShift += depthShift[d];
3629     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3630   }
3631   /* Step 9: Convert pointSF */
3632   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3633   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3634   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3635   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3636   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3637   if (numRoots >= 0) {
3638     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3639     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3640     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3641     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3642     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3643     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3644     for (l = 0; l < numLeaves; ++l) {
3645       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3646       gremotePoints[l].rank  = remotePoints[l].rank;
3647       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3648     }
3649     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3650     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3651   }
3652   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3653   PetscFunctionReturn(0);
3654 }
3655 
3656 #undef __FUNCT__
3657 #define __FUNCT__ "DMPlexShiftLabels_Private"
3658 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3659 {
3660   PetscSF        sfPoint;
3661   DMLabel        vtkLabel, ghostLabel;
3662   PetscInt      *depthEnd;
3663   const PetscSFNode *leafRemote;
3664   const PetscInt    *leafLocal;
3665   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3666   PetscMPIInt    rank;
3667   PetscErrorCode ierr;
3668 
3669   PetscFunctionBegin;
3670   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3671   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3672   for (d = 0; d <= depth; ++d) {
3673     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3674   }
3675   /* Step 10: Convert labels */
3676   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3677   for (l = 0; l < numLabels; ++l) {
3678     DMLabel         label, newlabel;
3679     const char     *lname;
3680     PetscBool       isDepth;
3681     IS              valueIS;
3682     const PetscInt *values;
3683     PetscInt        numValues, val;
3684 
3685     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3686     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3687     if (isDepth) continue;
3688     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3689     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3690     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3691     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3692     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3693     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3694     for (val = 0; val < numValues; ++val) {
3695       IS              pointIS;
3696       const PetscInt *points;
3697       PetscInt        numPoints, p;
3698 
3699       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3700       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3701       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3702       for (p = 0; p < numPoints; ++p) {
3703         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3704 
3705         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3706       }
3707       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3708       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3709     }
3710     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3711     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3712   }
3713   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3714   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3715   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3716   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3717   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3718   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3719   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3720   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3721   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3722   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3723   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3724     for (; c < leafLocal[l] && c < cEnd; ++c) {
3725       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3726     }
3727     if (leafLocal[l] >= cEnd) break;
3728     if (leafRemote[l].rank == rank) {
3729       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3730     } else {
3731       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3732     }
3733   }
3734   for (; c < cEnd; ++c) {
3735     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3736   }
3737   if (0) {
3738     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3739     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3740     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3741   }
3742   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3743   for (f = fStart; f < fEnd; ++f) {
3744     PetscInt numCells;
3745 
3746     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3747     if (numCells < 2) {
3748       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3749     } else {
3750       const PetscInt *cells = PETSC_NULL;
3751       PetscInt        vA, vB;
3752 
3753       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3754       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3755       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3756       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3757     }
3758   }
3759   if (0) {
3760     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3761     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3762     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3763   }
3764   PetscFunctionReturn(0);
3765 }
3766 
3767 #undef __FUNCT__
3768 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3769 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3770 {
3771   DMLabel         label;
3772   IS              valueIS;
3773   const PetscInt *values;
3774   PetscInt       *depthShift;
3775   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3776   PetscErrorCode  ierr;
3777 
3778   PetscFunctionBegin;
3779   /* Count ghost cells */
3780   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3781   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3782   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3783   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3784   *numGhostCells = 0;
3785   for (fs = 0; fs < numFS; ++fs) {
3786     PetscInt numBdFaces;
3787 
3788     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3789     *numGhostCells += numBdFaces;
3790   }
3791   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3792   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3793   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3794   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3795   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3796   /* Step 3: Set cone/support sizes for new points */
3797   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3798   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3799     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3800   }
3801   for (fs = 0; fs < numFS; ++fs) {
3802     IS              faceIS;
3803     const PetscInt *faces;
3804     PetscInt        numFaces, f;
3805 
3806     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3807     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3808     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3809     for (f = 0; f < numFaces; ++f) {
3810       PetscInt size;
3811 
3812       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3813       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3814       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3815     }
3816     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3817     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3818   }
3819   /* Step 4: Setup ghosted DM */
3820   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3821   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3822   /* Step 6: Set cones and supports for new points */
3823   ghostCell = cEnd;
3824   for (fs = 0; fs < numFS; ++fs) {
3825     IS              faceIS;
3826     const PetscInt *faces;
3827     PetscInt        numFaces, f;
3828 
3829     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3830     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3831     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3832     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3833       PetscInt newFace = faces[f] + *numGhostCells;
3834 
3835       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3836       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3837     }
3838     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3839     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3840   }
3841   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3842   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3843   /* Step 7: Stratify */
3844   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3845   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3846   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3847   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3848   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3849   PetscFunctionReturn(0);
3850 }
3851 
3852 #undef __FUNCT__
3853 #define __FUNCT__ "DMPlexConstructGhostCells"
3854 /*@C
3855   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3856 
3857   Collective on dm
3858 
3859   Input Parameters:
3860 + dm - The original DM
3861 - labelName - The label specifying the boundary faces (this could be auto-generated)
3862 
3863   Output Parameters:
3864 + numGhostCells - The number of ghost cells added to the DM
3865 - dmGhosted - The new DM
3866 
3867   Level: developer
3868 
3869 .seealso: DMCreate()
3870 */
3871 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3872 {
3873   DM             gdm;
3874   PetscInt       dim;
3875   PetscErrorCode ierr;
3876 
3877   PetscFunctionBegin;
3878   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3879   PetscValidPointer(numGhostCells, 3);
3880   PetscValidPointer(dmGhosted, 4);
3881   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3882   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3883   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3884   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3885   switch (dim) {
3886   case 2:
3887     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3888     break;
3889   default:
3890     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3891   }
3892   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3893   *dmGhosted = gdm;
3894   PetscFunctionReturn(0);
3895 }
3896 
3897 #undef __FUNCT__
3898 #define __FUNCT__ "DMPlexConstructCohesiveCells_2D"
3899 PetscErrorCode DMPlexConstructCohesiveCells_2D(DM dm, const char labelName[], DM sdm)
3900 {
3901   MPI_Comm        comm = ((PetscObject) dm)->comm;
3902   DMLabel         label;
3903   IS              valueIS, svIS, seIS;
3904   const PetscInt *values, *splitVertices, *splitEdges;
3905   PetscSection    coordSection;
3906   Vec             coordinates;
3907   PetscScalar    *coords;
3908   PetscInt       *depthShift, *depthOffset, *pMaxNew, *coneNew, *supportNew;
3909   PetscInt        shift = 100, depth = 0, dim, d, numSP, sp, maxConeSize, maxSupportSize, numSplitVertices, v, numSplitEdges, numLabels, l;
3910   PetscErrorCode  ierr;
3911 
3912   PetscFunctionBegin;
3913   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3914   /* Count split points and add cohesive cells */
3915   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3916   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3917   ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3918   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3919   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3920   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3921   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3922   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3923   for(d = 0; d <= dim; ++d) {
3924     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3925   }
3926   for(sp = 0; sp < numSP; ++sp) {
3927     if ((values[sp] < 0) || (values[sp] > depth)) continue;
3928     ierr = DMLabelGetStratumSize(label, values[sp], &depthShift[values[sp]]);CHKERRQ(ierr);
3929   }
3930   depthShift[dim] = depthShift[dim-1]; /* There is a cohesive cell for every split face   */
3931   depthShift[1]  += depthShift[0];     /* There is a cohesive edge for every split vertex */
3932   pMaxNew[0]   += depthShift[dim];
3933   if (dim > 1) {pMaxNew[1]   += depthShift[dim] + depthShift[0];}
3934   if (dim > 2) {pMaxNew[2]   += depthShift[dim] + depthShift[0] + depthShift[1];}
3935   depthOffset[dim] = 0;
3936   depthOffset[0]   = depthOffset[dim] + depthShift[dim];
3937   if (dim > 1) {depthOffset[1]   = depthOffset[0] + depthShift[0];}
3938   if (dim > 2) {depthOffset[2]   = depthOffset[1] + depthShift[1];}
3939   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3940   ierr = DMLabelGetStratumIS(label, 0, &svIS);CHKERRQ(ierr);
3941   ierr = DMLabelGetStratumIS(label, 1, &seIS);CHKERRQ(ierr);
3942   ierr = ISGetLocalSize(svIS, &numSplitVertices);CHKERRQ(ierr);
3943   ierr = ISGetLocalSize(seIS, &numSplitEdges);CHKERRQ(ierr);
3944   ierr = ISGetIndices(svIS, &splitVertices);CHKERRQ(ierr);
3945   ierr = ISGetIndices(seIS, &splitEdges);CHKERRQ(ierr);
3946   /* Step 3: Set cone/support sizes for new points */
3947   for(sp = 0; sp < numSP; ++sp) {
3948     const PetscInt  dep = values[sp];
3949     const PetscInt *points;
3950     IS              dimIS;
3951     PetscInt        numPoints, p;
3952 
3953     if ((values[sp] < 0) || (values[sp] > depth)) continue;
3954     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
3955     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
3956     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
3957     for(p = 0; p < numPoints; ++p) {
3958       const PetscInt *support;
3959       PetscInt        coneSize, supportSize, q, e;
3960 
3961       ierr = DMPlexGetConeSize(dm, points[p], &coneSize);CHKERRQ(ierr);
3962       ierr = DMPlexSetConeSize(sdm, pMaxNew[dep] + p, coneSize);CHKERRQ(ierr);
3963       ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
3964       ierr = DMPlexSetSupportSize(sdm, pMaxNew[dep] + p, supportSize);CHKERRQ(ierr);
3965       if (dep == dim-1) {
3966         /* Add cohesive cells, they are prisms */
3967         ierr = DMPlexSetConeSize(sdm, pMaxNew[dim] + p, 2 + coneSize);CHKERRQ(ierr);
3968       } else if (dep == 0) {
3969         ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
3970         /* Split old vertex: Edges in old split faces and new cohesive edge */
3971         for(e = 0, q = 0; e < supportSize; ++e) {
3972           PetscInt val;
3973 
3974           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3975           if ((val == 1) || (val == (shift + 1))) ++q;
3976         }
3977         ierr = DMPlexSetSupportSize(sdm, depthShift[dim] + points[p], q+1);CHKERRQ(ierr);
3978         /* Split new vertex: Edges in new split faces and new cohesive edge */
3979         for(e = 0, q = 0; e < supportSize; ++e) {
3980           PetscInt val;
3981 
3982           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3983           if ((val == 1) || (val == -(shift + 1))) ++q;
3984         }
3985         ierr = DMPlexSetSupportSize(sdm, pMaxNew[dep] + p, q+1);CHKERRQ(ierr);
3986         /* Add cohesive edges */
3987         ierr = DMPlexSetConeSize(sdm, pMaxNew[1] + (depthShift[1] - depthShift[0]) + p, 2);CHKERRQ(ierr);
3988         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3989       }
3990     }
3991     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
3992     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
3993   }
3994   /* Step 4: Setup ghosted DM */
3995   ierr = DMSetUp(sdm);CHKERRQ(ierr);
3996   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3997   /* Step 6: Set cones and supports for new points */
3998   for(sp = 0; sp < numSP; ++sp) {
3999     const PetscInt  dep = values[sp];
4000     const PetscInt *points;
4001     IS              dimIS;
4002     PetscInt        numPoints, p;
4003 
4004     if ((values[sp] < 0) || (values[sp] > depth)) continue;
4005     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
4006     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4007     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4008     for(p = 0; p < numPoints; ++p) {
4009       const PetscInt *cone, *support;
4010       PetscInt        coneSize, supportSize, q, v, e, s;
4011 
4012       ierr = DMPlexGetConeSize(dm, points[p], &coneSize);CHKERRQ(ierr);
4013       ierr = DMPlexGetCone(dm, points[p], &cone);CHKERRQ(ierr);
4014       ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4015       ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4016       if (dep == dim-1) {
4017         const PetscInt  newp   = depthOffset[dep] + points[p];
4018         const PetscInt  splitp = pMaxNew[dep] + p;
4019         const PetscInt  ccell  = pMaxNew[dim] + p;
4020         const PetscInt *supportF;
4021 
4022         /* Split face:       copy in old face to new face to start */
4023         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4024         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4025         /* Split old face:   old vertices in cone so no change */
4026         /* Split new face:   new vertices in cone */
4027         for(q = 0; q < coneSize; ++q) {
4028           ierr = PetscFindInt(cone[q], numSplitVertices, splitVertices, &v);CHKERRQ(ierr);
4029           coneNew[2+q] = pMaxNew[0] + v;
4030         }
4031         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4032         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4033         coneNew[0] = newp;
4034         coneNew[1] = splitp;
4035         for(q = 0; q < coneSize; ++q) {
4036           coneNew[2+q] = (pMaxNew[1] - pMaxNew[0]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4037         }
4038         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4039         for(s = 0; s < supportSize; ++s) {
4040           PetscInt val;
4041 
4042           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4043           if (val < 0) {
4044             const PetscInt *scone;
4045             PetscInt        sconeSize, sc;
4046 
4047             /* Split old face:   Replace negative side cell with cohesive cell */
4048             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4049             /* Negative cell: replace split face */
4050             ierr = DMPlexGetConeSize(sdm, support[s], &sconeSize);CHKERRQ(ierr);
4051             ierr = DMPlexGetCone(sdm, support[s], &scone);CHKERRQ(ierr);
4052             for(sc = 0; sc < sconeSize; ++sc) {
4053               if (scone[sc] == newp) {
4054                 ierr = DMPlexInsertCone(sdm, support[s], sc, splitp);CHKERRQ(ierr);
4055                 break;
4056               }
4057             }
4058           } else {
4059             /* Split new face:   Replace positive side cell with cohesive cell */
4060             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4061           }
4062         }
4063       } else if (dep == 0) {
4064         const PetscInt newp   = depthOffset[dep] + points[p];
4065         const PetscInt splitp = pMaxNew[dep] + p;
4066         const PetscInt cedge  = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4067 
4068         /* Split old vertex: Edges in old split faces and new cohesive edge */
4069         for(e = 0, q = 0; e < supportSize; ++e) {
4070           PetscInt val;
4071 
4072           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4073           if ((val == 1) || (val == (shift + 1))) {
4074             supportNew[q++] = depthOffset[1] + support[e];
4075           }
4076         }
4077         supportNew[q] = cedge;
4078         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4079         /* Split new vertex: Edges in new split faces and new cohesive edge */
4080         for(e = 0, q = 0; e < supportSize; ++e) {
4081           PetscInt val, edge;
4082 
4083           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4084           if (val == 1) {
4085             ierr = PetscFindInt(support[e], numSplitEdges, splitEdges, &edge);CHKERRQ(ierr);
4086             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4087             supportNew[q++] = pMaxNew[1] + edge;
4088           } else if (val == -(shift + 1)) {
4089             const PetscInt *scone;
4090             PetscInt        sconeSize, sc;
4091 
4092             supportNew[q++] = depthOffset[1] + support[e];
4093             /* Negative edge: replace split vertex */
4094             ierr = DMPlexGetConeSize(sdm, depthOffset[1] + support[e], &sconeSize);CHKERRQ(ierr);
4095             ierr = DMPlexGetCone(sdm, depthOffset[1] + support[e], &scone);CHKERRQ(ierr);
4096             for(sc = 0; sc < sconeSize; ++sc) {
4097               if (scone[sc] == newp) {
4098                 ierr = DMPlexInsertCone(sdm, depthOffset[1] + support[e], sc, splitp);CHKERRQ(ierr);
4099                 break;
4100               }
4101             }
4102             if (sc == sconeSize) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Edge %d does not contain split vertex %d", support[e], newp);
4103           }
4104         }
4105         supportNew[q] = cedge;
4106         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4107         /* Cohesive edge:    Old and new split vertex, punting on support */
4108         coneNew[0] = newp;
4109         coneNew[1] = splitp;
4110         ierr = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4111       }
4112     }
4113     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4114     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4115   }
4116   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4117   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4118   /* Step 7: Stratify */
4119   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4120   /* Step 8: Coordinates */
4121   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4122   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4123   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4124   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4125   for(v = 0; v < numSplitVertices; ++v) {
4126     const PetscInt newp   = depthOffset[0] + splitVertices[v];
4127     const PetscInt splitp = pMaxNew[0] + v;
4128     PetscInt       dof, off, soff, d;
4129 
4130     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4131     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4132     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4133     for(d = 0; d < dof; ++d) {
4134       coords[soff+d] = coords[off+d];
4135     }
4136   }
4137   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4138   /* TODO Put new edges and faces in SF */
4139   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4140   /* Step 10: Labels */
4141   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4142   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4143   for(sp = 0; sp < numSP; ++sp) {
4144     const PetscInt  dep = values[sp];
4145     const PetscInt *points;
4146     IS              dimIS;
4147     PetscInt        numPoints, p;
4148 
4149     if ((values[sp] < 0) || (values[sp] > depth)) continue;
4150     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
4151     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4152     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4153     for(p = 0; p < numPoints; ++p) {
4154       const PetscInt newp   = depthOffset[dep] + points[p];
4155       const PetscInt splitp = pMaxNew[dep] + p;
4156 
4157       for (l = 0; l < numLabels; ++l) {
4158         DMLabel     label;
4159         const char *lname;
4160         PetscInt    val;
4161 
4162         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4163         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4164         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4165         if (val >= 0) {
4166           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4167           if (dep == 0) {
4168             const PetscInt cedge  = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4169             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4170           }
4171         }
4172       }
4173     }
4174     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4175     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4176   }
4177   ierr = ISRestoreIndices(svIS, &splitVertices);CHKERRQ(ierr);
4178   ierr = ISRestoreIndices(seIS, &splitEdges);CHKERRQ(ierr);
4179   ierr = ISDestroy(&svIS);CHKERRQ(ierr);
4180   ierr = ISDestroy(&seIS);CHKERRQ(ierr);
4181   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4182   PetscFunctionReturn(0);
4183 }
4184 
4185 #undef __FUNCT__
4186 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4187 /*@C
4188   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4189 
4190   Collective on dm
4191 
4192   Input Parameters:
4193 + dm - The original DM
4194 - labelName - The label specifying the boundary faces (this could be auto-generated)
4195 
4196   Output Parameters:
4197 - dmSplit - The new DM
4198 
4199   Level: developer
4200 
4201 .seealso: DMCreate()
4202 */
4203 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4204 {
4205   DM             sdm;
4206   PetscInt       dim;
4207   PetscErrorCode ierr;
4208 
4209   PetscFunctionBegin;
4210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4211   PetscValidPointer(dmSplit, 4);
4212   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4213   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4214   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4215   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4216   switch(dim) {
4217   case 2:
4218     ierr = DMPlexConstructCohesiveCells_2D(dm, labelName, sdm);CHKERRQ(ierr);
4219     break;
4220   default:
4221     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4222   }
4223   *dmSplit = sdm;
4224   PetscFunctionReturn(0);
4225 }
4226 
4227 #undef __FUNCT__
4228 #define __FUNCT__ "DMLabelCohesiveComplete"
4229 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4230 {
4231   IS              dimIS;
4232   const PetscInt *points;
4233   PetscInt        shift = 100, dim, numPoints, p;
4234   PetscErrorCode  ierr;
4235 
4236   PetscFunctionBegin;
4237   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4238   /* Cell orientation for face gives the side of the fault */
4239   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4240   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4241   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4242   for(p = 0; p < numPoints; ++p) {
4243     const PetscInt *support;
4244     PetscInt        supportSize, s;
4245 
4246     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4247     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4248     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4249     for(s = 0; s < supportSize; ++s) {
4250       const PetscInt *cone, *ornt;
4251       PetscInt        coneSize, c;
4252       PetscBool       pos = PETSC_TRUE;
4253 
4254       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4255       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4256       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4257       for(c = 0; c < coneSize; ++c) {
4258         if (cone[c] == points[p]) {
4259           if (ornt[c] >= 0) {
4260             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4261           } else {
4262             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4263             pos  = PETSC_FALSE;
4264           }
4265           break;
4266         }
4267       }
4268       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]);
4269       for(c = 0; c < coneSize; ++c) {
4270         if (cone[c] != points[p]) {
4271           if (pos) {
4272             ierr = DMLabelSetValue(label, cone[c],   shift+dim-1);CHKERRQ(ierr);
4273           } else {
4274             ierr = DMLabelSetValue(label, cone[c], -(shift+dim-1));CHKERRQ(ierr);
4275             pos  = PETSC_FALSE;
4276           }
4277         }
4278       }
4279     }
4280   }
4281   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4282   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4283   /* Search for other cells/faces/edges connected to the fault */
4284   PetscFunctionReturn(0);
4285 }
4286 
4287 #undef __FUNCT__
4288 #define __FUNCT__ "DMPlexInterpolate_2D"
4289 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4290 {
4291   DM             idm;
4292   DM_Plex       *mesh;
4293   PetscHashIJ    edgeTable;
4294   PetscInt      *off;
4295   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4296   PetscInt       numEdges, firstEdge, edge, e;
4297   PetscErrorCode ierr;
4298 
4299   PetscFunctionBegin;
4300   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4301   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4302   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4303   numCells    = cEnd - cStart;
4304   numVertices = vEnd - vStart;
4305   firstEdge   = numCells + numVertices;
4306   numEdges    = 0 ;
4307   /* Count edges using algorithm from CreateNeighborCSR */
4308   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4309   if (off) {
4310     PetscInt numCorners = 0;
4311 
4312     numEdges = off[numCells]/2;
4313 #if 0
4314     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4315     numEdges += 3*numCells - off[numCells];
4316 #else
4317     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4318     for (c = cStart; c < cEnd; ++c) {
4319       PetscInt coneSize;
4320 
4321       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4322       numCorners += coneSize;
4323     }
4324     numEdges += numCorners - off[numCells];
4325 #endif
4326   }
4327 #if 0
4328   /* Check Euler characteristic V - E + F = 1 */
4329   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4330 #endif
4331   /* Create interpolated mesh */
4332   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4333   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4334   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4335   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4336   for (c = 0; c < numCells; ++c) {
4337     PetscInt numCorners;
4338 
4339     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4340     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4341   }
4342   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4343     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4344   }
4345   ierr = DMSetUp(idm);CHKERRQ(ierr);
4346   /* Get edge cones from subsets of cell vertices */
4347   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4348   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4349 
4350   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4351     const PetscInt *cellFaces;
4352     PetscInt        numCellFaces, faceSize, cf;
4353 
4354     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4355     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4356     for (cf = 0; cf < numCellFaces; ++cf) {
4357 #if 1
4358       PetscHashIJKey key = {PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]),
4359                             PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1])};
4360 
4361       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4362       if (e < 0) {
4363         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4364         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4365         e    = edge++;
4366       }
4367 #else
4368       PetscBool found = PETSC_FALSE;
4369 
4370       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4371       for (e = firstEdge; e < edge; ++e) {
4372         const PetscInt *cone;
4373 
4374         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4375         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4376             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4377           found = PETSC_TRUE;
4378           break;
4379         }
4380       }
4381       if (!found) {
4382         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4383         ++edge;
4384       }
4385 #endif
4386       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4387     }
4388   }
4389   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4390   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4391   ierr = PetscFree(off);CHKERRQ(ierr);
4392   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4393   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4394   mesh = (DM_Plex *) (idm)->data;
4395   /* Orient edges */
4396   for (c = 0; c < numCells; ++c) {
4397     const PetscInt *cone = PETSC_NULL, *cellFaces;
4398     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4399 
4400     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4401     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4402     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4403     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4404     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4405     for (cf = 0; cf < numCellFaces; ++cf) {
4406       const PetscInt *econe = PETSC_NULL;
4407       PetscInt        esize;
4408 
4409       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4410       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4411       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]);
4412       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4413         /* Correctly oriented */
4414         mesh->coneOrientations[coff+cf] = 0;
4415       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4416         /* Start at index 1, and reverse orientation */
4417         mesh->coneOrientations[coff+cf] = -(1+1);
4418       }
4419     }
4420   }
4421   *dmInt  = idm;
4422   PetscFunctionReturn(0);
4423 }
4424 
4425 #undef __FUNCT__
4426 #define __FUNCT__ "DMPlexInterpolate_3D"
4427 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4428 {
4429   DM             idm, fdm;
4430   DM_Plex    *mesh;
4431   PetscInt      *off;
4432   const PetscInt numCorners = 4;
4433   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4434   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4435   PetscErrorCode ierr;
4436 
4437   PetscFunctionBegin;
4438   {
4439     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4440     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4441     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4442   }
4443   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4444   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4445   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4446   numCells    = cEnd - cStart;
4447   numVertices = vEnd - vStart;
4448   firstFace   = numCells + numVertices;
4449   numFaces    = 0 ;
4450   /* Count faces using algorithm from CreateNeighborCSR */
4451   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4452   if (off) {
4453     numFaces = off[numCells]/2;
4454     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4455     numFaces += 4*numCells - off[numCells];
4456   }
4457   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4458   firstEdge = firstFace + numFaces;
4459   numEdges  = numVertices + numFaces - numCells - 1;
4460   /* Create interpolated mesh */
4461   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4462   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4463   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4464   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4465   for (c = 0; c < numCells; ++c) {
4466     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4467   }
4468   for (f = firstFace; f < firstFace+numFaces; ++f) {
4469     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4470   }
4471   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4472     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4473   }
4474   ierr = DMSetUp(idm);CHKERRQ(ierr);
4475   /* Get face cones from subsets of cell vertices */
4476   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4477   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4478   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4479   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4480   for (f = firstFace; f < firstFace+numFaces; ++f) {
4481     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4482   }
4483   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4484   for (c = 0, face = firstFace; c < numCells; ++c) {
4485     const PetscInt *cellFaces;
4486     PetscInt        numCellFaces, faceSize, cf;
4487 
4488     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4489     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4490     for (cf = 0; cf < numCellFaces; ++cf) {
4491       PetscBool found = PETSC_FALSE;
4492 
4493       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4494       for (f = firstFace; f < face; ++f) {
4495         const PetscInt *cone = PETSC_NULL;
4496 
4497         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4498         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4499             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4500             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4501             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4502             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4503             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4504           found = PETSC_TRUE;
4505           break;
4506         }
4507       }
4508       if (!found) {
4509         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4510         /* Save the vertices for orientation calculation */
4511         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4512         ++face;
4513       }
4514       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4515     }
4516   }
4517   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4518   /* Get edge cones from subsets of face vertices */
4519   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4520     const PetscInt *cellFaces;
4521     PetscInt        numCellFaces, faceSize, cf;
4522 
4523     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4524     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4525     for (cf = 0; cf < numCellFaces; ++cf) {
4526       PetscBool found = PETSC_FALSE;
4527 
4528       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4529       for (e = firstEdge; e < edge; ++e) {
4530         const PetscInt *cone = PETSC_NULL;
4531 
4532         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4533         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4534             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4535           found = PETSC_TRUE;
4536           break;
4537         }
4538       }
4539       if (!found) {
4540         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4541         ++edge;
4542       }
4543       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4544     }
4545   }
4546   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4547   ierr = PetscFree(off);CHKERRQ(ierr);
4548   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4549   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4550   mesh = (DM_Plex *) (idm)->data;
4551   /* Orient edges */
4552   for (f = firstFace; f < firstFace+numFaces; ++f) {
4553     const PetscInt *cone, *cellFaces;
4554     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4555 
4556     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4557     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4558     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4559     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4560     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4561     for (cf = 0; cf < numCellFaces; ++cf) {
4562       const PetscInt *econe;
4563       PetscInt        esize;
4564 
4565       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4566       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4567       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]);
4568       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4569         /* Correctly oriented */
4570         mesh->coneOrientations[coff+cf] = 0;
4571       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4572         /* Start at index 1, and reverse orientation */
4573         mesh->coneOrientations[coff+cf] = -(1+1);
4574       }
4575     }
4576   }
4577   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4578   /* Orient faces */
4579   for (c = 0; c < numCells; ++c) {
4580     const PetscInt *cone, *cellFaces;
4581     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4582 
4583     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4584     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4585     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4586     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4587     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4588     for (cf = 0; cf < numCellFaces; ++cf) {
4589       PetscInt *origClosure = PETSC_NULL, *closure;
4590       PetscInt  closureSize, i;
4591 
4592       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4593       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4594       for (i = 4; i < 7; ++i) {
4595         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);
4596       }
4597       closure = &origClosure[4*2];
4598       /* Remember that this is the orientation for edges, not vertices */
4599       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4600         /* Correctly oriented */
4601         mesh->coneOrientations[coff+cf] = 0;
4602       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4603         /* Shifted by 1 */
4604         mesh->coneOrientations[coff+cf] = 1;
4605       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4606         /* Shifted by 2 */
4607         mesh->coneOrientations[coff+cf] = 2;
4608       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4609         /* Start at edge 1, and reverse orientation */
4610         mesh->coneOrientations[coff+cf] = -(1+1);
4611       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4612         /* Start at index 0, and reverse orientation */
4613         mesh->coneOrientations[coff+cf] = -(0+1);
4614       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4615         /* Start at index 2, and reverse orientation */
4616         mesh->coneOrientations[coff+cf] = -(2+1);
4617       } 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);
4618       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4619     }
4620   }
4621   {
4622     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4623     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4624     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4625   }
4626   *dmInt  = idm;
4627   PetscFunctionReturn(0);
4628 }
4629 
4630 #undef __FUNCT__
4631 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4632 /*
4633   This takes as input the common mesh generator output, a list of the vertices for each cell
4634 */
4635 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4636 {
4637   PetscInt      *cone, c, p;
4638   PetscErrorCode ierr;
4639 
4640   PetscFunctionBegin;
4641   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4642   for (c = 0; c < numCells; ++c) {
4643     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4644   }
4645   ierr = DMSetUp(dm);CHKERRQ(ierr);
4646   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4647   for (c = 0; c < numCells; ++c) {
4648     for (p = 0; p < numCorners; ++p) {
4649       cone[p] = cells[c*numCorners+p]+numCells;
4650     }
4651     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4652   }
4653   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4654   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4655   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4656   PetscFunctionReturn(0);
4657 }
4658 
4659 #undef __FUNCT__
4660 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4661 /*
4662   This takes as input the coordinates for each vertex
4663 */
4664 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4665 {
4666   PetscSection   coordSection;
4667   Vec            coordinates;
4668   PetscScalar   *coords;
4669   PetscInt       coordSize, v, d;
4670   PetscErrorCode ierr;
4671 
4672   PetscFunctionBegin;
4673   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4674   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4675   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4676   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4677   for (v = numCells; v < numCells+numVertices; ++v) {
4678     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4679     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4680   }
4681   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4682   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4683   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4684   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4685   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4686   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4687   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4688   for (v = 0; v < numVertices; ++v) {
4689     for (d = 0; d < spaceDim; ++d) {
4690       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4691     }
4692   }
4693   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4694   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4695   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4696   PetscFunctionReturn(0);
4697 }
4698 
4699 #undef __FUNCT__
4700 #define __FUNCT__ "DMPlexCreateFromCellList"
4701 /*
4702   This takes as input the common mesh generator output, a list of the vertices for each cell
4703 */
4704 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4705 {
4706   PetscErrorCode ierr;
4707 
4708   PetscFunctionBegin;
4709   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4710   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4711   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4712   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4713   if (interpolate) {
4714     DM idm;
4715 
4716     switch (dim) {
4717     case 2:
4718       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4719     case 3:
4720       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4721     default:
4722       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4723     }
4724     ierr = DMDestroy(dm);CHKERRQ(ierr);
4725     *dm  = idm;
4726   }
4727   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4728   PetscFunctionReturn(0);
4729 }
4730 
4731 #if defined(PETSC_HAVE_TRIANGLE)
4732 #include <triangle.h>
4733 
4734 #undef __FUNCT__
4735 #define __FUNCT__ "InitInput_Triangle"
4736 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4737 {
4738   PetscFunctionBegin;
4739   inputCtx->numberofpoints = 0;
4740   inputCtx->numberofpointattributes = 0;
4741   inputCtx->pointlist = PETSC_NULL;
4742   inputCtx->pointattributelist = PETSC_NULL;
4743   inputCtx->pointmarkerlist = PETSC_NULL;
4744   inputCtx->numberofsegments = 0;
4745   inputCtx->segmentlist = PETSC_NULL;
4746   inputCtx->segmentmarkerlist = PETSC_NULL;
4747   inputCtx->numberoftriangleattributes = 0;
4748   inputCtx->trianglelist = PETSC_NULL;
4749   inputCtx->numberofholes = 0;
4750   inputCtx->holelist = PETSC_NULL;
4751   inputCtx->numberofregions = 0;
4752   inputCtx->regionlist = PETSC_NULL;
4753   PetscFunctionReturn(0);
4754 }
4755 
4756 #undef __FUNCT__
4757 #define __FUNCT__ "InitOutput_Triangle"
4758 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4759 {
4760   PetscFunctionBegin;
4761   outputCtx->numberofpoints = 0;
4762   outputCtx->pointlist = PETSC_NULL;
4763   outputCtx->pointattributelist = PETSC_NULL;
4764   outputCtx->pointmarkerlist = PETSC_NULL;
4765   outputCtx->numberoftriangles = 0;
4766   outputCtx->trianglelist = PETSC_NULL;
4767   outputCtx->triangleattributelist = PETSC_NULL;
4768   outputCtx->neighborlist = PETSC_NULL;
4769   outputCtx->segmentlist = PETSC_NULL;
4770   outputCtx->segmentmarkerlist = PETSC_NULL;
4771   outputCtx->numberofedges = 0;
4772   outputCtx->edgelist = PETSC_NULL;
4773   outputCtx->edgemarkerlist = PETSC_NULL;
4774   PetscFunctionReturn(0);
4775 }
4776 
4777 #undef __FUNCT__
4778 #define __FUNCT__ "FiniOutput_Triangle"
4779 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4780 {
4781   PetscFunctionBegin;
4782   free(outputCtx->pointmarkerlist);
4783   free(outputCtx->edgelist);
4784   free(outputCtx->edgemarkerlist);
4785   free(outputCtx->trianglelist);
4786   free(outputCtx->neighborlist);
4787   PetscFunctionReturn(0);
4788 }
4789 
4790 #undef __FUNCT__
4791 #define __FUNCT__ "DMPlexGenerate_Triangle"
4792 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4793 {
4794   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4795   PetscInt             dim              = 2;
4796   const PetscBool      createConvexHull = PETSC_FALSE;
4797   const PetscBool      constrained      = PETSC_FALSE;
4798   struct triangulateio in;
4799   struct triangulateio out;
4800   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4801   PetscMPIInt          rank;
4802   PetscErrorCode       ierr;
4803 
4804   PetscFunctionBegin;
4805   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4806   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4807   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4808   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4809   in.numberofpoints = vEnd - vStart;
4810   if (in.numberofpoints > 0) {
4811     PetscSection coordSection;
4812     Vec          coordinates;
4813     PetscScalar *array;
4814 
4815     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4816     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4817     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4818     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4819     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4820     for (v = vStart; v < vEnd; ++v) {
4821       const PetscInt idx = v - vStart;
4822       PetscInt       off, d;
4823 
4824       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4825       for (d = 0; d < dim; ++d) {
4826         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4827       }
4828       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4829     }
4830     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4831   }
4832   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4833   in.numberofsegments = eEnd - eStart;
4834   if (in.numberofsegments > 0) {
4835     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4836     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4837     for (e = eStart; e < eEnd; ++e) {
4838       const PetscInt  idx = e - eStart;
4839       const PetscInt *cone;
4840 
4841       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4842       in.segmentlist[idx*2+0] = cone[0] - vStart;
4843       in.segmentlist[idx*2+1] = cone[1] - vStart;
4844       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4845     }
4846   }
4847 #if 0 /* Do not currently support holes */
4848   PetscReal *holeCoords;
4849   PetscInt   h, d;
4850 
4851   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4852   if (in.numberofholes > 0) {
4853     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4854     for (h = 0; h < in.numberofholes; ++h) {
4855       for (d = 0; d < dim; ++d) {
4856         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4857       }
4858     }
4859   }
4860 #endif
4861   if (!rank) {
4862     char args[32];
4863 
4864     /* Take away 'Q' for verbose output */
4865     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4866     if (createConvexHull) {
4867       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4868     }
4869     if (constrained) {
4870       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4871     }
4872     triangulate(args, &in, &out, PETSC_NULL);
4873   }
4874   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4875   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4876   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4877   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4878   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4879 
4880   {
4881     const PetscInt numCorners  = 3;
4882     const PetscInt numCells    = out.numberoftriangles;
4883     const PetscInt numVertices = out.numberofpoints;
4884     const int     *cells       = out.trianglelist;
4885     const double  *meshCoords  = out.pointlist;
4886 
4887     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4888     /* Set labels */
4889     for (v = 0; v < numVertices; ++v) {
4890       if (out.pointmarkerlist[v]) {
4891         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4892       }
4893     }
4894     if (interpolate) {
4895       for (e = 0; e < out.numberofedges; e++) {
4896         if (out.edgemarkerlist[e]) {
4897           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4898           const PetscInt *edges;
4899           PetscInt        numEdges;
4900 
4901           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4902           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4903           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4904           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4905         }
4906       }
4907     }
4908     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4909   }
4910 #if 0 /* Do not currently support holes */
4911   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4912 #endif
4913   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4914   PetscFunctionReturn(0);
4915 }
4916 
4917 #undef __FUNCT__
4918 #define __FUNCT__ "DMPlexRefine_Triangle"
4919 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4920 {
4921   MPI_Comm             comm = ((PetscObject) dm)->comm;
4922   PetscInt             dim  = 2;
4923   struct triangulateio in;
4924   struct triangulateio out;
4925   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4926   PetscMPIInt          rank;
4927   PetscErrorCode       ierr;
4928 
4929   PetscFunctionBegin;
4930   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4931   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4932   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4933   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4934   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4935   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4936   in.numberofpoints = vEnd - vStart;
4937   if (in.numberofpoints > 0) {
4938     PetscSection coordSection;
4939     Vec          coordinates;
4940     PetscScalar *array;
4941 
4942     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4943     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4944     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4945     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4946     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4947     for (v = vStart; v < vEnd; ++v) {
4948       const PetscInt idx = v - vStart;
4949       PetscInt       off, d;
4950 
4951       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4952       for (d = 0; d < dim; ++d) {
4953         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4954       }
4955       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4956     }
4957     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4958   }
4959   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4960   in.numberofcorners   = 3;
4961   in.numberoftriangles = cEnd - cStart;
4962   in.trianglearealist  = (double *) maxVolumes;
4963   if (in.numberoftriangles > 0) {
4964     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4965     for (c = cStart; c < cEnd; ++c) {
4966       const PetscInt idx     = c - cStart;
4967       PetscInt      *closure = PETSC_NULL;
4968       PetscInt       closureSize;
4969 
4970       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4971       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4972       for (v = 0; v < 3; ++v) {
4973         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4974       }
4975       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4976     }
4977   }
4978   /* TODO: Segment markers are missing on input */
4979 #if 0 /* Do not currently support holes */
4980   PetscReal *holeCoords;
4981   PetscInt   h, d;
4982 
4983   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4984   if (in.numberofholes > 0) {
4985     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4986     for (h = 0; h < in.numberofholes; ++h) {
4987       for (d = 0; d < dim; ++d) {
4988         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4989       }
4990     }
4991   }
4992 #endif
4993   if (!rank) {
4994     char args[32];
4995 
4996     /* Take away 'Q' for verbose output */
4997     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4998     triangulate(args, &in, &out, PETSC_NULL);
4999   }
5000   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5001   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5002   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5003   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5004   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5005 
5006   {
5007     const PetscInt numCorners  = 3;
5008     const PetscInt numCells    = out.numberoftriangles;
5009     const PetscInt numVertices = out.numberofpoints;
5010     const int     *cells       = out.trianglelist;
5011     const double  *meshCoords  = out.pointlist;
5012     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5013 
5014     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5015     /* Set labels */
5016     for (v = 0; v < numVertices; ++v) {
5017       if (out.pointmarkerlist[v]) {
5018         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5019       }
5020     }
5021     if (interpolate) {
5022       PetscInt e;
5023 
5024       for (e = 0; e < out.numberofedges; e++) {
5025         if (out.edgemarkerlist[e]) {
5026           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5027           const PetscInt *edges;
5028           PetscInt        numEdges;
5029 
5030           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5031           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5032           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5033           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5034         }
5035       }
5036     }
5037     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5038   }
5039 #if 0 /* Do not currently support holes */
5040   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5041 #endif
5042   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5043   PetscFunctionReturn(0);
5044 }
5045 #endif
5046 
5047 #if defined(PETSC_HAVE_TETGEN)
5048 #include <tetgen.h>
5049 #undef __FUNCT__
5050 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5051 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5052 {
5053   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5054   const PetscInt dim  = 3;
5055   ::tetgenio     in;
5056   ::tetgenio     out;
5057   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5058   PetscMPIInt    rank;
5059   PetscErrorCode ierr;
5060 
5061   PetscFunctionBegin;
5062   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5063   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5064   in.numberofpoints = vEnd - vStart;
5065   if (in.numberofpoints > 0) {
5066     PetscSection coordSection;
5067     Vec          coordinates;
5068     PetscScalar *array;
5069 
5070     in.pointlist       = new double[in.numberofpoints*dim];
5071     in.pointmarkerlist = new int[in.numberofpoints];
5072     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5073     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5074     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5075     for (v = vStart; v < vEnd; ++v) {
5076       const PetscInt idx = v - vStart;
5077       PetscInt       off, d;
5078 
5079       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5080       for (d = 0; d < dim; ++d) {
5081         in.pointlist[idx*dim + d] = array[off+d];
5082       }
5083       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5084     }
5085     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5086   }
5087   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5088   in.numberoffacets = fEnd - fStart;
5089   if (in.numberoffacets > 0) {
5090     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5091     in.facetmarkerlist = new int[in.numberoffacets];
5092     for (f = fStart; f < fEnd; ++f) {
5093       const PetscInt idx    = f - fStart;
5094       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5095 
5096       in.facetlist[idx].numberofpolygons = 1;
5097       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5098       in.facetlist[idx].numberofholes    = 0;
5099       in.facetlist[idx].holelist         = NULL;
5100 
5101       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5102       for (p = 0; p < numPoints*2; p += 2) {
5103         const PetscInt point = points[p];
5104         if ((point >= vStart) && (point < vEnd)) {
5105           points[numVertices++] = point;
5106         }
5107       }
5108 
5109       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5110       poly->numberofvertices = numVertices;
5111       poly->vertexlist       = new int[poly->numberofvertices];
5112       for (v = 0; v < numVertices; ++v) {
5113         const PetscInt vIdx = points[v] - vStart;
5114         poly->vertexlist[v] = vIdx;
5115       }
5116       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5117       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5118     }
5119   }
5120   if (!rank) {
5121     char args[32];
5122 
5123     /* Take away 'Q' for verbose output */
5124     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5125     ::tetrahedralize(args, &in, &out);
5126   }
5127   {
5128     const PetscInt numCorners  = 4;
5129     const PetscInt numCells    = out.numberoftetrahedra;
5130     const PetscInt numVertices = out.numberofpoints;
5131     const int     *cells       = out.tetrahedronlist;
5132     const double  *meshCoords  = out.pointlist;
5133 
5134     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5135     /* Set labels */
5136     for (v = 0; v < numVertices; ++v) {
5137       if (out.pointmarkerlist[v]) {
5138         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5139       }
5140     }
5141     if (interpolate) {
5142       PetscInt e;
5143 
5144       for (e = 0; e < out.numberofedges; e++) {
5145         if (out.edgemarkerlist[e]) {
5146           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5147           const PetscInt *edges;
5148           PetscInt        numEdges;
5149 
5150           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5151           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5152           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5153           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5154         }
5155       }
5156       for (f = 0; f < out.numberoftrifaces; f++) {
5157         if (out.trifacemarkerlist[f]) {
5158           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5159           const PetscInt *faces;
5160           PetscInt        numFaces;
5161 
5162           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5163           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5164           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5165           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5166         }
5167       }
5168     }
5169     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5170   }
5171   PetscFunctionReturn(0);
5172 }
5173 
5174 #undef __FUNCT__
5175 #define __FUNCT__ "DMPlexRefine_Tetgen"
5176 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5177 {
5178   MPI_Comm       comm = ((PetscObject) dm)->comm;
5179   const PetscInt dim  = 3;
5180   ::tetgenio     in;
5181   ::tetgenio     out;
5182   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5183   PetscMPIInt    rank;
5184   PetscErrorCode ierr;
5185 
5186   PetscFunctionBegin;
5187   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5188   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5189   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5190   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5191   in.numberofpoints = vEnd - vStart;
5192   if (in.numberofpoints > 0) {
5193     PetscSection coordSection;
5194     Vec          coordinates;
5195     PetscScalar *array;
5196 
5197     in.pointlist       = new double[in.numberofpoints*dim];
5198     in.pointmarkerlist = new int[in.numberofpoints];
5199     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5200     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5201     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5202     for (v = vStart; v < vEnd; ++v) {
5203       const PetscInt idx = v - vStart;
5204       PetscInt       off, d;
5205 
5206       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5207       for (d = 0; d < dim; ++d) {
5208         in.pointlist[idx*dim + d] = array[off+d];
5209       }
5210       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5211     }
5212     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5213   }
5214   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5215   in.numberofcorners       = 4;
5216   in.numberoftetrahedra    = cEnd - cStart;
5217   in.tetrahedronvolumelist = (double *) maxVolumes;
5218   if (in.numberoftetrahedra > 0) {
5219     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5220     for (c = cStart; c < cEnd; ++c) {
5221       const PetscInt idx     = c - cStart;
5222       PetscInt      *closure = PETSC_NULL;
5223       PetscInt       closureSize;
5224 
5225       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5226       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5227       for (v = 0; v < 4; ++v) {
5228         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5229       }
5230       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5231     }
5232   }
5233   /* TODO: Put in boundary faces with markers */
5234   if (!rank) {
5235     char args[32];
5236 
5237     /* Take away 'Q' for verbose output */
5238     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5239     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5240     ::tetrahedralize(args, &in, &out);
5241   }
5242   in.tetrahedronvolumelist = NULL;
5243 
5244   {
5245     const PetscInt numCorners  = 4;
5246     const PetscInt numCells    = out.numberoftetrahedra;
5247     const PetscInt numVertices = out.numberofpoints;
5248     const int     *cells       = out.tetrahedronlist;
5249     const double  *meshCoords  = out.pointlist;
5250     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5251 
5252     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5253     /* Set labels */
5254     for (v = 0; v < numVertices; ++v) {
5255       if (out.pointmarkerlist[v]) {
5256         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5257       }
5258     }
5259     if (interpolate) {
5260       PetscInt e, f;
5261 
5262       for (e = 0; e < out.numberofedges; e++) {
5263         if (out.edgemarkerlist[e]) {
5264           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5265           const PetscInt *edges;
5266           PetscInt        numEdges;
5267 
5268           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5269           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5270           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5271           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5272         }
5273       }
5274       for (f = 0; f < out.numberoftrifaces; f++) {
5275         if (out.trifacemarkerlist[f]) {
5276           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5277           const PetscInt *faces;
5278           PetscInt        numFaces;
5279 
5280           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5281           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5282           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5283           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5284         }
5285       }
5286     }
5287     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5288   }
5289   PetscFunctionReturn(0);
5290 }
5291 #endif
5292 
5293 #if defined(PETSC_HAVE_CTETGEN)
5294 #include "ctetgen.h"
5295 
5296 #undef __FUNCT__
5297 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5298 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5299 {
5300   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5301   const PetscInt dim  = 3;
5302   PLC           *in, *out;
5303   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5304   PetscMPIInt    rank;
5305   PetscErrorCode ierr;
5306 
5307   PetscFunctionBegin;
5308   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5309   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5310   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5311   ierr = PLCCreate(&in);CHKERRQ(ierr);
5312   ierr = PLCCreate(&out);CHKERRQ(ierr);
5313   in->numberofpoints = vEnd - vStart;
5314   if (in->numberofpoints > 0) {
5315     PetscSection coordSection;
5316     Vec          coordinates;
5317     PetscScalar *array;
5318 
5319     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5320     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5321     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5322     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5323     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5324     for (v = vStart; v < vEnd; ++v) {
5325       const PetscInt idx = v - vStart;
5326       PetscInt       off, d, m;
5327 
5328       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5329       for (d = 0; d < dim; ++d) {
5330         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5331       }
5332       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5333       in->pointmarkerlist[idx] = (int) m;
5334     }
5335     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5336   }
5337   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5338   in->numberoffacets = fEnd - fStart;
5339   if (in->numberoffacets > 0) {
5340     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5341     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5342     for (f = fStart; f < fEnd; ++f) {
5343       const PetscInt idx    = f - fStart;
5344       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5345       polygon       *poly;
5346 
5347       in->facetlist[idx].numberofpolygons = 1;
5348       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5349       in->facetlist[idx].numberofholes    = 0;
5350       in->facetlist[idx].holelist         = PETSC_NULL;
5351 
5352       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5353       for (p = 0; p < numPoints*2; p += 2) {
5354         const PetscInt point = points[p];
5355         if ((point >= vStart) && (point < vEnd)) {
5356           points[numVertices++] = point;
5357         }
5358       }
5359 
5360       poly = in->facetlist[idx].polygonlist;
5361       poly->numberofvertices = numVertices;
5362       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5363       for (v = 0; v < numVertices; ++v) {
5364         const PetscInt vIdx = points[v] - vStart;
5365         poly->vertexlist[v] = vIdx;
5366       }
5367       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5368       in->facetmarkerlist[idx] = (int) m;
5369       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5370     }
5371   }
5372   if (!rank) {
5373     TetGenOpts t;
5374 
5375     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5376     t.in        = boundary; /* Should go away */
5377     t.plc       = 1;
5378     t.quality   = 1;
5379     t.edgesout  = 1;
5380     t.zeroindex = 1;
5381     t.quiet     = 1;
5382     t.verbose   = verbose;
5383     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5384     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5385   }
5386   {
5387     const PetscInt numCorners  = 4;
5388     const PetscInt numCells    = out->numberoftetrahedra;
5389     const PetscInt numVertices = out->numberofpoints;
5390     const int     *cells       = out->tetrahedronlist;
5391     const double  *meshCoords  = out->pointlist;
5392 
5393     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5394     /* Set labels */
5395     for (v = 0; v < numVertices; ++v) {
5396       if (out->pointmarkerlist[v]) {
5397         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5398       }
5399     }
5400     if (interpolate) {
5401       PetscInt e;
5402 
5403       for (e = 0; e < out->numberofedges; e++) {
5404         if (out->edgemarkerlist[e]) {
5405           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5406           const PetscInt *edges;
5407           PetscInt        numEdges;
5408 
5409           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5410           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5411           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5412           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5413         }
5414       }
5415       for (f = 0; f < out->numberoftrifaces; f++) {
5416         if (out->trifacemarkerlist[f]) {
5417           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5418           const PetscInt *faces;
5419           PetscInt        numFaces;
5420 
5421           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5422           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5423           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5424           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5425         }
5426       }
5427     }
5428     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5429   }
5430 
5431   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5432   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5433   PetscFunctionReturn(0);
5434 }
5435 
5436 #undef __FUNCT__
5437 #define __FUNCT__ "DMPlexRefine_CTetgen"
5438 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5439 {
5440   MPI_Comm       comm = ((PetscObject) dm)->comm;
5441   const PetscInt dim  = 3;
5442   PLC           *in, *out;
5443   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5444   PetscMPIInt    rank;
5445   PetscErrorCode ierr;
5446 
5447   PetscFunctionBegin;
5448   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5449   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5450   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5451   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5452   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5453   ierr = PLCCreate(&in);CHKERRQ(ierr);
5454   ierr = PLCCreate(&out);CHKERRQ(ierr);
5455   in->numberofpoints = vEnd - vStart;
5456   if (in->numberofpoints > 0) {
5457     PetscSection coordSection;
5458     Vec          coordinates;
5459     PetscScalar *array;
5460 
5461     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5462     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5463     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5464     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5465     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5466     for (v = vStart; v < vEnd; ++v) {
5467       const PetscInt idx = v - vStart;
5468       PetscInt       off, d, m;
5469 
5470       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5471       for (d = 0; d < dim; ++d) {
5472         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5473       }
5474       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5475       in->pointmarkerlist[idx] = (int) m;
5476     }
5477     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5478   }
5479   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5480   in->numberofcorners       = 4;
5481   in->numberoftetrahedra    = cEnd - cStart;
5482   in->tetrahedronvolumelist = maxVolumes;
5483   if (in->numberoftetrahedra > 0) {
5484     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5485     for (c = cStart; c < cEnd; ++c) {
5486       const PetscInt idx     = c - cStart;
5487       PetscInt      *closure = PETSC_NULL;
5488       PetscInt       closureSize;
5489 
5490       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5491       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5492       for (v = 0; v < 4; ++v) {
5493         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5494       }
5495       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5496     }
5497   }
5498   if (!rank) {
5499     TetGenOpts t;
5500 
5501     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5502     t.in        = dm; /* Should go away */
5503     t.refine    = 1;
5504     t.varvolume = 1;
5505     t.quality   = 1;
5506     t.edgesout  = 1;
5507     t.zeroindex = 1;
5508     t.quiet     = 1;
5509     t.verbose   = verbose; /* Change this */
5510     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5511     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5512   }
5513   {
5514     const PetscInt numCorners  = 4;
5515     const PetscInt numCells    = out->numberoftetrahedra;
5516     const PetscInt numVertices = out->numberofpoints;
5517     const int     *cells       = out->tetrahedronlist;
5518     const double  *meshCoords  = out->pointlist;
5519     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5520 
5521     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5522     /* Set labels */
5523     for (v = 0; v < numVertices; ++v) {
5524       if (out->pointmarkerlist[v]) {
5525         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5526       }
5527     }
5528     if (interpolate) {
5529       PetscInt e, f;
5530 
5531       for (e = 0; e < out->numberofedges; e++) {
5532         if (out->edgemarkerlist[e]) {
5533           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5534           const PetscInt *edges;
5535           PetscInt        numEdges;
5536 
5537           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5538           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5539           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5540           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5541         }
5542       }
5543       for (f = 0; f < out->numberoftrifaces; f++) {
5544         if (out->trifacemarkerlist[f]) {
5545           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5546           const PetscInt *faces;
5547           PetscInt        numFaces;
5548 
5549           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5550           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5551           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5552           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5553         }
5554       }
5555     }
5556     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5557   }
5558   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5559   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5560   PetscFunctionReturn(0);
5561 }
5562 #endif
5563 
5564 #undef __FUNCT__
5565 #define __FUNCT__ "DMPlexGenerate"
5566 /*@C
5567   DMPlexGenerate - Generates a mesh.
5568 
5569   Not Collective
5570 
5571   Input Parameters:
5572 + boundary - The DMPlex boundary object
5573 . name - The mesh generation package name
5574 - interpolate - Flag to create intermediate mesh elements
5575 
5576   Output Parameter:
5577 . mesh - The DMPlex object
5578 
5579   Level: intermediate
5580 
5581 .keywords: mesh, elements
5582 .seealso: DMPlexCreate(), DMRefine()
5583 @*/
5584 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5585 {
5586   PetscInt       dim;
5587   char           genname[1024];
5588   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5589   PetscErrorCode ierr;
5590 
5591   PetscFunctionBegin;
5592   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5593   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5594   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5595   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5596   if (flg) {name = genname;}
5597   if (name) {
5598     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5599     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5600     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5601   }
5602   switch (dim) {
5603   case 1:
5604     if (!name || isTriangle) {
5605 #if defined(PETSC_HAVE_TRIANGLE)
5606       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5607 #else
5608       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5609 #endif
5610     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5611     break;
5612   case 2:
5613     if (!name || isCTetgen) {
5614 #if defined(PETSC_HAVE_CTETGEN)
5615       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5616 #else
5617       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5618 #endif
5619     } else if (isTetgen) {
5620 #if defined(PETSC_HAVE_TETGEN)
5621       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5622 #else
5623       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5624 #endif
5625     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5626     break;
5627   default:
5628     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5629   }
5630   PetscFunctionReturn(0);
5631 }
5632 
5633 typedef PetscInt CellRefiner;
5634 
5635 #undef __FUNCT__
5636 #define __FUNCT__ "GetDepthStart_Private"
5637 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5638 {
5639   PetscFunctionBegin;
5640   if (cStart) *cStart = 0;
5641   if (vStart) *vStart = depthSize[depth];
5642   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5643   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5644   PetscFunctionReturn(0);
5645 }
5646 
5647 #undef __FUNCT__
5648 #define __FUNCT__ "GetDepthEnd_Private"
5649 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5650 {
5651   PetscFunctionBegin;
5652   if (cEnd) *cEnd = depthSize[depth];
5653   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5654   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5655   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5656   PetscFunctionReturn(0);
5657 }
5658 
5659 #undef __FUNCT__
5660 #define __FUNCT__ "CellRefinerGetSizes"
5661 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5662 {
5663   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5664   PetscErrorCode ierr;
5665 
5666   PetscFunctionBegin;
5667   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5668   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5669   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5670   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5671   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5672   switch (refiner) {
5673   case 1:
5674     /* Simplicial 2D */
5675     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5676     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5677     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5678     break;
5679   case 3:
5680     /* Hybrid 2D */
5681     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5682     cMax = PetscMin(cEnd, cMax);
5683     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5684     fMax = PetscMin(fEnd, fMax);
5685     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5686     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 */
5687     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5688     break;
5689   case 2:
5690     /* Hex 2D */
5691     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5692     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5693     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5694     break;
5695   default:
5696     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5697   }
5698   PetscFunctionReturn(0);
5699 }
5700 
5701 #undef __FUNCT__
5702 #define __FUNCT__ "CellRefinerSetConeSizes"
5703 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5704 {
5705   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5706   PetscErrorCode ierr;
5707 
5708   PetscFunctionBegin;
5709   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5710   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5711   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5712   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5713   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5714   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5715   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5716   switch (refiner) {
5717   case 1:
5718     /* Simplicial 2D */
5719     /* All cells have 3 faces */
5720     for (c = cStart; c < cEnd; ++c) {
5721       for (r = 0; r < 4; ++r) {
5722         const PetscInt newp = (c - cStart)*4 + r;
5723 
5724         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5725       }
5726     }
5727     /* Split faces have 2 vertices and the same cells as the parent */
5728     for (f = fStart; f < fEnd; ++f) {
5729       for (r = 0; r < 2; ++r) {
5730         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5731         PetscInt       size;
5732 
5733         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5734         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5735         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5736       }
5737     }
5738     /* Interior faces have 2 vertices and 2 cells */
5739     for (c = cStart; c < cEnd; ++c) {
5740       for (r = 0; r < 3; ++r) {
5741         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5742 
5743         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5744         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5745       }
5746     }
5747     /* Old vertices have identical supports */
5748     for (v = vStart; v < vEnd; ++v) {
5749       const PetscInt newp = vStartNew + (v - vStart);
5750       PetscInt       size;
5751 
5752       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5753       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5754     }
5755     /* Face vertices have 2 + cells*2 supports */
5756     for (f = fStart; f < fEnd; ++f) {
5757       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5758       PetscInt       size;
5759 
5760       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5761       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5762     }
5763     break;
5764   case 2:
5765     /* Hex 2D */
5766     /* All cells have 4 faces */
5767     for (c = cStart; c < cEnd; ++c) {
5768       for (r = 0; r < 4; ++r) {
5769         const PetscInt newp = (c - cStart)*4 + r;
5770 
5771         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5772       }
5773     }
5774     /* Split faces have 2 vertices and the same cells as the parent */
5775     for (f = fStart; f < fEnd; ++f) {
5776       for (r = 0; r < 2; ++r) {
5777         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5778         PetscInt       size;
5779 
5780         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5781         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5782         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5783       }
5784     }
5785     /* Interior faces have 2 vertices and 2 cells */
5786     for (c = cStart; c < cEnd; ++c) {
5787       for (r = 0; r < 4; ++r) {
5788         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5789 
5790         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5791         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5792       }
5793     }
5794     /* Old vertices have identical supports */
5795     for (v = vStart; v < vEnd; ++v) {
5796       const PetscInt newp = vStartNew + (v - vStart);
5797       PetscInt       size;
5798 
5799       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5800       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5801     }
5802     /* Face vertices have 2 + cells supports */
5803     for (f = fStart; f < fEnd; ++f) {
5804       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5805       PetscInt       size;
5806 
5807       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5808       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5809     }
5810     /* Cell vertices have 4 supports */
5811     for (c = cStart; c < cEnd; ++c) {
5812       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5813 
5814       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5815     }
5816     break;
5817   case 3:
5818     /* Hybrid 2D */
5819     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5820     cMax = PetscMin(cEnd, cMax);
5821     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5822     fMax = PetscMin(fEnd, fMax);
5823     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5824     /* Interior cells have 3 faces */
5825     for (c = cStart; c < cMax; ++c) {
5826       for (r = 0; r < 4; ++r) {
5827         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5828 
5829         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5830       }
5831     }
5832     /* Hybrid cells have 4 faces */
5833     for (c = cMax; c < cEnd; ++c) {
5834       for (r = 0; r < 2; ++r) {
5835         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5836 
5837         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5838       }
5839     }
5840     /* Interior split faces have 2 vertices and the same cells as the parent */
5841     for (f = fStart; f < fMax; ++f) {
5842       for (r = 0; r < 2; ++r) {
5843         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5844         PetscInt       size;
5845 
5846         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5847         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5848         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5849       }
5850     }
5851     /* Interior cell faces have 2 vertices and 2 cells */
5852     for (c = cStart; c < cMax; ++c) {
5853       for (r = 0; r < 3; ++r) {
5854         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5855 
5856         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5857         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5858       }
5859     }
5860     /* Hybrid faces have 2 vertices and the same cells */
5861     for (f = fMax; f < fEnd; ++f) {
5862       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5863       PetscInt       size;
5864 
5865       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5866       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5867       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5868     }
5869     /* Hybrid cell faces have 2 vertices and 2 cells */
5870     for (c = cMax; c < cEnd; ++c) {
5871       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5872 
5873       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5874       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5875     }
5876     /* Old vertices have identical supports */
5877     for (v = vStart; v < vEnd; ++v) {
5878       const PetscInt newp = vStartNew + (v - vStart);
5879       PetscInt       size;
5880 
5881       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5882       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5883     }
5884     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5885     for (f = fStart; f < fMax; ++f) {
5886       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5887       const PetscInt *support;
5888       PetscInt        size, newSize = 2, s;
5889 
5890       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5891       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5892       for (s = 0; s < size; ++s) {
5893         if (support[s] >= cMax) {
5894           newSize += 1;
5895         } else {
5896           newSize += 2;
5897         }
5898       }
5899       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5900     }
5901     break;
5902   default:
5903     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5904   }
5905   PetscFunctionReturn(0);
5906 }
5907 
5908 #undef __FUNCT__
5909 #define __FUNCT__ "CellRefinerSetCones"
5910 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5911 {
5912   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;
5913   PetscInt       maxSupportSize, *supportRef;
5914   PetscErrorCode ierr;
5915 
5916   PetscFunctionBegin;
5917   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5918   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5919   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5920   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5921   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5922   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5923   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5924   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5925   switch (refiner) {
5926   case 1:
5927     /* Simplicial 2D */
5928     /*
5929      2
5930      |\
5931      | \
5932      |  \
5933      |   \
5934      | C  \
5935      |     \
5936      |      \
5937      2---1---1
5938      |\  D  / \
5939      | 2   0   \
5940      |A \ /  B  \
5941      0---0-------1
5942      */
5943     /* All cells have 3 faces */
5944     for (c = cStart; c < cEnd; ++c) {
5945       const PetscInt  newp = cStartNew + (c - cStart)*4;
5946       const PetscInt *cone, *ornt;
5947       PetscInt        coneNew[3], orntNew[3];
5948 
5949       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5950       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5951       /* A triangle */
5952       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5953       orntNew[0] = ornt[0];
5954       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5955       orntNew[1] = -2;
5956       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5957       orntNew[2] = ornt[2];
5958       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5959       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5960 #if 1
5961       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);
5962       for (p = 0; p < 3; ++p) {
5963         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);
5964       }
5965 #endif
5966       /* B triangle */
5967       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5968       orntNew[0] = ornt[0];
5969       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5970       orntNew[1] = ornt[1];
5971       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5972       orntNew[2] = -2;
5973       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5974       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5975 #if 1
5976       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);
5977       for (p = 0; p < 3; ++p) {
5978         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);
5979       }
5980 #endif
5981       /* C triangle */
5982       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5983       orntNew[0] = -2;
5984       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5985       orntNew[1] = ornt[1];
5986       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5987       orntNew[2] = ornt[2];
5988       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5989       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5990 #if 1
5991       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);
5992       for (p = 0; p < 3; ++p) {
5993         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);
5994       }
5995 #endif
5996       /* D triangle */
5997       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5998       orntNew[0] = 0;
5999       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6000       orntNew[1] = 0;
6001       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6002       orntNew[2] = 0;
6003       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6004       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6005 #if 1
6006       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);
6007       for (p = 0; p < 3; ++p) {
6008         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);
6009       }
6010 #endif
6011     }
6012     /* Split faces have 2 vertices and the same cells as the parent */
6013     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6014     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6015     for (f = fStart; f < fEnd; ++f) {
6016       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6017 
6018       for (r = 0; r < 2; ++r) {
6019         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6020         const PetscInt *cone, *support;
6021         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6022 
6023         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6024         coneNew[0] = vStartNew + (cone[0] - vStart);
6025         coneNew[1] = vStartNew + (cone[1] - vStart);
6026         coneNew[(r+1)%2] = newv;
6027         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6028 #if 1
6029         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6030         for (p = 0; p < 2; ++p) {
6031           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);
6032         }
6033 #endif
6034         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6035         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6036         for (s = 0; s < supportSize; ++s) {
6037           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6038           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6039           for (c = 0; c < coneSize; ++c) {
6040             if (cone[c] == f) {
6041               break;
6042             }
6043           }
6044           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6045         }
6046         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6047 #if 1
6048         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6049         for (p = 0; p < supportSize; ++p) {
6050           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);
6051         }
6052 #endif
6053       }
6054     }
6055     /* Interior faces have 2 vertices and 2 cells */
6056     for (c = cStart; c < cEnd; ++c) {
6057       const PetscInt *cone;
6058 
6059       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6060       for (r = 0; r < 3; ++r) {
6061         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6062         PetscInt       coneNew[2];
6063         PetscInt       supportNew[2];
6064 
6065         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6066         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6067         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6068 #if 1
6069         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6070         for (p = 0; p < 2; ++p) {
6071           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);
6072         }
6073 #endif
6074         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6075         supportNew[1] = (c - cStart)*4 + 3;
6076         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6077 #if 1
6078         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6079         for (p = 0; p < 2; ++p) {
6080           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);
6081         }
6082 #endif
6083       }
6084     }
6085     /* Old vertices have identical supports */
6086     for (v = vStart; v < vEnd; ++v) {
6087       const PetscInt  newp = vStartNew + (v - vStart);
6088       const PetscInt *support, *cone;
6089       PetscInt        size, s;
6090 
6091       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6092       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6093       for (s = 0; s < size; ++s) {
6094         PetscInt r = 0;
6095 
6096         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6097         if (cone[1] == v) r = 1;
6098         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6099       }
6100       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6101 #if 1
6102       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6103       for (p = 0; p < size; ++p) {
6104         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);
6105       }
6106 #endif
6107     }
6108     /* Face vertices have 2 + cells*2 supports */
6109     for (f = fStart; f < fEnd; ++f) {
6110       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6111       const PetscInt *cone, *support;
6112       PetscInt        size, s;
6113 
6114       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6115       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6116       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6117       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6118       for (s = 0; s < size; ++s) {
6119         PetscInt r = 0;
6120 
6121         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6122         if      (cone[1] == f) r = 1;
6123         else if (cone[2] == f) r = 2;
6124         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6125         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6126       }
6127       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6128 #if 1
6129       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6130       for (p = 0; p < 2+size*2; ++p) {
6131         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);
6132       }
6133 #endif
6134     }
6135     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6136     break;
6137   case 2:
6138     /* Hex 2D */
6139     /*
6140      3---------2---------2
6141      |         |         |
6142      |    D    2    C    |
6143      |         |         |
6144      3----3----0----1----1
6145      |         |         |
6146      |    A    0    B    |
6147      |         |         |
6148      0---------0---------1
6149      */
6150     /* All cells have 4 faces */
6151     for (c = cStart; c < cEnd; ++c) {
6152       const PetscInt  newp = (c - cStart)*4;
6153       const PetscInt *cone, *ornt;
6154       PetscInt        coneNew[4], orntNew[4];
6155 
6156       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6157       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6158       /* A quad */
6159       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6160       orntNew[0] = ornt[0];
6161       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6162       orntNew[1] = 0;
6163       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6164       orntNew[2] = -2;
6165       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6166       orntNew[3] = ornt[3];
6167       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6168       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6169 #if 1
6170       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);
6171       for (p = 0; p < 4; ++p) {
6172         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);
6173       }
6174 #endif
6175       /* B quad */
6176       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6177       orntNew[0] = ornt[0];
6178       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6179       orntNew[1] = ornt[1];
6180       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6181       orntNew[2] = 0;
6182       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6183       orntNew[3] = -2;
6184       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6185       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6186 #if 1
6187       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);
6188       for (p = 0; p < 4; ++p) {
6189         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);
6190       }
6191 #endif
6192       /* C quad */
6193       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6194       orntNew[0] = -2;
6195       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6196       orntNew[1] = ornt[1];
6197       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6198       orntNew[2] = ornt[2];
6199       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6200       orntNew[3] = 0;
6201       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6202       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6203 #if 1
6204       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);
6205       for (p = 0; p < 4; ++p) {
6206         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);
6207       }
6208 #endif
6209       /* D quad */
6210       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6211       orntNew[0] = 0;
6212       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6213       orntNew[1] = -2;
6214       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6215       orntNew[2] = ornt[2];
6216       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6217       orntNew[3] = ornt[3];
6218       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6219       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6220 #if 1
6221       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);
6222       for (p = 0; p < 4; ++p) {
6223         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);
6224       }
6225 #endif
6226     }
6227     /* Split faces have 2 vertices and the same cells as the parent */
6228     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6229     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6230     for (f = fStart; f < fEnd; ++f) {
6231       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6232 
6233       for (r = 0; r < 2; ++r) {
6234         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6235         const PetscInt *cone, *support;
6236         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6237 
6238         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6239         coneNew[0] = vStartNew + (cone[0] - vStart);
6240         coneNew[1] = vStartNew + (cone[1] - vStart);
6241         coneNew[(r+1)%2] = newv;
6242         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6243 #if 1
6244         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6245         for (p = 0; p < 2; ++p) {
6246           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6247         }
6248 #endif
6249         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6250         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6251         for (s = 0; s < supportSize; ++s) {
6252           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6253           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6254           for (c = 0; c < coneSize; ++c) {
6255             if (cone[c] == f) {
6256               break;
6257             }
6258           }
6259           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6260         }
6261         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6262 #if 1
6263         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6264         for (p = 0; p < supportSize; ++p) {
6265           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);
6266         }
6267 #endif
6268       }
6269     }
6270     /* Interior faces have 2 vertices and 2 cells */
6271     for (c = cStart; c < cEnd; ++c) {
6272       const PetscInt *cone;
6273       PetscInt        coneNew[2], supportNew[2];
6274 
6275       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6276       for (r = 0; r < 4; ++r) {
6277         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6278 
6279         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6280         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6281         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6282 #if 1
6283         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6284         for (p = 0; p < 2; ++p) {
6285           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);
6286         }
6287 #endif
6288         supportNew[0] = (c - cStart)*4 + r;
6289         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6290         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6291 #if 1
6292         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6293         for (p = 0; p < 2; ++p) {
6294           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);
6295         }
6296 #endif
6297       }
6298     }
6299     /* Old vertices have identical supports */
6300     for (v = vStart; v < vEnd; ++v) {
6301       const PetscInt  newp = vStartNew + (v - vStart);
6302       const PetscInt *support, *cone;
6303       PetscInt        size, s;
6304 
6305       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6306       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6307       for (s = 0; s < size; ++s) {
6308         PetscInt r = 0;
6309 
6310         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6311         if (cone[1] == v) r = 1;
6312         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6313       }
6314       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6315 #if 1
6316       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6317       for (p = 0; p < size; ++p) {
6318         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);
6319       }
6320 #endif
6321     }
6322     /* Face vertices have 2 + cells supports */
6323     for (f = fStart; f < fEnd; ++f) {
6324       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6325       const PetscInt *cone, *support;
6326       PetscInt        size, s;
6327 
6328       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6329       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6330       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6331       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6332       for (s = 0; s < size; ++s) {
6333         PetscInt r = 0;
6334 
6335         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6336         if      (cone[1] == f) r = 1;
6337         else if (cone[2] == f) r = 2;
6338         else if (cone[3] == f) r = 3;
6339         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6340       }
6341       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6342 #if 1
6343       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6344       for (p = 0; p < 2+size; ++p) {
6345         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);
6346       }
6347 #endif
6348     }
6349     /* Cell vertices have 4 supports */
6350     for (c = cStart; c < cEnd; ++c) {
6351       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6352       PetscInt       supportNew[4];
6353 
6354       for (r = 0; r < 4; ++r) {
6355         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6356       }
6357       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6358     }
6359     break;
6360   case 3:
6361     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6362     cMax = PetscMin(cEnd, cMax);
6363     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6364     fMax = PetscMin(fEnd, fMax);
6365     /* Interior cells have 3 faces */
6366     for (c = cStart; c < cMax; ++c) {
6367       const PetscInt  newp = cStartNew + (c - cStart)*4;
6368       const PetscInt *cone, *ornt;
6369       PetscInt        coneNew[3], orntNew[3];
6370 
6371       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6372       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6373       /* A triangle */
6374       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6375       orntNew[0] = ornt[0];
6376       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6377       orntNew[1] = -2;
6378       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6379       orntNew[2] = ornt[2];
6380       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6381       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6382 #if 1
6383       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);
6384       for (p = 0; p < 3; ++p) {
6385         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);
6386       }
6387 #endif
6388       /* B triangle */
6389       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6390       orntNew[0] = ornt[0];
6391       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6392       orntNew[1] = ornt[1];
6393       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6394       orntNew[2] = -2;
6395       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6396       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6397 #if 1
6398       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);
6399       for (p = 0; p < 3; ++p) {
6400         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);
6401       }
6402 #endif
6403       /* C triangle */
6404       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6405       orntNew[0] = -2;
6406       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6407       orntNew[1] = ornt[1];
6408       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6409       orntNew[2] = ornt[2];
6410       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6411       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6412 #if 1
6413       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);
6414       for (p = 0; p < 3; ++p) {
6415         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);
6416       }
6417 #endif
6418       /* D triangle */
6419       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6420       orntNew[0] = 0;
6421       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6422       orntNew[1] = 0;
6423       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6424       orntNew[2] = 0;
6425       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6426       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6427 #if 1
6428       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);
6429       for (p = 0; p < 3; ++p) {
6430         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);
6431       }
6432 #endif
6433     }
6434     /*
6435      2----3----3
6436      |         |
6437      |    B    |
6438      |         |
6439      0----4--- 1
6440      |         |
6441      |    A    |
6442      |         |
6443      0----2----1
6444      */
6445     /* Hybrid cells have 4 faces */
6446     for (c = cMax; c < cEnd; ++c) {
6447       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6448       const PetscInt *cone, *ornt;
6449       PetscInt        coneNew[4], orntNew[4];
6450 
6451       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6452       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6453       /* A quad */
6454       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6455       orntNew[0] = ornt[0];
6456       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6457       orntNew[1] = ornt[1];
6458       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6459       orntNew[2] = 0;
6460       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6461       orntNew[3] = 0;
6462       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6463       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6464 #if 1
6465       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);
6466       for (p = 0; p < 4; ++p) {
6467         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);
6468       }
6469 #endif
6470       /* B quad */
6471       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6472       orntNew[0] = ornt[0];
6473       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6474       orntNew[1] = ornt[1];
6475       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6476       orntNew[2] = 0;
6477       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6478       orntNew[3] = 0;
6479       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6480       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6481 #if 1
6482       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);
6483       for (p = 0; p < 4; ++p) {
6484         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);
6485       }
6486 #endif
6487     }
6488     /* Interior split faces have 2 vertices and the same cells as the parent */
6489     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6490     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6491     for (f = fStart; f < fMax; ++f) {
6492       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6493 
6494       for (r = 0; r < 2; ++r) {
6495         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6496         const PetscInt *cone, *support;
6497         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6498 
6499         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6500         coneNew[0] = vStartNew + (cone[0] - vStart);
6501         coneNew[1] = vStartNew + (cone[1] - vStart);
6502         coneNew[(r+1)%2] = newv;
6503         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6504 #if 1
6505         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6506         for (p = 0; p < 2; ++p) {
6507           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);
6508         }
6509 #endif
6510         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6511         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6512         for (s = 0; s < supportSize; ++s) {
6513           if (support[s] >= cMax) {
6514             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6515           } else {
6516             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6517             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6518             for (c = 0; c < coneSize; ++c) {
6519               if (cone[c] == f) {
6520                 break;
6521               }
6522             }
6523             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6524           }
6525         }
6526         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6527 #if 1
6528         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6529         for (p = 0; p < supportSize; ++p) {
6530           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);
6531         }
6532 #endif
6533       }
6534     }
6535     /* Interior cell faces have 2 vertices and 2 cells */
6536     for (c = cStart; c < cMax; ++c) {
6537       const PetscInt *cone;
6538 
6539       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6540       for (r = 0; r < 3; ++r) {
6541         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6542         PetscInt       coneNew[2];
6543         PetscInt       supportNew[2];
6544 
6545         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6546         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6547         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6548 #if 1
6549         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6550         for (p = 0; p < 2; ++p) {
6551           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);
6552         }
6553 #endif
6554         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6555         supportNew[1] = (c - cStart)*4 + 3;
6556         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6557 #if 1
6558         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6559         for (p = 0; p < 2; ++p) {
6560           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);
6561         }
6562 #endif
6563       }
6564     }
6565     /* Interior hybrid faces have 2 vertices and the same cells */
6566     for (f = fMax; f < fEnd; ++f) {
6567       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6568       const PetscInt *cone;
6569       const PetscInt *support;
6570       PetscInt        coneNew[2];
6571       PetscInt        supportNew[2];
6572       PetscInt        size, s, r;
6573 
6574       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6575       coneNew[0] = vStartNew + (cone[0] - vStart);
6576       coneNew[1] = vStartNew + (cone[1] - vStart);
6577       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6578 #if 1
6579       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6580       for (p = 0; p < 2; ++p) {
6581         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);
6582       }
6583 #endif
6584       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6585       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6586       for (s = 0; s < size; ++s) {
6587         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6588         for (r = 0; r < 2; ++r) {
6589           if (cone[r+2] == f) break;
6590         }
6591         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6592       }
6593       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6594 #if 1
6595       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6596       for (p = 0; p < size; ++p) {
6597         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);
6598       }
6599 #endif
6600     }
6601     /* Cell hybrid faces have 2 vertices and 2 cells */
6602     for (c = cMax; c < cEnd; ++c) {
6603       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6604       const PetscInt *cone;
6605       PetscInt        coneNew[2];
6606       PetscInt        supportNew[2];
6607 
6608       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6609       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6610       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6611       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6612 #if 1
6613       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6614       for (p = 0; p < 2; ++p) {
6615         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);
6616       }
6617 #endif
6618       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6619       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6620       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6621 #if 1
6622       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6623       for (p = 0; p < 2; ++p) {
6624         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);
6625       }
6626 #endif
6627     }
6628     /* Old vertices have identical supports */
6629     for (v = vStart; v < vEnd; ++v) {
6630       const PetscInt  newp = vStartNew + (v - vStart);
6631       const PetscInt *support, *cone;
6632       PetscInt        size, s;
6633 
6634       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6635       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6636       for (s = 0; s < size; ++s) {
6637         if (support[s] >= fMax) {
6638           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6639         } else {
6640           PetscInt r = 0;
6641 
6642           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6643           if (cone[1] == v) r = 1;
6644           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6645         }
6646       }
6647       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6648 #if 1
6649       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6650       for (p = 0; p < size; ++p) {
6651         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);
6652       }
6653 #endif
6654     }
6655     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6656     for (f = fStart; f < fMax; ++f) {
6657       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6658       const PetscInt *cone, *support;
6659       PetscInt        size, newSize = 2, s;
6660 
6661       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6662       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6663       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6664       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6665       for (s = 0; s < size; ++s) {
6666         PetscInt r = 0;
6667 
6668         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6669         if (support[s] >= cMax) {
6670           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6671           newSize += 1;
6672         } else {
6673           if      (cone[1] == f) r = 1;
6674           else if (cone[2] == f) r = 2;
6675           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6676           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6677           newSize += 2;
6678         }
6679       }
6680       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6681 #if 1
6682       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6683       for (p = 0; p < newSize; ++p) {
6684         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);
6685       }
6686 #endif
6687     }
6688     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6689     break;
6690   default:
6691     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6692   }
6693   PetscFunctionReturn(0);
6694 }
6695 
6696 #undef __FUNCT__
6697 #define __FUNCT__ "CellRefinerSetCoordinates"
6698 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6699 {
6700   PetscSection   coordSection, coordSectionNew;
6701   Vec            coordinates, coordinatesNew;
6702   PetscScalar   *coords, *coordsNew;
6703   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6704   PetscErrorCode ierr;
6705 
6706   PetscFunctionBegin;
6707   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6708   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6709   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6710   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6711   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6712   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6713   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6714   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6715   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6716   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6717   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6718   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6719   if (fMax < 0) fMax = fEnd;
6720   switch (refiner) {
6721   case 1:
6722   case 2:
6723   case 3:
6724     /* Simplicial and Hex 2D */
6725     /* All vertices have the dim coordinates */
6726     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6727       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6728       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6729     }
6730     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6731     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6732     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6733     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6734     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6735     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6736     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6737     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6738     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6739     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6740     /* Old vertices have the same coordinates */
6741     for (v = vStart; v < vEnd; ++v) {
6742       const PetscInt newv = vStartNew + (v - vStart);
6743       PetscInt       off, offnew, d;
6744 
6745       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6746       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6747       for (d = 0; d < dim; ++d) {
6748         coordsNew[offnew+d] = coords[off+d];
6749       }
6750     }
6751     /* Face vertices have the average of endpoint coordinates */
6752     for (f = fStart; f < fMax; ++f) {
6753       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6754       const PetscInt *cone;
6755       PetscInt        coneSize, offA, offB, offnew, d;
6756 
6757       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6758       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6759       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6760       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6761       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6762       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6763       for (d = 0; d < dim; ++d) {
6764         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6765       }
6766     }
6767     /* Just Hex 2D */
6768     if (refiner == 2) {
6769       /* Cell vertices have the average of corner coordinates */
6770       for (c = cStart; c < cEnd; ++c) {
6771         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6772         PetscInt      *cone = PETSC_NULL;
6773         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6774 
6775         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6776         for (p = 0; p < closureSize*2; p += 2) {
6777           const PetscInt point = cone[p];
6778           if ((point >= vStart) && (point < vEnd)) {
6779             cone[coneSize++] = point;
6780           }
6781         }
6782         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6783         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6784         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6785         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6786         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6787         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6788         for (d = 0; d < dim; ++d) {
6789           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6790         }
6791         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6792       }
6793     }
6794     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6795     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6796     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6797     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6798     break;
6799   default:
6800     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6801   }
6802   PetscFunctionReturn(0);
6803 }
6804 
6805 #undef __FUNCT__
6806 #define __FUNCT__ "DMPlexCreateProcessSF"
6807 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6808 {
6809   PetscInt           numRoots, numLeaves, l;
6810   const PetscInt    *localPoints;
6811   const PetscSFNode *remotePoints;
6812   PetscInt          *localPointsNew;
6813   PetscSFNode       *remotePointsNew;
6814   PetscInt          *ranks, *ranksNew;
6815   PetscErrorCode     ierr;
6816 
6817   PetscFunctionBegin;
6818   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6819   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6820   for (l = 0; l < numLeaves; ++l) {
6821     ranks[l] = remotePoints[l].rank;
6822   }
6823   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6824   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6825   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6826   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6827   for (l = 0; l < numLeaves; ++l) {
6828     ranksNew[l]              = ranks[l];
6829     localPointsNew[l]        = l;
6830     remotePointsNew[l].index = 0;
6831     remotePointsNew[l].rank  = ranksNew[l];
6832   }
6833   ierr = PetscFree(ranks);CHKERRQ(ierr);
6834   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6835   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6836   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6837   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6838   PetscFunctionReturn(0);
6839 }
6840 
6841 #undef __FUNCT__
6842 #define __FUNCT__ "CellRefinerCreateSF"
6843 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6844 {
6845   PetscSF            sf, sfNew, sfProcess;
6846   IS                 processRanks;
6847   MPI_Datatype       depthType;
6848   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6849   const PetscInt    *localPoints, *neighbors;
6850   const PetscSFNode *remotePoints;
6851   PetscInt          *localPointsNew;
6852   PetscSFNode       *remotePointsNew;
6853   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6854   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6855   PetscErrorCode     ierr;
6856 
6857   PetscFunctionBegin;
6858   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6859   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6860   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6861   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6862   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6863   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6864   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6865   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6866   switch (refiner) {
6867   case 3:
6868     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6869     cMax = PetscMin(cEnd, cMax);
6870     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6871     fMax = PetscMin(fEnd, fMax);
6872   }
6873   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6874   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6875   /* Caculate size of new SF */
6876   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6877   if (numRoots < 0) PetscFunctionReturn(0);
6878   for (l = 0; l < numLeaves; ++l) {
6879     const PetscInt p = localPoints[l];
6880 
6881     switch (refiner) {
6882     case 1:
6883       /* Simplicial 2D */
6884       if ((p >= vStart) && (p < vEnd)) {
6885         /* Old vertices stay the same */
6886         ++numLeavesNew;
6887       } else if ((p >= fStart) && (p < fEnd)) {
6888         /* Old faces add new faces and vertex */
6889         numLeavesNew += 1 + 2;
6890       } else if ((p >= cStart) && (p < cEnd)) {
6891         /* Old cells add new cells and interior faces */
6892         numLeavesNew += 4 + 3;
6893       }
6894       break;
6895     case 2:
6896       /* Hex 2D */
6897       if ((p >= vStart) && (p < vEnd)) {
6898         /* Old vertices stay the same */
6899         ++numLeavesNew;
6900       } else if ((p >= fStart) && (p < fEnd)) {
6901         /* Old faces add new faces and vertex */
6902         numLeavesNew += 1 + 2;
6903       } else if ((p >= cStart) && (p < cEnd)) {
6904         /* Old cells add new cells and interior faces */
6905         numLeavesNew += 4 + 4;
6906       }
6907       break;
6908     default:
6909       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6910     }
6911   }
6912   /* Communicate depthSizes for each remote rank */
6913   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6914   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6915   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6916   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);
6917   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6918   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6919   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6920   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6921   for (n = 0; n < numNeighbors; ++n) {
6922     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6923   }
6924   depthSizeOld[depth]   = cMax;
6925   depthSizeOld[0]       = vMax;
6926   depthSizeOld[depth-1] = fMax;
6927   depthSizeOld[1]       = eMax;
6928   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6929   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6930   depthSizeOld[depth]   = cEnd - cStart;
6931   depthSizeOld[0]       = vEnd - vStart;
6932   depthSizeOld[depth-1] = fEnd - fStart;
6933   depthSizeOld[1]       = eEnd - eStart;
6934   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6935   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6936   for (n = 0; n < numNeighbors; ++n) {
6937     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6938   }
6939   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6940   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6941   /* Calculate new point SF */
6942   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6943   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6944   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6945   for (l = 0, m = 0; l < numLeaves; ++l) {
6946     PetscInt    p     = localPoints[l];
6947     PetscInt    rp    = remotePoints[l].index, n;
6948     PetscMPIInt rrank = remotePoints[l].rank;
6949 
6950     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6951     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6952     switch (refiner) {
6953     case 1:
6954       /* Simplicial 2D */
6955       if ((p >= vStart) && (p < vEnd)) {
6956         /* Old vertices stay the same */
6957         localPointsNew[m]        = vStartNew     + (p  - vStart);
6958         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6959         remotePointsNew[m].rank  = rrank;
6960         ++m;
6961       } else if ((p >= fStart) && (p < fEnd)) {
6962         /* Old faces add new faces and vertex */
6963         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6964         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6965         remotePointsNew[m].rank  = rrank;
6966         ++m;
6967         for (r = 0; r < 2; ++r, ++m) {
6968           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6969           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6970           remotePointsNew[m].rank  = rrank;
6971         }
6972       } else if ((p >= cStart) && (p < cEnd)) {
6973         /* Old cells add new cells and interior faces */
6974         for (r = 0; r < 4; ++r, ++m) {
6975           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6976           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6977           remotePointsNew[m].rank  = rrank;
6978         }
6979         for (r = 0; r < 3; ++r, ++m) {
6980           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6981           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6982           remotePointsNew[m].rank  = rrank;
6983         }
6984       }
6985       break;
6986     case 2:
6987       /* Hex 2D */
6988       if ((p >= vStart) && (p < vEnd)) {
6989         /* Old vertices stay the same */
6990         localPointsNew[m]        = vStartNew     + (p  - vStart);
6991         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6992         remotePointsNew[m].rank  = rrank;
6993         ++m;
6994       } else if ((p >= fStart) && (p < fEnd)) {
6995         /* Old faces add new faces and vertex */
6996         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6997         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6998         remotePointsNew[m].rank  = rrank;
6999         ++m;
7000         for (r = 0; r < 2; ++r, ++m) {
7001           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7002           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7003           remotePointsNew[m].rank  = rrank;
7004         }
7005       } else if ((p >= cStart) && (p < cEnd)) {
7006         /* Old cells add new cells and interior faces */
7007         for (r = 0; r < 4; ++r, ++m) {
7008           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7009           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7010           remotePointsNew[m].rank  = rrank;
7011         }
7012         for (r = 0; r < 4; ++r, ++m) {
7013           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7014           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7015           remotePointsNew[m].rank  = rrank;
7016         }
7017       }
7018       break;
7019     case 3:
7020       /* Hybrid simplicial 2D */
7021       if ((p >= vStart) && (p < vEnd)) {
7022         /* Old vertices stay the same */
7023         localPointsNew[m]        = vStartNew     + (p  - vStart);
7024         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7025         remotePointsNew[m].rank  = rrank;
7026         ++m;
7027       } else if ((p >= fStart) && (p < fMax)) {
7028         /* Old interior faces add new faces and vertex */
7029         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7030         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7031         remotePointsNew[m].rank  = rrank;
7032         ++m;
7033         for (r = 0; r < 2; ++r, ++m) {
7034           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7035           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7036           remotePointsNew[m].rank  = rrank;
7037         }
7038       } else if ((p >= fMax) && (p < fEnd)) {
7039         /* Old hybrid faces stay the same */
7040         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7041         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7042         remotePointsNew[m].rank  = rrank;
7043         ++m;
7044       } else if ((p >= cStart) && (p < cMax)) {
7045         /* Old interior cells add new cells and interior faces */
7046         for (r = 0; r < 4; ++r, ++m) {
7047           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7048           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7049           remotePointsNew[m].rank  = rrank;
7050         }
7051         for (r = 0; r < 3; ++r, ++m) {
7052           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7053           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7054           remotePointsNew[m].rank  = rrank;
7055         }
7056       } else if ((p >= cStart) && (p < cMax)) {
7057         /* Old hybrid cells add new cells and hybrid face */
7058         for (r = 0; r < 2; ++r, ++m) {
7059           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7060           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7061           remotePointsNew[m].rank  = rrank;
7062         }
7063         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7064         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]);
7065         remotePointsNew[m].rank  = rrank;
7066         ++m;
7067       }
7068       break;
7069     default:
7070       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7071     }
7072   }
7073   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7074   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7075   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7076   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7077   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7078   PetscFunctionReturn(0);
7079 }
7080 
7081 #undef __FUNCT__
7082 #define __FUNCT__ "CellRefinerCreateLabels"
7083 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7084 {
7085   PetscInt       numLabels, l;
7086   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7087   PetscErrorCode ierr;
7088 
7089   PetscFunctionBegin;
7090   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7091   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7092   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7093   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7094   cStartNew = 0;
7095   vStartNew = depthSize[2];
7096   fStartNew = depthSize[2] + depthSize[0];
7097   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7098   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7099   switch (refiner) {
7100   case 3:
7101     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7102     cMax = PetscMin(cEnd, cMax);
7103     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7104     fMax = PetscMin(fEnd, fMax);
7105   }
7106   for (l = 0; l < numLabels; ++l) {
7107     DMLabel         label, labelNew;
7108     const char     *lname;
7109     PetscBool       isDepth;
7110     IS              valueIS;
7111     const PetscInt *values;
7112     PetscInt        numValues, val;
7113 
7114     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7115     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7116     if (isDepth) continue;
7117     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7118     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7119     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7120     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7121     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7122     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7123     for (val = 0; val < numValues; ++val) {
7124       IS              pointIS;
7125       const PetscInt *points;
7126       PetscInt        numPoints, n;
7127 
7128       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7129       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7130       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7131       for (n = 0; n < numPoints; ++n) {
7132         const PetscInt p = points[n];
7133         switch (refiner) {
7134         case 1:
7135           /* Simplicial 2D */
7136           if ((p >= vStart) && (p < vEnd)) {
7137             /* Old vertices stay the same */
7138             newp = vStartNew + (p - vStart);
7139             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7140           } else if ((p >= fStart) && (p < fEnd)) {
7141             /* Old faces add new faces and vertex */
7142             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7143             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7144             for (r = 0; r < 2; ++r) {
7145               newp = fStartNew + (p - fStart)*2 + r;
7146               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7147             }
7148           } else if ((p >= cStart) && (p < cEnd)) {
7149             /* Old cells add new cells and interior faces */
7150             for (r = 0; r < 4; ++r) {
7151               newp = cStartNew + (p - cStart)*4 + r;
7152               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7153             }
7154             for (r = 0; r < 3; ++r) {
7155               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7156               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7157             }
7158           }
7159           break;
7160         case 2:
7161           /* Hex 2D */
7162           if ((p >= vStart) && (p < vEnd)) {
7163             /* Old vertices stay the same */
7164             newp = vStartNew + (p - vStart);
7165             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7166           } else if ((p >= fStart) && (p < fEnd)) {
7167             /* Old faces add new faces and vertex */
7168             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7169             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7170             for (r = 0; r < 2; ++r) {
7171               newp = fStartNew + (p - fStart)*2 + r;
7172               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7173             }
7174           } else if ((p >= cStart) && (p < cEnd)) {
7175             /* Old cells add new cells and interior faces and vertex */
7176             for (r = 0; r < 4; ++r) {
7177               newp = cStartNew + (p - cStart)*4 + r;
7178               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7179             }
7180             for (r = 0; r < 4; ++r) {
7181               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7182               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7183             }
7184             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7185             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7186           }
7187           break;
7188         case 3:
7189           /* Hybrid simplicial 2D */
7190           if ((p >= vStart) && (p < vEnd)) {
7191             /* Old vertices stay the same */
7192             newp = vStartNew + (p - vStart);
7193             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7194           } else if ((p >= fStart) && (p < fMax)) {
7195             /* Old interior faces add new faces and vertex */
7196             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7197             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7198             for (r = 0; r < 2; ++r) {
7199               newp = fStartNew + (p - fStart)*2 + r;
7200               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7201             }
7202           } else if ((p >= fMax) && (p < fEnd)) {
7203             /* Old hybrid faces stay the same */
7204             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7205             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7206           } else if ((p >= cStart) && (p < cMax)) {
7207             /* Old interior cells add new cells and interior faces */
7208             for (r = 0; r < 4; ++r) {
7209               newp = cStartNew + (p - cStart)*4 + r;
7210               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7211             }
7212             for (r = 0; r < 3; ++r) {
7213               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7214               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7215             }
7216           } else if ((p >= cMax) && (p < cEnd)) {
7217             /* Old hybrid cells add new cells and hybrid face */
7218             for (r = 0; r < 2; ++r) {
7219               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7220               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7221             }
7222             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7223             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7224           }
7225           break;
7226         default:
7227           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7228         }
7229       }
7230       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7231       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7232     }
7233     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7234     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7235     if (0) {
7236       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7237       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7238       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7239     }
7240   }
7241   PetscFunctionReturn(0);
7242 }
7243 
7244 #undef __FUNCT__
7245 #define __FUNCT__ "DMPlexRefine_Uniform"
7246 /* This will only work for interpolated meshes */
7247 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7248 {
7249   DM              rdm;
7250   PetscInt       *depthSize;
7251   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
7252   PetscErrorCode  ierr;
7253 
7254   PetscFunctionBegin;
7255   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7256   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7257   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7258   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7259   /* Calculate number of new points of each depth */
7260   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7261   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7262   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7263   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7264   /* Step 1: Set chart */
7265   for (d = 0; d <= depth; ++d) {
7266     pEnd += depthSize[d];
7267   }
7268   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7269   /* Step 2: Set cone/support sizes */
7270   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7271   /* Step 3: Setup refined DM */
7272   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7273   /* Step 4: Set cones and supports */
7274   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7275   /* Step 5: Stratify */
7276   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7277   /* Step 6: Set coordinates for vertices */
7278   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7279   /* Step 7: Create pointSF */
7280   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7281   /* Step 8: Create labels */
7282   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7283   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7284 
7285   *dmRefined = rdm;
7286 #if 0
7287   DM_Plex *mesh = (DM_Plex *) dm->data;
7288   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7289   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7290 
7291   PetscFunctionBegin;
7292   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7293   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7294   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7295   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7296   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7297 
7298   /* Count number of new cells which are normal and extra */
7299   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7300   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7301   for (c = cStart; c < cEnd2; ++c) {
7302     PetscInt n;
7303     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7304     newNumCellsNormal += n;
7305   }
7306   for (c = cEnd2; c < cEnd; ++c) {
7307     PetscInt n;
7308     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7309     newNumCellsExtra += n;
7310   }
7311   newNumCells = newNumCellsNormal + newNumCellsExtra;
7312   /* Count number of new vertices which are normal and extra */
7313   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7314   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7315   for (c = cStart; c < cEnd; ++c) {
7316     PetscInt *closure = PETSC_NULL;
7317     PetscInt  closureSize, numCorners = 0, p;
7318 
7319     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7320     for (p = 0; p < closureSize*2; p += 2) {
7321       const PetscInt point = closure[p];
7322       if ((point >= vStart) && (point < vEnd)) {
7323         closure[numCorners++] = point;
7324       }
7325     }
7326     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7327     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7328   }
7329   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7330   for (c = cEnd2; c < cEnd; ++c) {
7331     PetscInt *closure = PETSC_NULL;
7332     PetscInt  closureSize, numCorners = 0, p;
7333 
7334     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7335     for (p = 0; p < closureSize*2; p += 2) {
7336       const PetscInt point = closure[p];
7337       if ((point >= vStart) && (point < vEnd)) {
7338         closure[numCorners++] = point;
7339       }
7340     }
7341     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7342     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7343   } /* for */
7344   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7345   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
7346 
7347 #if 1
7348   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
7349   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
7350   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7351   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7352   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7353   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7354   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7355   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7356   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7357   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7358   ierr = PetscSynchronizedFlush(comm);
7359 #endif
7360 
7361   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7362   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7363   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7364   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7365   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7366   /* Set cone and support sizes for new normal cells */
7367   PetscInt newCell = 0;
7368   for (c = cStart; c < cEnd2; ++c) {
7369     PetscInt coneSize, n, i;
7370 
7371     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7372     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7373     for (i = 0; i < n; ++i, ++newCell) {
7374       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7375     }
7376 
7377     PetscInt *closure = PETSC_NULL;
7378     PetscInt  closureSize, numCorners = 0, p;
7379 
7380     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7381     for (p = 0; p < closureSize*2; p += 2) {
7382       const PetscInt point = closure[p];
7383       if ((point >= vStart) && (point < vEnd)) {
7384         closure[numCorners++] = point;
7385       }
7386     }
7387     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7388     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7389   }
7390 
7391   /* Reset current new cell value and loop over censored cells. */
7392   curNewCell = _orderNewMesh->cellsCensored().min();
7393   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7394   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7395     /* Set new cone and support sizes */
7396     cV.clear();
7397     sieve->cone(*c_iter, cV);
7398     const point_type* cone = cV.getPoints();
7399     const int coneSize = cV.getSize();
7400 
7401     const point_type* newCells;
7402     int numNewCells = 0;
7403     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7404 
7405     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7406       newSieve->setConeSize(curNewCell, coneSize);
7407       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7408         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7409       } /* for */
7410     } /* for */
7411   } /* for */
7412   newSieve->allocate();
7413 
7414   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7415 
7416   /* Create refined cells in new sieve. */
7417   curNewCell = _orderNewMesh->cellsNormal().min();
7418   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7419   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7420     cV.clear();
7421     sieve->cone(*c_iter, cV);
7422     const point_type *cone = cV.getPoints();
7423     const int coneSize = cV.getSize();
7424 
7425     const point_type* newCells;
7426     int numNewCells = 0;
7427     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7428 
7429     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7430       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7431     } /* for */
7432   } /* for */
7433   curNewCell = _orderNewMesh->cellsCensored().min();
7434   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7435   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7436     cV.clear();
7437     sieve->cone(*c_iter, cV);
7438     const point_type *cone = cV.getPoints();
7439     const int coneSize = cV.getSize();
7440 
7441     const point_type* newCells;
7442     int numNewCells = 0;
7443     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7444 
7445     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7446       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7447     } /* for */
7448   } /* for */
7449   newSieve->symmetrize();
7450 
7451   /* Set coordinates in refined mesh. */
7452   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7453   assert(!coordinates.isNull());
7454   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7455   assert(!newCoordinates.isNull());
7456 
7457   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7458   assert(vertices->size() > 0);
7459   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7460   assert(spaceDim > 0);
7461   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7462 
7463   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7464   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7465     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7466   } /* for */
7467   newCoordinates->allocatePoint();
7468 
7469   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7470   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7471     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7472     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7473   } /* for */
7474   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7475   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7476     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7477     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7478   } /* for */
7479 
7480   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7481 
7482   /* Create sensored depth */
7483   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7484   assert(!censoredLabel.isNull());
7485 
7486   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7487 
7488   newSieve->roots(depthVisitor);
7489   while (depthVisitor.isModified()) {
7490     /* FIX: Avoid the copy here somehow by fixing the traversal */
7491     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7492 
7493     depthVisitor.clear();
7494     newSieve->support(modifiedPoints, depthVisitor);
7495   } /* while */
7496   /* Stratify refined mesh */
7497   /* Calculate new point SF */
7498   _calcNewOverlap(newMesh, mesh, refiner);
7499   /* Calculate new labels */
7500   _createLabels(newMesh, mesh, refiner);
7501 #endif
7502   PetscFunctionReturn(0);
7503 }
7504 
7505 #undef __FUNCT__
7506 #define __FUNCT__ "DMPlexSetRefinementUniform"
7507 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7508 {
7509   DM_Plex *mesh = (DM_Plex *) dm->data;
7510 
7511   PetscFunctionBegin;
7512   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7513   mesh->refinementUniform = refinementUniform;
7514   PetscFunctionReturn(0);
7515 }
7516 
7517 #undef __FUNCT__
7518 #define __FUNCT__ "DMPlexGetRefinementUniform"
7519 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7520 {
7521   DM_Plex *mesh = (DM_Plex *) dm->data;
7522 
7523   PetscFunctionBegin;
7524   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7525   PetscValidPointer(refinementUniform,  2);
7526   *refinementUniform = mesh->refinementUniform;
7527   PetscFunctionReturn(0);
7528 }
7529 
7530 #undef __FUNCT__
7531 #define __FUNCT__ "DMPlexSetRefinementLimit"
7532 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7533 {
7534   DM_Plex *mesh = (DM_Plex *) dm->data;
7535 
7536   PetscFunctionBegin;
7537   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7538   mesh->refinementLimit = refinementLimit;
7539   PetscFunctionReturn(0);
7540 }
7541 
7542 #undef __FUNCT__
7543 #define __FUNCT__ "DMPlexGetRefinementLimit"
7544 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7545 {
7546   DM_Plex *mesh = (DM_Plex *) dm->data;
7547 
7548   PetscFunctionBegin;
7549   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7550   PetscValidPointer(refinementLimit,  2);
7551   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7552   *refinementLimit = mesh->refinementLimit;
7553   PetscFunctionReturn(0);
7554 }
7555 
7556 #undef __FUNCT__
7557 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7558 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7559 {
7560   PetscInt       dim, cStart, coneSize, cMax;
7561   PetscErrorCode ierr;
7562 
7563   PetscFunctionBegin;
7564   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7565   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7566   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7567   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7568   switch (dim) {
7569   case 2:
7570     switch (coneSize) {
7571     case 3:
7572       if (cMax >= 0) {
7573         *cellRefiner = 3; /* Hybrid */
7574       } else {
7575         *cellRefiner = 1; /* Triangular */
7576       }
7577       break;
7578     case 4:
7579       if (cMax >= 0) {
7580         *cellRefiner = 4; /* Hybrid */
7581       } else {
7582         *cellRefiner = 2; /* Quadrilateral */
7583       }
7584       break;
7585     default:
7586       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7587     }
7588     break;
7589   default:
7590     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7591   }
7592   PetscFunctionReturn(0);
7593 }
7594 
7595 #undef __FUNCT__
7596 #define __FUNCT__ "DMRefine_Plex"
7597 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7598 {
7599   PetscReal      refinementLimit;
7600   PetscInt       dim, cStart, cEnd;
7601   char           genname[1024], *name = PETSC_NULL;
7602   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7603   PetscErrorCode ierr;
7604 
7605   PetscFunctionBegin;
7606   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7607   if (isUniform) {
7608     CellRefiner cellRefiner;
7609 
7610     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7611     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7612     PetscFunctionReturn(0);
7613   }
7614   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7615   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7616   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7617   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7618   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7619   if (flg) {name = genname;}
7620   if (name) {
7621     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7622     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7623     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7624   }
7625   switch (dim) {
7626   case 2:
7627     if (!name || isTriangle) {
7628 #if defined(PETSC_HAVE_TRIANGLE)
7629       double  *maxVolumes;
7630       PetscInt c;
7631 
7632       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7633       for (c = 0; c < cEnd-cStart; ++c) {
7634         maxVolumes[c] = refinementLimit;
7635       }
7636       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7637 #else
7638       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7639 #endif
7640     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7641     break;
7642   case 3:
7643     if (!name || isCTetgen) {
7644 #if defined(PETSC_HAVE_CTETGEN)
7645       PetscReal *maxVolumes;
7646       PetscInt   c;
7647 
7648       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7649       for (c = 0; c < cEnd-cStart; ++c) {
7650         maxVolumes[c] = refinementLimit;
7651       }
7652       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7653 #else
7654       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7655 #endif
7656     } else if (isTetgen) {
7657 #if defined(PETSC_HAVE_TETGEN)
7658       double  *maxVolumes;
7659       PetscInt c;
7660 
7661       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7662       for (c = 0; c < cEnd-cStart; ++c) {
7663         maxVolumes[c] = refinementLimit;
7664       }
7665       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7666 #else
7667       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7668 #endif
7669     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7670     break;
7671   default:
7672     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7673   }
7674   PetscFunctionReturn(0);
7675 }
7676 
7677 #undef __FUNCT__
7678 #define __FUNCT__ "DMPlexGetDepth"
7679 /*@
7680   DMPlexGetDepth - get the number of strata
7681 
7682   Not Collective
7683 
7684   Input Parameters:
7685 . dm           - The DMPlex object
7686 
7687   Output Parameters:
7688 . depth - number of strata
7689 
7690   Level: developer
7691 
7692   Notes:
7693   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7694 
7695 .keywords: mesh, points
7696 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7697 @*/
7698 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7699 {
7700   PetscInt       d;
7701   PetscErrorCode ierr;
7702 
7703   PetscFunctionBegin;
7704   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7705   PetscValidPointer(depth, 2);
7706   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7707   *depth = d-1;
7708   PetscFunctionReturn(0);
7709 }
7710 
7711 #undef __FUNCT__
7712 #define __FUNCT__ "DMPlexGetDepthStratum"
7713 /*@
7714   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7715 
7716   Not Collective
7717 
7718   Input Parameters:
7719 + dm           - The DMPlex object
7720 - stratumValue - The requested depth
7721 
7722   Output Parameters:
7723 + start - The first point at this depth
7724 - end   - One beyond the last point at this depth
7725 
7726   Level: developer
7727 
7728 .keywords: mesh, points
7729 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7730 @*/
7731 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7732 {
7733   DM_Plex    *mesh = (DM_Plex *) dm->data;
7734   DMLabel        next = mesh->labels;
7735   PetscBool      flg  = PETSC_FALSE;
7736   PetscInt       depth;
7737   PetscErrorCode ierr;
7738 
7739   PetscFunctionBegin;
7740   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7741   if (stratumValue < 0) {
7742     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7743     PetscFunctionReturn(0);
7744   } else {
7745     PetscInt pStart, pEnd;
7746 
7747     if (start) {*start = 0;}
7748     if (end)   {*end   = 0;}
7749     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7750     if (pStart == pEnd) {PetscFunctionReturn(0);}
7751   }
7752   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7753   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7754   /* We should have a generic GetLabel() and a Label class */
7755   while (next) {
7756     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7757     if (flg) break;
7758     next = next->next;
7759   }
7760   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7761   depth = stratumValue;
7762   if ((depth < 0) || (depth >= next->numStrata)) {
7763     if (start) {*start = 0;}
7764     if (end)   {*end   = 0;}
7765   } else {
7766     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7767     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7768   }
7769   PetscFunctionReturn(0);
7770 }
7771 
7772 #undef __FUNCT__
7773 #define __FUNCT__ "DMPlexGetHeightStratum"
7774 /*@
7775   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7776 
7777   Not Collective
7778 
7779   Input Parameters:
7780 + dm           - The DMPlex object
7781 - stratumValue - The requested height
7782 
7783   Output Parameters:
7784 + start - The first point at this height
7785 - end   - One beyond the last point at this height
7786 
7787   Level: developer
7788 
7789 .keywords: mesh, points
7790 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7791 @*/
7792 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7793 {
7794   DM_Plex        *mesh = (DM_Plex *) dm->data;
7795   DMLabel        next = mesh->labels;
7796   PetscBool      flg  = PETSC_FALSE;
7797   PetscInt       depth;
7798   PetscErrorCode ierr;
7799 
7800   PetscFunctionBegin;
7801   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7802   if (stratumValue < 0) {
7803     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7804   } else {
7805     PetscInt pStart, pEnd;
7806 
7807     if (start) {*start = 0;}
7808     if (end)   {*end   = 0;}
7809     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7810     if (pStart == pEnd) {PetscFunctionReturn(0);}
7811   }
7812   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7813   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7814   /* We should have a generic GetLabel() and a Label class */
7815   while (next) {
7816     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7817     if (flg) break;
7818     next = next->next;
7819   }
7820   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7821   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7822   if ((depth < 0) || (depth >= next->numStrata)) {
7823     if (start) {*start = 0;}
7824     if (end)   {*end   = 0;}
7825   } else {
7826     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7827     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7828   }
7829   PetscFunctionReturn(0);
7830 }
7831 
7832 #undef __FUNCT__
7833 #define __FUNCT__ "DMPlexCreateSectionInitial"
7834 /* Set the number of dof on each point and separate by fields */
7835 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7836 {
7837   PetscInt      *numDofTot;
7838   PetscInt       pStart = 0, pEnd = 0;
7839   PetscInt       p, d, f;
7840   PetscErrorCode ierr;
7841 
7842   PetscFunctionBegin;
7843   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7844   for (d = 0; d <= dim; ++d) {
7845     numDofTot[d] = 0;
7846     for (f = 0; f < numFields; ++f) {
7847       numDofTot[d] += numDof[f*(dim+1)+d];
7848     }
7849   }
7850   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7851   if (numFields > 0) {
7852     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7853     if (numComp) {
7854       for (f = 0; f < numFields; ++f) {
7855         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7856       }
7857     }
7858   }
7859   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7860   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7861   for (d = 0; d <= dim; ++d) {
7862     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7863     for (p = pStart; p < pEnd; ++p) {
7864       for (f = 0; f < numFields; ++f) {
7865         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7866       }
7867       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7868     }
7869   }
7870   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7871   PetscFunctionReturn(0);
7872 }
7873 
7874 #undef __FUNCT__
7875 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7876 /* Set the number of dof on each point and separate by fields
7877    If constDof is PETSC_DETERMINE, constrain every dof on the point
7878 */
7879 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7880 {
7881   PetscInt       numFields;
7882   PetscInt       bc;
7883   PetscErrorCode ierr;
7884 
7885   PetscFunctionBegin;
7886   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7887   for (bc = 0; bc < numBC; ++bc) {
7888     PetscInt        field = 0;
7889     const PetscInt *idx;
7890     PetscInt        n, i;
7891 
7892     if (numFields) {field = bcField[bc];}
7893     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7894     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7895     for (i = 0; i < n; ++i) {
7896       const PetscInt p = idx[i];
7897       PetscInt       numConst = constDof;
7898 
7899       /* Constrain every dof on the point */
7900       if (numConst < 0) {
7901         if (numFields) {
7902           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7903         } else {
7904           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7905         }
7906       }
7907       if (numFields) {
7908         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7909       }
7910       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7911     }
7912     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7913   }
7914   PetscFunctionReturn(0);
7915 }
7916 
7917 #undef __FUNCT__
7918 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7919 /* Set the constrained indices on each point and separate by fields */
7920 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7921 {
7922   PetscInt      *maxConstraints;
7923   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7924   PetscErrorCode ierr;
7925 
7926   PetscFunctionBegin;
7927   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7928   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7929   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7930   for (f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
7931   for (p = pStart; p < pEnd; ++p) {
7932     PetscInt cdof;
7933 
7934     if (numFields) {
7935       for (f = 0; f < numFields; ++f) {
7936         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7937         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7938       }
7939     } else {
7940       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7941       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7942     }
7943   }
7944   for (f = 0; f < numFields; ++f) {
7945     maxConstraints[numFields] += maxConstraints[f];
7946   }
7947   if (maxConstraints[numFields]) {
7948     PetscInt *indices;
7949 
7950     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7951     for (p = pStart; p < pEnd; ++p) {
7952       PetscInt cdof, d;
7953 
7954       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7955       if (cdof) {
7956         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7957         if (numFields) {
7958           PetscInt numConst = 0, foff = 0;
7959 
7960           for (f = 0; f < numFields; ++f) {
7961             PetscInt cfdof, fdof;
7962 
7963             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7964             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7965             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7966             for (d = 0; d < cfdof; ++d) {
7967               indices[numConst+d] = d;
7968             }
7969             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7970             for (d = 0; d < cfdof; ++d) {
7971               indices[numConst+d] += foff;
7972             }
7973             numConst += cfdof;
7974             foff     += fdof;
7975           }
7976           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7977         } else {
7978           for (d = 0; d < cdof; ++d) {
7979             indices[d] = d;
7980           }
7981         }
7982         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7983       }
7984     }
7985     ierr = PetscFree(indices);CHKERRQ(ierr);
7986   }
7987   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7988   PetscFunctionReturn(0);
7989 }
7990 
7991 #undef __FUNCT__
7992 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7993 /* Set the constrained field indices on each point */
7994 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7995 {
7996   const PetscInt *points, *indices;
7997   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7998   PetscErrorCode  ierr;
7999 
8000   PetscFunctionBegin;
8001   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8002   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8003 
8004   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8005   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8006   if (!constraintIndices) {
8007     PetscInt *idx, i;
8008 
8009     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8010     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8011     for (i = 0; i < maxDof; ++i) {idx[i] = i;}
8012     for (p = 0; p < numPoints; ++p) {
8013       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8014     }
8015     ierr = PetscFree(idx);CHKERRQ(ierr);
8016   } else {
8017     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8018     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8019     for (p = 0; p < numPoints; ++p) {
8020       PetscInt fcdof;
8021 
8022       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8023       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);
8024       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8025     }
8026     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8027   }
8028   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8029   PetscFunctionReturn(0);
8030 }
8031 
8032 #undef __FUNCT__
8033 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8034 /* Set the constrained indices on each point and separate by fields */
8035 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8036 {
8037   PetscInt      *indices;
8038   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8039   PetscErrorCode ierr;
8040 
8041   PetscFunctionBegin;
8042   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8043   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8044   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8045   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8046   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8047   for (p = pStart; p < pEnd; ++p) {
8048     PetscInt cdof, d;
8049 
8050     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8051     if (cdof) {
8052       PetscInt numConst = 0, foff = 0;
8053 
8054       for (f = 0; f < numFields; ++f) {
8055         const PetscInt *fcind;
8056         PetscInt        fdof, fcdof;
8057 
8058         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8059         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8060         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8061         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8062         for (d = 0; d < fcdof; ++d) {
8063           indices[numConst+d] = fcind[d]+foff;
8064         }
8065         foff     += fdof;
8066         numConst += fcdof;
8067       }
8068       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8069       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8070     }
8071   }
8072   ierr = PetscFree(indices);CHKERRQ(ierr);
8073   PetscFunctionReturn(0);
8074 }
8075 
8076 #undef __FUNCT__
8077 #define __FUNCT__ "DMPlexCreateSection"
8078 /*@C
8079   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8080 
8081   Not Collective
8082 
8083   Input Parameters:
8084 + dm        - The DMPlex object
8085 . dim       - The spatial dimension of the problem
8086 . numFields - The number of fields in the problem
8087 . numComp   - An array of size numFields that holds the number of components for each field
8088 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8089 . numBC     - The number of boundary conditions
8090 . bcField   - An array of size numBC giving the field number for each boundry condition
8091 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8092 
8093   Output Parameter:
8094 . section - The PetscSection object
8095 
8096   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
8097   nubmer of dof for field 0 on each edge.
8098 
8099   Level: developer
8100 
8101 .keywords: mesh, elements
8102 .seealso: DMPlexCreate(), PetscSectionCreate()
8103 @*/
8104 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8105 {
8106   PetscErrorCode ierr;
8107 
8108   PetscFunctionBegin;
8109   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8110   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8111   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8112   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8113   {
8114     PetscBool view = PETSC_FALSE;
8115 
8116     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8117     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8118   }
8119   PetscFunctionReturn(0);
8120 }
8121 
8122 #undef __FUNCT__
8123 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8124 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8125 {
8126   PetscSection   section;
8127   PetscErrorCode ierr;
8128 
8129   PetscFunctionBegin;
8130   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8131   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8132   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8133   PetscFunctionReturn(0);
8134 }
8135 
8136 #undef __FUNCT__
8137 #define __FUNCT__ "DMPlexGetCoordinateSection"
8138 /*@
8139   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8140 
8141   Not Collective
8142 
8143   Input Parameter:
8144 . dm - The DMPlex object
8145 
8146   Output Parameter:
8147 . section - The PetscSection object
8148 
8149   Level: intermediate
8150 
8151 .keywords: mesh, coordinates
8152 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8153 @*/
8154 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8155 {
8156   DM             cdm;
8157   PetscErrorCode ierr;
8158 
8159   PetscFunctionBegin;
8160   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8161   PetscValidPointer(section, 2);
8162   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8163   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8164   PetscFunctionReturn(0);
8165 }
8166 
8167 #undef __FUNCT__
8168 #define __FUNCT__ "DMPlexSetCoordinateSection"
8169 /*@
8170   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8171 
8172   Not Collective
8173 
8174   Input Parameters:
8175 + dm      - The DMPlex object
8176 - section - The PetscSection object
8177 
8178   Level: intermediate
8179 
8180 .keywords: mesh, coordinates
8181 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8182 @*/
8183 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8184 {
8185   DM             cdm;
8186   PetscErrorCode ierr;
8187 
8188   PetscFunctionBegin;
8189   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8190   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8191   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8192   PetscFunctionReturn(0);
8193 }
8194 
8195 #undef __FUNCT__
8196 #define __FUNCT__ "DMPlexGetConeSection"
8197 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8198 {
8199   DM_Plex *mesh = (DM_Plex *) dm->data;
8200 
8201   PetscFunctionBegin;
8202   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8203   if (section) *section = mesh->coneSection;
8204   PetscFunctionReturn(0);
8205 }
8206 
8207 #undef __FUNCT__
8208 #define __FUNCT__ "DMPlexGetCones"
8209 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8210 {
8211   DM_Plex *mesh = (DM_Plex *) dm->data;
8212 
8213   PetscFunctionBegin;
8214   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8215   if (cones) *cones = mesh->cones;
8216   PetscFunctionReturn(0);
8217 }
8218 
8219 #undef __FUNCT__
8220 #define __FUNCT__ "DMPlexGetConeOrientations"
8221 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8222 {
8223   DM_Plex *mesh = (DM_Plex *) dm->data;
8224 
8225   PetscFunctionBegin;
8226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8227   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8228   PetscFunctionReturn(0);
8229 }
8230 
8231 #undef __FUNCT__
8232 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8233 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8234 {
8235   const PetscInt embedDim = 2;
8236   PetscReal      x = PetscRealPart(point[0]);
8237   PetscReal      y = PetscRealPart(point[1]);
8238   PetscReal      v0[2], J[4], invJ[4], detJ;
8239   PetscReal      xi, eta;
8240   PetscErrorCode ierr;
8241 
8242   PetscFunctionBegin;
8243   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8244   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8245   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8246 
8247   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
8248     *cell = c;
8249   } else {
8250     *cell = -1;
8251   }
8252   PetscFunctionReturn(0);
8253 }
8254 
8255 #undef __FUNCT__
8256 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8257 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8258 {
8259   PetscSection       coordSection;
8260   Vec                coordsLocal;
8261   const PetscScalar *coords;
8262   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8263   PetscReal          x         = PetscRealPart(point[0]);
8264   PetscReal          y         = PetscRealPart(point[1]);
8265   PetscInt           crossings = 0, f;
8266   PetscErrorCode     ierr;
8267 
8268   PetscFunctionBegin;
8269   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8270   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8271   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8272   for (f = 0; f < 4; ++f) {
8273     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8274     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8275     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8276     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8277     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8278     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8279     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8280     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8281     if ((cond1 || cond2)  && above) ++crossings;
8282   }
8283   if (crossings % 2) {
8284     *cell = c;
8285   } else {
8286     *cell = -1;
8287   }
8288   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8289   PetscFunctionReturn(0);
8290 }
8291 
8292 #undef __FUNCT__
8293 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8294 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8295 {
8296   const PetscInt embedDim = 3;
8297   PetscReal      v0[3], J[9], invJ[9], detJ;
8298   PetscReal      x = PetscRealPart(point[0]);
8299   PetscReal      y = PetscRealPart(point[1]);
8300   PetscReal      z = PetscRealPart(point[2]);
8301   PetscReal      xi, eta, zeta;
8302   PetscErrorCode ierr;
8303 
8304   PetscFunctionBegin;
8305   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8306   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8307   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8308   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8309 
8310   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
8311     *cell = c;
8312   } else {
8313     *cell = -1;
8314   }
8315   PetscFunctionReturn(0);
8316 }
8317 
8318 #undef __FUNCT__
8319 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8320 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8321 {
8322   PetscSection       coordSection;
8323   Vec                coordsLocal;
8324   const PetscScalar *coords;
8325   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8326                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8327   PetscBool          found     = PETSC_TRUE;
8328   PetscInt           f;
8329   PetscErrorCode     ierr;
8330 
8331   PetscFunctionBegin;
8332   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8333   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8334   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8335   for (f = 0; f < 6; ++f) {
8336     /* Check the point is under plane */
8337     /*   Get face normal */
8338     PetscReal v_i[3]    = {PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]),
8339                            PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]),
8340                            PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2])};
8341     PetscReal v_j[3]    = {PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]),
8342                            PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]),
8343                            PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2])};
8344     PetscReal normal[3] = {v_i[1]*v_j[2] - v_i[2]*v_j[1], v_i[2]*v_j[0] - v_i[0]*v_j[2], v_i[0]*v_j[1] - v_i[1]*v_j[0]};
8345     PetscReal pp[3]     = {PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]),
8346                            PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]),
8347                            PetscRealPart(coords[faces[f*4+0]*3+2] - point[2])};
8348     PetscReal dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8349     /* Check that projected point is in face (2D location problem) */
8350     if (dot < 0.0) {
8351       found = PETSC_FALSE;
8352       break;
8353     }
8354   }
8355   if (found) {
8356     *cell = c;
8357   } else {
8358     *cell = -1;
8359   }
8360   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8361   PetscFunctionReturn(0);
8362 }
8363 
8364 #undef __FUNCT__
8365 #define __FUNCT__ "DMLocatePoints_Plex"
8366 /*
8367  Need to implement using the guess
8368 */
8369 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8370 {
8371   PetscInt       cell = -1/*, guess = -1*/;
8372   PetscInt       bs, numPoints, p;
8373   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8374   PetscInt      *cells;
8375   PetscScalar   *a;
8376   PetscErrorCode ierr;
8377 
8378   PetscFunctionBegin;
8379   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8380   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8381   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8382   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8383   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8384   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8385   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8386   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);
8387   numPoints /= bs;
8388   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8389   for (p = 0; p < numPoints; ++p) {
8390     const PetscScalar *point = &a[p*bs];
8391 
8392     switch (dim) {
8393     case 2:
8394       for (c = cStart; c < cEnd; ++c) {
8395         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8396         switch (coneSize) {
8397         case 3:
8398           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8399           break;
8400         case 4:
8401           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8402           break;
8403         default:
8404           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8405         }
8406         if (cell >= 0) break;
8407       }
8408       break;
8409     case 3:
8410       for (c = cStart; c < cEnd; ++c) {
8411         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8412         switch (coneSize) {
8413         case 4:
8414           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8415           break;
8416         case 8:
8417           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8418           break;
8419         default:
8420           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8421         }
8422         if (cell >= 0) break;
8423       }
8424       break;
8425     default:
8426       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8427     }
8428     cells[p] = cell;
8429   }
8430   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8431   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8432   PetscFunctionReturn(0);
8433 }
8434 
8435 /******************************** FEM Support **********************************/
8436 
8437 #undef __FUNCT__
8438 #define __FUNCT__ "DMPlexVecGetClosure"
8439 /*@C
8440   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8441 
8442   Not collective
8443 
8444   Input Parameters:
8445 + dm - The DM
8446 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8447 . v - The local vector
8448 - point - The sieve point in the DM
8449 
8450   Output Parameters:
8451 + csize - The number of values in the closure, or PETSC_NULL
8452 - values - The array of values, which is a borrowed array and should not be freed
8453 
8454   Level: intermediate
8455 
8456 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8457 @*/
8458 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8459 {
8460   PetscScalar    *array, *vArray;
8461   PetscInt       *points = PETSC_NULL;
8462   PetscInt        offsets[32];
8463   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8464   PetscErrorCode  ierr;
8465 
8466   PetscFunctionBegin;
8467   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8468   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8469   if (!section) {
8470     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8471   }
8472   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8473   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8474   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8475   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8476   /* Compress out points not in the section */
8477   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8478   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8479     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8480       points[q*2]   = points[p];
8481       points[q*2+1] = points[p+1];
8482       ++q;
8483     }
8484   }
8485   numPoints = q;
8486   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8487     PetscInt dof, fdof;
8488 
8489     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8490     for (f = 0; f < numFields; ++f) {
8491       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8492       offsets[f+1] += fdof;
8493     }
8494     size += dof;
8495   }
8496   for (f = 1; f < numFields; ++f) {
8497     offsets[f+1] += offsets[f];
8498   }
8499   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8500   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8501   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8502   for (p = 0; p < numPoints*2; p += 2) {
8503     PetscInt     o = points[p+1];
8504     PetscInt     dof, off, d;
8505     PetscScalar *varr;
8506 
8507     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8508     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8509     varr = &vArray[off];
8510     if (numFields) {
8511       PetscInt fdof, foff, fcomp, f, c;
8512 
8513       for (f = 0, foff = 0; f < numFields; ++f) {
8514         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8515         if (o >= 0) {
8516           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8517             array[offsets[f]] = varr[foff+d];
8518           }
8519         } else {
8520           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8521           for (d = fdof/fcomp-1; d >= 0; --d) {
8522             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8523               array[offsets[f]] = varr[foff+d*fcomp+c];
8524             }
8525           }
8526         }
8527         foff += fdof;
8528       }
8529     } else {
8530       if (o >= 0) {
8531         for (d = 0; d < dof; ++d, ++offsets[0]) {
8532           array[offsets[0]] = varr[d];
8533         }
8534       } else {
8535         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8536           array[offsets[0]] = varr[d];
8537         }
8538       }
8539     }
8540   }
8541   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8542   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8543   if (csize) *csize = size;
8544   *values = array;
8545   PetscFunctionReturn(0);
8546 }
8547 
8548 #undef __FUNCT__
8549 #define __FUNCT__ "DMPlexVecRestoreClosure"
8550 /*@C
8551   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8552 
8553   Not collective
8554 
8555   Input Parameters:
8556 + dm - The DM
8557 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8558 . v - The local vector
8559 . point - The sieve point in the DM
8560 . csize - The number of values in the closure, or PETSC_NULL
8561 - values - The array of values, which is a borrowed array and should not be freed
8562 
8563   Level: intermediate
8564 
8565 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8566 @*/
8567 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8568 {
8569   PetscInt        size = 0;
8570   PetscErrorCode  ierr;
8571 
8572   PetscFunctionBegin;
8573   /* Should work without recalculating size */
8574   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8575   PetscFunctionReturn(0);
8576 }
8577 
8578 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8579 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8580 
8581 #undef __FUNCT__
8582 #define __FUNCT__ "updatePoint_private"
8583 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8584 {
8585   PetscInt        cdof;  /* The number of constraints on this point */
8586   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8587   PetscScalar    *a;
8588   PetscInt        off, cind = 0, k;
8589   PetscErrorCode  ierr;
8590 
8591   PetscFunctionBegin;
8592   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8593   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8594   a    = &array[off];
8595   if (!cdof || setBC) {
8596     if (orientation >= 0) {
8597       for (k = 0; k < dof; ++k) {
8598         fuse(&a[k], values[k]);
8599       }
8600     } else {
8601       for (k = 0; k < dof; ++k) {
8602         fuse(&a[k], values[dof-k-1]);
8603       }
8604     }
8605   } else {
8606     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8607     if (orientation >= 0) {
8608       for (k = 0; k < dof; ++k) {
8609         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8610         fuse(&a[k], values[k]);
8611       }
8612     } else {
8613       for (k = 0; k < dof; ++k) {
8614         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8615         fuse(&a[k], values[dof-k-1]);
8616       }
8617     }
8618   }
8619   PetscFunctionReturn(0);
8620 }
8621 
8622 #undef __FUNCT__
8623 #define __FUNCT__ "updatePointFields_private"
8624 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8625 {
8626   PetscScalar   *a;
8627   PetscInt       numFields, off, foff, f;
8628   PetscErrorCode ierr;
8629 
8630   PetscFunctionBegin;
8631   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8632   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8633   a    = &array[off];
8634   for (f = 0, foff = 0; f < numFields; ++f) {
8635     PetscInt        fdof, fcomp, fcdof;
8636     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8637     PetscInt        cind = 0, k, c;
8638 
8639     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8640     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8641     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8642     if (!fcdof || setBC) {
8643       if (orientation >= 0) {
8644         for (k = 0; k < fdof; ++k) {
8645           fuse(&a[foff+k], values[foffs[f]+k]);
8646         }
8647       } else {
8648         for (k = fdof/fcomp-1; k >= 0; --k) {
8649           for (c = 0; c < fcomp; ++c) {
8650             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8651           }
8652         }
8653       }
8654     } else {
8655       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8656       if (orientation >= 0) {
8657         for (k = 0; k < fdof; ++k) {
8658           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8659           fuse(&a[foff+k], values[foffs[f]+k]);
8660         }
8661       } else {
8662         for (k = fdof/fcomp-1; k >= 0; --k) {
8663           for (c = 0; c < fcomp; ++c) {
8664             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8665             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8666           }
8667         }
8668       }
8669     }
8670     foff     += fdof;
8671     foffs[f] += fdof;
8672   }
8673   PetscFunctionReturn(0);
8674 }
8675 
8676 #undef __FUNCT__
8677 #define __FUNCT__ "DMPlexVecSetClosure"
8678 /*@C
8679   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8680 
8681   Not collective
8682 
8683   Input Parameters:
8684 + dm - The DM
8685 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8686 . v - The local vector
8687 . point - The sieve point in the DM
8688 . values - The array of values, which is a borrowed array and should not be freed
8689 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8690 
8691   Level: intermediate
8692 
8693 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8694 @*/
8695 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8696 {
8697   PetscScalar    *array;
8698   PetscInt       *points = PETSC_NULL;
8699   PetscInt        offsets[32];
8700   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8701   PetscErrorCode  ierr;
8702 
8703   PetscFunctionBegin;
8704   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8705   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8706   if (!section) {
8707     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8708   }
8709   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8710   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8711   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8712   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8713   /* Compress out points not in the section */
8714   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8715   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8716     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8717       points[q*2]   = points[p];
8718       points[q*2+1] = points[p+1];
8719       ++q;
8720     }
8721   }
8722   numPoints = q;
8723   for (p = 0; p < numPoints*2; p += 2) {
8724     PetscInt fdof;
8725 
8726     for (f = 0; f < numFields; ++f) {
8727       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8728       offsets[f+1] += fdof;
8729     }
8730   }
8731   for (f = 1; f < numFields; ++f) {
8732     offsets[f+1] += offsets[f];
8733   }
8734   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8735   if (numFields) {
8736     switch (mode) {
8737     case INSERT_VALUES:
8738       for (p = 0; p < numPoints*2; p += 2) {
8739         PetscInt o = points[p+1];
8740         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8741       } break;
8742     case INSERT_ALL_VALUES:
8743       for (p = 0; p < numPoints*2; p += 2) {
8744         PetscInt o = points[p+1];
8745         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8746       } break;
8747     case ADD_VALUES:
8748       for (p = 0; p < numPoints*2; p += 2) {
8749         PetscInt o = points[p+1];
8750         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8751       } break;
8752     case ADD_ALL_VALUES:
8753       for (p = 0; p < numPoints*2; p += 2) {
8754         PetscInt o = points[p+1];
8755         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8756       } break;
8757     default:
8758       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8759     }
8760   } else {
8761     switch (mode) {
8762     case INSERT_VALUES:
8763       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8764         PetscInt o = points[p+1];
8765         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8766         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8767       } break;
8768     case INSERT_ALL_VALUES:
8769       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8770         PetscInt o = points[p+1];
8771         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8772         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8773       } break;
8774     case ADD_VALUES:
8775       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8776         PetscInt o = points[p+1];
8777         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8778         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8779       } break;
8780     case ADD_ALL_VALUES:
8781       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8782         PetscInt o = points[p+1];
8783         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8784         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8785       } break;
8786     default:
8787       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8788     }
8789   }
8790   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8791   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8792   PetscFunctionReturn(0);
8793 }
8794 
8795 #undef __FUNCT__
8796 #define __FUNCT__ "DMPlexPrintMatSetValues"
8797 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8798 {
8799   PetscMPIInt    rank;
8800   PetscInt       i, j;
8801   PetscErrorCode ierr;
8802 
8803   PetscFunctionBegin;
8804   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8805   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8806   for (i = 0; i < numIndices; i++) {
8807     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8808   }
8809   for (i = 0; i < numIndices; i++) {
8810     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8811     for (j = 0; j < numIndices; j++) {
8812 #if defined(PETSC_USE_COMPLEX)
8813       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8814 #else
8815       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8816 #endif
8817     }
8818     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8819   }
8820   PetscFunctionReturn(0);
8821 }
8822 
8823 #undef __FUNCT__
8824 #define __FUNCT__ "indicesPoint_private"
8825 /* . off - The global offset of this point */
8826 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8827 {
8828   PetscInt        cdof;  /* The number of constraints on this point */
8829   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8830   PetscInt        cind = 0, k;
8831   PetscErrorCode  ierr;
8832 
8833   PetscFunctionBegin;
8834   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8835   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8836   if (!cdof || setBC) {
8837     if (orientation >= 0) {
8838       for (k = 0; k < dof; ++k) {
8839         indices[k] = off+k;
8840       }
8841     } else {
8842       for (k = 0; k < dof; ++k) {
8843         indices[dof-k-1] = off+k;
8844       }
8845     }
8846   } else {
8847     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8848     if (orientation >= 0) {
8849       for (k = 0; k < dof; ++k) {
8850         if ((cind < cdof) && (k == cdofs[cind])) {
8851           /* Insert check for returning constrained indices */
8852           indices[k] = -(off+k+1);
8853           ++cind;
8854         } else {
8855           indices[k] = off+k-cind;
8856         }
8857       }
8858     } else {
8859       for (k = 0; k < dof; ++k) {
8860         if ((cind < cdof) && (k == cdofs[cind])) {
8861           /* Insert check for returning constrained indices */
8862           indices[dof-k-1] = -(off+k+1);
8863           ++cind;
8864         } else {
8865           indices[dof-k-1] = off+k-cind;
8866         }
8867       }
8868     }
8869   }
8870   PetscFunctionReturn(0);
8871 }
8872 
8873 #undef __FUNCT__
8874 #define __FUNCT__ "indicesPointFields_private"
8875 /* . off - The global offset of this point */
8876 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8877 {
8878   PetscInt       numFields, foff, f;
8879   PetscErrorCode ierr;
8880 
8881   PetscFunctionBegin;
8882   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8883   for (f = 0, foff = 0; f < numFields; ++f) {
8884     PetscInt        fdof, fcomp, cfdof;
8885     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8886     PetscInt        cind = 0, k, c;
8887 
8888     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8889     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8890     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8891     if (!cfdof || setBC) {
8892       if (orientation >= 0) {
8893         for (k = 0; k < fdof; ++k) {
8894           indices[foffs[f]+k] = off+foff+k;
8895         }
8896       } else {
8897         for (k = fdof/fcomp-1; k >= 0; --k) {
8898           for (c = 0; c < fcomp; ++c) {
8899             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8900           }
8901         }
8902       }
8903     } else {
8904       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8905       if (orientation >= 0) {
8906         for (k = 0; k < fdof; ++k) {
8907           if ((cind < cfdof) && (k == fcdofs[cind])) {
8908             indices[foffs[f]+k] = -(off+foff+k+1);
8909             ++cind;
8910           } else {
8911             indices[foffs[f]+k] = off+foff+k-cind;
8912           }
8913         }
8914       } else {
8915         for (k = fdof/fcomp-1; k >= 0; --k) {
8916           for (c = 0; c < fcomp; ++c) {
8917             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8918               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8919               ++cind;
8920             } else {
8921               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8922             }
8923           }
8924         }
8925       }
8926     }
8927     foff     += fdof - cfdof;
8928     foffs[f] += fdof;
8929   }
8930   PetscFunctionReturn(0);
8931 }
8932 
8933 #undef __FUNCT__
8934 #define __FUNCT__ "DMPlexMatSetClosure"
8935 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8936 {
8937   DM_Plex     *mesh   = (DM_Plex *) dm->data;
8938   PetscInt       *points = PETSC_NULL;
8939   PetscInt       *indices;
8940   PetscInt        offsets[32];
8941   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8942   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8943   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8944   PetscErrorCode  ierr;
8945 
8946   PetscFunctionBegin;
8947   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8948   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8949   if (useDefault) {
8950     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8951   }
8952   if (useGlobalDefault) {
8953     if (useDefault) {
8954       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8955     } else {
8956       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8957     }
8958   }
8959   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8960   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8961   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8962   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8963   /* Compress out points not in the section */
8964   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8965   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8966     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8967       points[q*2]   = points[p];
8968       points[q*2+1] = points[p+1];
8969       ++q;
8970     }
8971   }
8972   numPoints = q;
8973   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8974     PetscInt fdof;
8975 
8976     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8977     for (f = 0; f < numFields; ++f) {
8978       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8979       offsets[f+1] += fdof;
8980     }
8981     numIndices += dof;
8982   }
8983   for (f = 1; f < numFields; ++f) {
8984     offsets[f+1] += offsets[f];
8985   }
8986   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8987   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8988   if (numFields) {
8989     for (p = 0; p < numPoints*2; p += 2) {
8990       PetscInt o = points[p+1];
8991       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8992       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8993     }
8994   } else {
8995     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8996       PetscInt o = points[p+1];
8997       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8998       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8999     }
9000   }
9001   if (useGlobalDefault && !useDefault) {
9002     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9003   }
9004   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
9005   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9006   if (ierr) {
9007     PetscMPIInt    rank;
9008     PetscErrorCode ierr2;
9009 
9010     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
9011     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9012     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9013     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9014     CHKERRQ(ierr);
9015   }
9016   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9017   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9018   PetscFunctionReturn(0);
9019 }
9020 
9021 #undef __FUNCT__
9022 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9023 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9024 {
9025   PetscSection       coordSection;
9026   Vec                coordinates;
9027   const PetscScalar *coords;
9028   const PetscInt     dim = 2;
9029   PetscInt           d, f;
9030   PetscErrorCode     ierr;
9031 
9032   PetscFunctionBegin;
9033   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9034   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9035   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9036   if (v0) {
9037     for (d = 0; d < dim; d++) {
9038       v0[d] = PetscRealPart(coords[d]);
9039     }
9040   }
9041   if (J) {
9042     for (d = 0; d < dim; d++) {
9043       for (f = 0; f < dim; f++) {
9044         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9045       }
9046     }
9047     *detJ = J[0]*J[3] - J[1]*J[2];
9048 #if 0
9049     if (detJ < 0.0) {
9050       const PetscReal xLength = mesh->periodicity[0];
9051 
9052       if (xLength != 0.0) {
9053         PetscReal v0x = coords[0*dim+0];
9054 
9055         if (v0x == 0.0) {
9056           v0x = v0[0] = xLength;
9057         }
9058         for (f = 0; f < dim; f++) {
9059           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9060 
9061           J[0*dim+f] = 0.5*(px - v0x);
9062         }
9063       }
9064       detJ = J[0]*J[3] - J[1]*J[2];
9065     }
9066 #endif
9067     PetscLogFlops(8.0 + 3.0);
9068   }
9069   if (invJ) {
9070     const PetscReal invDet = 1.0/(*detJ);
9071 
9072     invJ[0] =  invDet*J[3];
9073     invJ[1] = -invDet*J[1];
9074     invJ[2] = -invDet*J[2];
9075     invJ[3] =  invDet*J[0];
9076     PetscLogFlops(5.0);
9077   }
9078   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9079   PetscFunctionReturn(0);
9080 }
9081 
9082 #undef __FUNCT__
9083 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9084 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9085 {
9086   PetscSection       coordSection;
9087   Vec                coordinates;
9088   const PetscScalar *coords;
9089   const PetscInt     dim = 2;
9090   PetscInt           d, f;
9091   PetscErrorCode     ierr;
9092 
9093   PetscFunctionBegin;
9094   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9095   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9096   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9097   if (v0) {
9098     for (d = 0; d < dim; d++) {
9099       v0[d] = PetscRealPart(coords[d]);
9100     }
9101   }
9102   if (J) {
9103     for (d = 0; d < dim; d++) {
9104       for (f = 0; f < dim; f++) {
9105         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9106       }
9107     }
9108     *detJ = J[0]*J[3] - J[1]*J[2];
9109     PetscLogFlops(8.0 + 3.0);
9110   }
9111   if (invJ) {
9112     const PetscReal invDet = 1.0/(*detJ);
9113 
9114     invJ[0] =  invDet*J[3];
9115     invJ[1] = -invDet*J[1];
9116     invJ[2] = -invDet*J[2];
9117     invJ[3] =  invDet*J[0];
9118     PetscLogFlops(5.0);
9119   }
9120   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9121   PetscFunctionReturn(0);
9122 }
9123 
9124 #undef __FUNCT__
9125 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9126 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9127 {
9128   PetscSection       coordSection;
9129   Vec                coordinates;
9130   const PetscScalar *coords;
9131   const PetscInt     dim = 3;
9132   PetscInt           d, f;
9133   PetscErrorCode     ierr;
9134 
9135   PetscFunctionBegin;
9136   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9137   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9138   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9139   if (v0) {
9140     for (d = 0; d < dim; d++) {
9141       v0[d] = PetscRealPart(coords[d]);
9142     }
9143   }
9144   if (J) {
9145     for (d = 0; d < dim; d++) {
9146       for (f = 0; f < dim; f++) {
9147         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9148       }
9149     }
9150     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9151     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9152              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9153              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9154     PetscLogFlops(18.0 + 12.0);
9155   }
9156   if (invJ) {
9157     const PetscReal invDet = 1.0/(*detJ);
9158 
9159     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9160     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9161     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9162     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9163     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9164     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9165     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9166     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9167     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9168     PetscLogFlops(37.0);
9169   }
9170   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9171   PetscFunctionReturn(0);
9172 }
9173 
9174 #undef __FUNCT__
9175 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9176 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9177 {
9178   PetscSection       coordSection;
9179   Vec                coordinates;
9180   const PetscScalar *coords;
9181   const PetscInt     dim = 3;
9182   PetscInt           d;
9183   PetscErrorCode     ierr;
9184 
9185   PetscFunctionBegin;
9186   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9187   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9188   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9189   if (v0) {
9190     for (d = 0; d < dim; d++) {
9191       v0[d] = PetscRealPart(coords[d]);
9192     }
9193   }
9194   if (J) {
9195     for (d = 0; d < dim; d++) {
9196       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9197       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9198       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9199     }
9200     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9201              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9202              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9203     PetscLogFlops(18.0 + 12.0);
9204   }
9205   if (invJ) {
9206     const PetscReal invDet = -1.0/(*detJ);
9207 
9208     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9209     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9210     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9211     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9212     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9213     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9214     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9215     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9216     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9217     PetscLogFlops(37.0);
9218   }
9219   *detJ *= 8.0;
9220   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9221   PetscFunctionReturn(0);
9222 }
9223 
9224 #undef __FUNCT__
9225 #define __FUNCT__ "DMPlexComputeCellGeometry"
9226 /*@C
9227   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9228 
9229   Collective on DM
9230 
9231   Input Arguments:
9232 + dm   - the DM
9233 - cell - the cell
9234 
9235   Output Arguments:
9236 + v0   - the translation part of this affine transform
9237 . J    - the Jacobian of the transform to the reference element
9238 . invJ - the inverse of the Jacobian
9239 - detJ - the Jacobian determinant
9240 
9241   Level: advanced
9242 
9243 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9244 @*/
9245 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9246 {
9247   PetscInt       dim, coneSize;
9248   PetscErrorCode ierr;
9249 
9250   PetscFunctionBegin;
9251   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9252   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9253   switch (dim) {
9254   case 2:
9255     switch (coneSize) {
9256     case 3:
9257       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9258       break;
9259     case 4:
9260       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9261       break;
9262     default:
9263       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9264     }
9265     break;
9266   case 3:
9267     switch (coneSize) {
9268     case 4:
9269       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9270       break;
9271     case 8:
9272       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9273       break;
9274     default:
9275       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9276     }
9277     break;
9278   default:
9279     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9280   }
9281   PetscFunctionReturn(0);
9282 }
9283 
9284 #undef __FUNCT__
9285 #define __FUNCT__ "DMPlexGetFaceOrientation"
9286 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9287 {
9288   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9289   PetscBool      posOrient = PETSC_FALSE;
9290   const PetscInt debug     = 0;
9291   PetscInt       cellDim, faceSize, f;
9292   PetscErrorCode ierr;
9293 
9294   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9295   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9296 
9297   if (cellDim == numCorners-1) {
9298     /* Simplices */
9299     faceSize  = numCorners-1;
9300     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9301   } else if (cellDim == 1 && numCorners == 3) {
9302     /* Quadratic line */
9303     faceSize  = 1;
9304     posOrient = PETSC_TRUE;
9305   } else if (cellDim == 2 && numCorners == 4) {
9306     /* Quads */
9307     faceSize  = 2;
9308     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9309       posOrient = PETSC_TRUE;
9310     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9311       posOrient = PETSC_TRUE;
9312     } else {
9313       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9314         posOrient = PETSC_FALSE;
9315       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9316     }
9317   } else if (cellDim == 2 && numCorners == 6) {
9318     /* Quadratic triangle (I hate this) */
9319     /* Edges are determined by the first 2 vertices (corners of edges) */
9320     const PetscInt faceSizeTri = 3;
9321     PetscInt  sortedIndices[3], i, iFace;
9322     PetscBool found = PETSC_FALSE;
9323     PetscInt  faceVerticesTriSorted[9] = {
9324       0, 3,  4, /* bottom */
9325       1, 4,  5, /* right */
9326       2, 3,  5, /* left */
9327     };
9328     PetscInt  faceVerticesTri[9] = {
9329       0, 3,  4, /* bottom */
9330       1, 4,  5, /* right */
9331       2, 5,  3, /* left */
9332     };
9333 
9334     faceSize = faceSizeTri;
9335     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9336     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9337     for (iFace = 0; iFace < 3; ++iFace) {
9338       const PetscInt ii = iFace*faceSizeTri;
9339       PetscInt       fVertex, cVertex;
9340 
9341       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9342           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9343         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9344           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9345             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9346               faceVertices[fVertex] = origVertices[cVertex];
9347               break;
9348             }
9349           }
9350         }
9351         found = PETSC_TRUE;
9352         break;
9353       }
9354     }
9355     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9356     if (posOriented) {*posOriented = PETSC_TRUE;}
9357     PetscFunctionReturn(0);
9358   } else if (cellDim == 2 && numCorners == 9) {
9359     /* Quadratic quad (I hate this) */
9360     /* Edges are determined by the first 2 vertices (corners of edges) */
9361     const PetscInt faceSizeQuad = 3;
9362     PetscInt  sortedIndices[3], i, iFace;
9363     PetscBool found = PETSC_FALSE;
9364     PetscInt  faceVerticesQuadSorted[12] = {
9365       0, 1,  4, /* bottom */
9366       1, 2,  5, /* right */
9367       2, 3,  6, /* top */
9368       0, 3,  7, /* left */
9369     };
9370     PetscInt  faceVerticesQuad[12] = {
9371       0, 1,  4, /* bottom */
9372       1, 2,  5, /* right */
9373       2, 3,  6, /* top */
9374       3, 0,  7, /* left */
9375     };
9376 
9377     faceSize = faceSizeQuad;
9378     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9379     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9380     for (iFace = 0; iFace < 4; ++iFace) {
9381       const PetscInt ii = iFace*faceSizeQuad;
9382       PetscInt       fVertex, cVertex;
9383 
9384       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9385           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9386         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9387           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9388             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9389               faceVertices[fVertex] = origVertices[cVertex];
9390               break;
9391             }
9392           }
9393         }
9394         found = PETSC_TRUE;
9395         break;
9396       }
9397     }
9398     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9399     if (posOriented) {*posOriented = PETSC_TRUE;}
9400     PetscFunctionReturn(0);
9401   } else if (cellDim == 3 && numCorners == 8) {
9402     /* Hexes
9403        A hex is two oriented quads with the normal of the first
9404        pointing up at the second.
9405 
9406           7---6
9407          /|  /|
9408         4---5 |
9409         | 3-|-2
9410         |/  |/
9411         0---1
9412 
9413         Faces are determined by the first 4 vertices (corners of faces) */
9414     const PetscInt faceSizeHex = 4;
9415     PetscInt  sortedIndices[4], i, iFace;
9416     PetscBool found = PETSC_FALSE;
9417     PetscInt faceVerticesHexSorted[24] = {
9418       0, 1, 2, 3,  /* bottom */
9419       4, 5, 6, 7,  /* top */
9420       0, 1, 4, 5,  /* front */
9421       1, 2, 5, 6,  /* right */
9422       2, 3, 6, 7,  /* back */
9423       0, 3, 4, 7,  /* left */
9424     };
9425     PetscInt faceVerticesHex[24] = {
9426       3, 2, 1, 0,  /* bottom */
9427       4, 5, 6, 7,  /* top */
9428       0, 1, 5, 4,  /* front */
9429       1, 2, 6, 5,  /* right */
9430       2, 3, 7, 6,  /* back */
9431       3, 0, 4, 7,  /* left */
9432     };
9433 
9434     faceSize = faceSizeHex;
9435     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9436     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9437     for (iFace = 0; iFace < 6; ++iFace) {
9438       const PetscInt ii = iFace*faceSizeHex;
9439       PetscInt       fVertex, cVertex;
9440 
9441       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9442           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9443           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9444           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9445         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9446           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9447             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9448               faceVertices[fVertex] = origVertices[cVertex];
9449               break;
9450             }
9451           }
9452         }
9453         found = PETSC_TRUE;
9454         break;
9455       }
9456     }
9457     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9458     if (posOriented) {*posOriented = PETSC_TRUE;}
9459     PetscFunctionReturn(0);
9460   } else if (cellDim == 3 && numCorners == 10) {
9461     /* Quadratic tet */
9462     /* Faces are determined by the first 3 vertices (corners of faces) */
9463     const PetscInt faceSizeTet = 6;
9464     PetscInt  sortedIndices[6], i, iFace;
9465     PetscBool found = PETSC_FALSE;
9466     PetscInt faceVerticesTetSorted[24] = {
9467       0, 1, 2,  6, 7, 8, /* bottom */
9468       0, 3, 4,  6, 7, 9,  /* front */
9469       1, 4, 5,  7, 8, 9,  /* right */
9470       2, 3, 5,  6, 8, 9,  /* left */
9471     };
9472     PetscInt faceVerticesTet[24] = {
9473       0, 1, 2,  6, 7, 8, /* bottom */
9474       0, 4, 3,  6, 7, 9,  /* front */
9475       1, 5, 4,  7, 8, 9,  /* right */
9476       2, 3, 5,  8, 6, 9,  /* left */
9477     };
9478 
9479     faceSize = faceSizeTet;
9480     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9481     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9482     for (iFace=0; iFace < 4; ++iFace) {
9483       const PetscInt ii = iFace*faceSizeTet;
9484       PetscInt       fVertex, cVertex;
9485 
9486       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9487           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9488           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9489           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9490         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9491           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9492             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9493               faceVertices[fVertex] = origVertices[cVertex];
9494               break;
9495             }
9496           }
9497         }
9498         found = PETSC_TRUE;
9499         break;
9500       }
9501     }
9502     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9503     if (posOriented) {*posOriented = PETSC_TRUE;}
9504     PetscFunctionReturn(0);
9505   } else if (cellDim == 3 && numCorners == 27) {
9506     /* Quadratic hexes (I hate this)
9507        A hex is two oriented quads with the normal of the first
9508        pointing up at the second.
9509 
9510          7---6
9511         /|  /|
9512        4---5 |
9513        | 3-|-2
9514        |/  |/
9515        0---1
9516 
9517        Faces are determined by the first 4 vertices (corners of faces) */
9518     const PetscInt faceSizeQuadHex = 9;
9519     PetscInt  sortedIndices[9], i, iFace;
9520     PetscBool found = PETSC_FALSE;
9521     PetscInt faceVerticesQuadHexSorted[54] = {
9522       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9523       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9524       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9525       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9526       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9527       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9528     };
9529     PetscInt faceVerticesQuadHex[54] = {
9530       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9531       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9532       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9533       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9534       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9535       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9536     };
9537 
9538     faceSize = faceSizeQuadHex;
9539     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9540     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9541     for (iFace = 0; iFace < 6; ++iFace) {
9542       const PetscInt ii = iFace*faceSizeQuadHex;
9543       PetscInt       fVertex, cVertex;
9544 
9545       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9546           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9547           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9548           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9549         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9550           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9551             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9552               faceVertices[fVertex] = origVertices[cVertex];
9553               break;
9554             }
9555           }
9556         }
9557         found = PETSC_TRUE;
9558         break;
9559       }
9560     }
9561     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9562     if (posOriented) {*posOriented = PETSC_TRUE;}
9563     PetscFunctionReturn(0);
9564   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9565   if (!posOrient) {
9566     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9567     for (f = 0; f < faceSize; ++f) {
9568       faceVertices[f] = origVertices[faceSize-1 - f];
9569     }
9570   } else {
9571     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9572     for (f = 0; f < faceSize; ++f) {
9573       faceVertices[f] = origVertices[f];
9574     }
9575   }
9576   if (posOriented) {*posOriented = posOrient;}
9577   PetscFunctionReturn(0);
9578 }
9579 
9580 #undef __FUNCT__
9581 #define __FUNCT__ "DMPlexGetOrientedFace"
9582 /*
9583     Given a cell and a face, as a set of vertices,
9584       return the oriented face, as a set of vertices, in faceVertices
9585     The orientation is such that the face normal points out of the cell
9586 */
9587 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9588 {
9589   const PetscInt *cone = PETSC_NULL;
9590   PetscInt        coneSize, v, f, v2;
9591   PetscInt        oppositeVertex = -1;
9592   PetscErrorCode  ierr;
9593 
9594   PetscFunctionBegin;
9595   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9596   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9597   for (v = 0, v2 = 0; v < coneSize; ++v) {
9598     PetscBool found  = PETSC_FALSE;
9599 
9600     for (f = 0; f < faceSize; ++f) {
9601       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9602     }
9603     if (found) {
9604       indices[v2]      = v;
9605       origVertices[v2] = cone[v];
9606       ++v2;
9607     } else {
9608       oppositeVertex = v;
9609     }
9610   }
9611   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9612   PetscFunctionReturn(0);
9613 }
9614 
9615 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9616 {
9617   switch (i) {
9618   case 0:
9619     switch (j) {
9620     case 0: return 0;
9621     case 1:
9622       switch (k) {
9623       case 0: return 0;
9624       case 1: return 0;
9625       case 2: return 1;
9626       }
9627     case 2:
9628       switch (k) {
9629       case 0: return 0;
9630       case 1: return -1;
9631       case 2: return 0;
9632       }
9633     }
9634   case 1:
9635     switch (j) {
9636     case 0:
9637       switch (k) {
9638       case 0: return 0;
9639       case 1: return 0;
9640       case 2: return -1;
9641       }
9642     case 1: return 0;
9643     case 2:
9644       switch (k) {
9645       case 0: return 1;
9646       case 1: return 0;
9647       case 2: return 0;
9648       }
9649     }
9650   case 2:
9651     switch (j) {
9652     case 0:
9653       switch (k) {
9654       case 0: return 0;
9655       case 1: return 1;
9656       case 2: return 0;
9657       }
9658     case 1:
9659       switch (k) {
9660       case 0: return -1;
9661       case 1: return 0;
9662       case 2: return 0;
9663       }
9664     case 2: return 0;
9665     }
9666   }
9667   return 0;
9668 }
9669 
9670 #undef __FUNCT__
9671 #define __FUNCT__ "DMPlexCreateRigidBody"
9672 /*@C
9673   DMPlexCreateRigidBody - create rigid body modes from coordinates
9674 
9675   Collective on DM
9676 
9677   Input Arguments:
9678 + dm - the DM
9679 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9680 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9681 
9682   Output Argument:
9683 . sp - the null space
9684 
9685   Note: This is necessary to take account of Dirichlet conditions on the displacements
9686 
9687   Level: advanced
9688 
9689 .seealso: MatNullSpaceCreate()
9690 @*/
9691 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9692 {
9693   MPI_Comm       comm = ((PetscObject) dm)->comm;
9694   Vec            coordinates, localMode, mode[6];
9695   PetscSection   coordSection;
9696   PetscScalar   *coords;
9697   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9698   PetscErrorCode ierr;
9699 
9700   PetscFunctionBegin;
9701   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9702   if (dim == 1) {
9703     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9704     PetscFunctionReturn(0);
9705   }
9706   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9707   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9708   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9709   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9710   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9711   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9712   m    = (dim*(dim+1))/2;
9713   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9714   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9715   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9716   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9717   /* Assume P1 */
9718   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9719   for (d = 0; d < dim; ++d) {
9720     PetscScalar values[3] = {0.0, 0.0, 0.0};
9721 
9722     values[d] = 1.0;
9723     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9724     for (v = vStart; v < vEnd; ++v) {
9725       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9726     }
9727     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9728     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9729   }
9730   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9731   for (d = dim; d < dim*(dim+1)/2; ++d) {
9732     PetscInt i, j, k = dim > 2 ? d - dim : d;
9733 
9734     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9735     for (v = vStart; v < vEnd; ++v) {
9736       PetscScalar values[3] = {0.0, 0.0, 0.0};
9737       PetscInt    off;
9738 
9739       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9740       for (i = 0; i < dim; ++i) {
9741         for (j = 0; j < dim; ++j) {
9742           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9743         }
9744       }
9745       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9746     }
9747     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9748     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9749   }
9750   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9751   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9752   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9753   /* Orthonormalize system */
9754   for (i = dim; i < m; ++i) {
9755     PetscScalar dots[6];
9756 
9757     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9758     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9759     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9760     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9761   }
9762   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9763   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9764   PetscFunctionReturn(0);
9765 }
9766 
9767 #undef __FUNCT__
9768 #define __FUNCT__ "DMPlexGetHybridBounds"
9769 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9770 {
9771   DM_Plex       *mesh = (DM_Plex *) dm->data;
9772   PetscInt       dim;
9773   PetscErrorCode ierr;
9774 
9775   PetscFunctionBegin;
9776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9777   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9778   if (cMax) *cMax = mesh->hybridPointMax[dim];
9779   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9780   if (eMax) *eMax = mesh->hybridPointMax[1];
9781   if (vMax) *vMax = mesh->hybridPointMax[0];
9782   PetscFunctionReturn(0);
9783 }
9784 
9785 #undef __FUNCT__
9786 #define __FUNCT__ "DMPlexSetHybridBounds"
9787 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9788 {
9789   DM_Plex       *mesh = (DM_Plex *) dm->data;
9790   PetscInt       dim;
9791   PetscErrorCode ierr;
9792 
9793   PetscFunctionBegin;
9794   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9795   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9796   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9797   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9798   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9799   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9800   PetscFunctionReturn(0);
9801 }
9802 
9803 #undef __FUNCT__
9804 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9805 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9806 {
9807   DM_Plex *mesh = (DM_Plex *) dm->data;
9808 
9809   PetscFunctionBegin;
9810   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9811   PetscValidPointer(cellHeight, 2);
9812   *cellHeight = mesh->vtkCellHeight;
9813   PetscFunctionReturn(0);
9814 }
9815 
9816 #undef __FUNCT__
9817 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9818 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9819 {
9820   DM_Plex *mesh = (DM_Plex *) dm->data;
9821 
9822   PetscFunctionBegin;
9823   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9824   mesh->vtkCellHeight = cellHeight;
9825   PetscFunctionReturn(0);
9826 }
9827 
9828 #undef __FUNCT__
9829 #define __FUNCT__ "DMPlexInsertFace_Private"
9830 /*
9831   DMPlexInsertFace_Private - Puts a face into the mesh
9832 
9833   Not collective
9834 
9835   Input Parameters:
9836   + dm              - The DMPlex
9837   . numFaceVertex   - The number of vertices in the face
9838   . faceVertices    - The vertices in the face for dm
9839   . subfaceVertices - The vertices in the face for subdm
9840   . numCorners      - The number of vertices in the cell
9841   . cell            - A cell in dm containing the face
9842   . subcell         - A cell in subdm containing the face
9843   . firstFace       - First face in the mesh
9844   - newFacePoint    - Next face in the mesh
9845 
9846   Output Parameters:
9847   . newFacePoint - Contains next face point number on input, updated on output
9848 
9849   Level: developer
9850 */
9851 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)
9852 {
9853   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9854   DM_Plex     *submesh = (DM_Plex *) subdm->data;
9855   const PetscInt *faces;
9856   PetscInt        numFaces, coneSize;
9857   PetscErrorCode  ierr;
9858 
9859   PetscFunctionBegin;
9860   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9861   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9862 #if 0
9863   /* Cannot use this because support() has not been constructed yet */
9864   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9865 #else
9866   {
9867     PetscInt f;
9868 
9869     numFaces = 0;
9870     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
9871     for (f = firstFace; f < *newFacePoint; ++f) {
9872       PetscInt dof, off, d;
9873 
9874       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9875       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9876       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9877       for (d = 0; d < dof; ++d) {
9878         const PetscInt p = submesh->cones[off+d];
9879         PetscInt       v;
9880 
9881         for (v = 0; v < numFaceVertices; ++v) {
9882           if (subfaceVertices[v] == p) break;
9883         }
9884         if (v == numFaceVertices) break;
9885       }
9886       if (d == dof) {
9887         numFaces = 1;
9888         ((PetscInt *) faces)[0] = f;
9889       }
9890     }
9891   }
9892 #endif
9893   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
9894   else if (numFaces == 1) {
9895     /* Add the other cell neighbor for this face */
9896     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
9897   } else {
9898     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
9899     PetscBool posOriented;
9900 
9901     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9902     origVertices = &orientedVertices[numFaceVertices];
9903     indices      = &orientedVertices[numFaceVertices*2];
9904     orientedSubVertices = &orientedVertices[numFaceVertices*3];
9905     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
9906     /* TODO: I know that routine should return a permutation, not the indices */
9907     for (v = 0; v < numFaceVertices; ++v) {
9908       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
9909       for (ov = 0; ov < numFaceVertices; ++ov) {
9910         if (orientedVertices[ov] == vertex) {
9911           orientedSubVertices[ov] = subvertex;
9912           break;
9913         }
9914       }
9915       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
9916     }
9917     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
9918     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
9919     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9920     ++(*newFacePoint);
9921   }
9922   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9923   PetscFunctionReturn(0);
9924 }
9925 
9926 #undef __FUNCT__
9927 #define __FUNCT__ "DMPlexCreateSubmesh"
9928 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
9929 {
9930   MPI_Comm        comm = ((PetscObject) dm)->comm;
9931   DM_Plex     *submesh;
9932   PetscBool       boundaryFaces = PETSC_FALSE;
9933   PetscSection    coordSection, subCoordSection;
9934   Vec             coordinates, subCoordinates;
9935   PetscScalar    *coords, *subCoords;
9936   IS              labelIS;
9937   const PetscInt *subVertices;
9938   PetscInt       *subVerticesActive, *tmpPoints;
9939   PetscInt       *subCells = PETSC_NULL;
9940   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
9941   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
9942   PetscInt        dim; /* Right now, do not specify dimension */
9943   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
9944   PetscErrorCode  ierr;
9945 
9946   PetscFunctionBegin;
9947   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9948   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9949   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9950   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
9951   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9952   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9953   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9954   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9955   subface = &face[maxConeSize];
9956   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
9957   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
9958   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
9959   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
9960   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
9961   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
9962   maxSubCells = numSubVertices;
9963   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
9964   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
9965   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
9966   for (v = 0; v < numSubVertices; ++v) {
9967     const PetscInt vertex = subVertices[v];
9968     PetscInt *star = PETSC_NULL;
9969     PetscInt  starSize, numCells = 0;
9970 
9971     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9972     for (p = 0; p < starSize*2; p += 2) {
9973       const PetscInt point = star[p];
9974       if ((point >= cStart) && (point < cEnd)) {
9975         star[numCells++] = point;
9976       }
9977     }
9978     numOldSubCells = numSubCells;
9979     for (c = 0; c < numCells; ++c) {
9980       const PetscInt cell    = star[c];
9981       PetscInt      *closure = PETSC_NULL;
9982       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9983       PetscInt       cellLoc;
9984 
9985       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9986       if (cellLoc >= 0) continue;
9987       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9988       for (p = 0; p < closureSize*2; p += 2) {
9989         const PetscInt point = closure[p];
9990         if ((point >= vStart) && (point < vEnd)) {
9991           closure[numCorners++] = point;
9992         }
9993       }
9994       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9995       for (corner = 0; corner < numCorners; ++corner) {
9996         const PetscInt cellVertex = closure[corner];
9997         PetscInt       subVertex;
9998 
9999         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
10000         if (subVertex >= 0) { /* contains submesh vertex */
10001           for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10002           if (i == faceSize) {
10003             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
10004             face[faceSize]    = cellVertex;
10005             subface[faceSize] = subVertex;
10006             ++faceSize;
10007           }
10008         }
10009       }
10010       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10011       if (faceSize >= nFV) {
10012         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10013         if (numSubCells >= maxSubCells) {
10014           PetscInt *tmpCells;
10015           maxSubCells *= 2;
10016           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
10017           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
10018           ierr = PetscFree(subCells);CHKERRQ(ierr);
10019           subCells = tmpCells;
10020         }
10021         /* TOOD: Maybe overestimate then squeeze out empty faces */
10022         if (faceSize > nFV) {
10023           /* TODO: This is tricky. Maybe just add all faces */
10024           numSubFaces++;
10025         } else {
10026           numSubFaces++;
10027         }
10028         for (f = 0; f < faceSize; ++f) {
10029           subVerticesActive[subface[f]] = 1;
10030         }
10031         subCells[numSubCells++] = cell;
10032       }
10033     }
10034     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10035     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
10036   }
10037   /* Pick out active subvertices */
10038   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
10039     if (subVerticesActive[v]) {
10040       subVerticesActive[numSubVerticesActive++] = subVertices[v];
10041     }
10042   }
10043   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
10044   /* Set cone sizes */
10045   firstSubVertex = numSubCells;
10046   firstSubFace   = numSubCells+numSubVerticesActive;
10047   newFacePoint   = firstSubFace;
10048   for (c = 0; c < numSubCells; ++c) {
10049     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
10050   }
10051   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
10052     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
10053   }
10054   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
10055   /* Create face cones */
10056   for (c = 0; c < numSubCells; ++c) {
10057     const PetscInt cell    = subCells[c];
10058     PetscInt      *closure = PETSC_NULL;
10059     PetscInt       closureSize, numCorners = 0, faceSize = 0;
10060 
10061     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10062     for (p = 0; p < closureSize*2; p += 2) {
10063       const PetscInt point = closure[p];
10064       if ((point >= vStart) && (point < vEnd)) {
10065         closure[numCorners++] = point;
10066       }
10067     }
10068     for (corner = 0; corner < numCorners; ++corner) {
10069       const PetscInt cellVertex = closure[corner];
10070       PetscInt       subVertex;
10071 
10072       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
10073       if (subVertex >= 0) { /* contains submesh vertex */
10074         for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10075         if (i == faceSize) {
10076           face[faceSize]    = cellVertex;
10077           subface[faceSize] = numSubCells+subVertex;
10078           ++faceSize;
10079         }
10080       }
10081     }
10082     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10083     if (faceSize >= nFV) {
10084       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10085       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
10086       /*   We have to take all the faces, and discard those in the interior */
10087       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
10088 #if 0
10089       /* This object just calls insert on each face that comes from subsets() */
10090       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
10091       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
10092       PointArray                          faceVec(face->begin(), face->end());
10093 
10094       subsets(faceVec, nFV, inserter);
10095 #endif
10096       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10097     }
10098   }
10099   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
10100   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
10101   /* Build coordinates */
10102   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10103   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10104   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
10105   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10106   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10107     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10108   }
10109   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10110   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10111   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
10112   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10113   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10114   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10115   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10116   for (v = 0; v < numSubVerticesActive; ++v) {
10117     const PetscInt vertex    = subVerticesActive[v];
10118     const PetscInt subVertex = firstSubVertex+v;
10119     PetscInt dof, off, sdof, soff;
10120 
10121     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10122     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10123     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10124     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10125     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10126     for (d = 0; d < dof; ++d) {
10127       subCoords[soff+d] = coords[off+d];
10128     }
10129   }
10130   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10131   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10132   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
10133   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10134 
10135   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
10136   /* Create map from submesh points to original mesh points */
10137   submesh = (DM_Plex *) (*subdm)->data;
10138   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10139   for (c = 0; c < numSubCells; ++c) {
10140     tmpPoints[c] = subCells[c];
10141   }
10142   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
10143     tmpPoints[v] = subVerticesActive[v-numSubCells];
10144   }
10145   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
10146 
10147   ierr = PetscFree(subCells);CHKERRQ(ierr);
10148   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10149   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10150   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10151   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10152   PetscFunctionReturn(0);
10153 }
10154 
10155 #undef __FUNCT__
10156 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10157 /* We can easily have a form that takes an IS instead */
10158 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10159 {
10160   PetscSection   section, globalSection;
10161   PetscInt      *numbers, p;
10162   PetscErrorCode ierr;
10163 
10164   PetscFunctionBegin;
10165   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10166   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10167   for (p = pStart; p < pEnd; ++p) {
10168     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10169   }
10170   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10171   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10172   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10173   for (p = pStart; p < pEnd; ++p) {
10174     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10175   }
10176   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10177   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10178   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10179   PetscFunctionReturn(0);
10180 }
10181 
10182 #undef __FUNCT__
10183 #define __FUNCT__ "DMPlexGetCellNumbering"
10184 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10185 {
10186   DM_Plex    *mesh = (DM_Plex *) dm->data;
10187   PetscInt       cellHeight, cStart, cEnd, cMax;
10188   PetscErrorCode ierr;
10189 
10190   PetscFunctionBegin;
10191   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10192   if (!mesh->globalCellNumbers) {
10193     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10194     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10195     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10196     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10197     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10198   }
10199   *globalCellNumbers = mesh->globalCellNumbers;
10200   PetscFunctionReturn(0);
10201 }
10202 
10203 #undef __FUNCT__
10204 #define __FUNCT__ "DMPlexGetVertexNumbering"
10205 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10206 {
10207   DM_Plex    *mesh = (DM_Plex *) dm->data;
10208   PetscInt       vStart, vEnd, vMax;
10209   PetscErrorCode ierr;
10210 
10211   PetscFunctionBegin;
10212   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10213   if (!mesh->globalVertexNumbers) {
10214     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10215     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10216     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10217     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10218   }
10219   *globalVertexNumbers = mesh->globalVertexNumbers;
10220   PetscFunctionReturn(0);
10221 }
10222 
10223 #undef __FUNCT__
10224 #define __FUNCT__ "DMPlexGetSubpointMap"
10225 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10226 {
10227   DM_Plex *mesh = (DM_Plex *) dm->data;
10228 
10229   PetscFunctionBegin;
10230   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10231   PetscValidPointer(subpointMap, 2);
10232   *subpointMap = mesh->subpointMap;
10233   PetscFunctionReturn(0);
10234 }
10235 
10236 #undef __FUNCT__
10237 #define __FUNCT__ "DMPlexSetSubpointMap"
10238 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10239 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10240 {
10241   DM_Plex *mesh = (DM_Plex *) dm->data;
10242 
10243   PetscFunctionBegin;
10244   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10245   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10246   mesh->subpointMap = subpointMap;
10247   PetscFunctionReturn(0);
10248 }
10249 
10250 #undef __FUNCT__
10251 #define __FUNCT__ "DMPlexGetScale"
10252 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10253 {
10254   DM_Plex *mesh = (DM_Plex *) dm->data;
10255 
10256   PetscFunctionBegin;
10257   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10258   PetscValidPointer(scale, 3);
10259   *scale = mesh->scale[unit];
10260   PetscFunctionReturn(0);
10261 }
10262 
10263 #undef __FUNCT__
10264 #define __FUNCT__ "DMPlexSetScale"
10265 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10266 {
10267   DM_Plex *mesh = (DM_Plex *) dm->data;
10268 
10269   PetscFunctionBegin;
10270   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10271   mesh->scale[unit] = scale;
10272   PetscFunctionReturn(0);
10273 }
10274 
10275 
10276 /*******************************************************************************
10277 This should be in a separate Discretization object, but I am not sure how to lay
10278 it out yet, so I am stuffing things here while I experiment.
10279 *******************************************************************************/
10280 #undef __FUNCT__
10281 #define __FUNCT__ "DMPlexSetFEMIntegration"
10282 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10283                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10284                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10285                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10286                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10287                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10288                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10289                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10290                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10291                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10292                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10293                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10294                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10295                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10296                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10297                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10298                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10299 {
10300   DM_Plex *mesh = (DM_Plex *) dm->data;
10301 
10302   PetscFunctionBegin;
10303   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10304   mesh->integrateResidualFEM       = integrateResidualFEM;
10305   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10306   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10307   PetscFunctionReturn(0);
10308 }
10309 
10310 #undef __FUNCT__
10311 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10312 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10313 {
10314   Vec            coordinates;
10315   PetscSection   section, cSection;
10316   PetscInt       dim, vStart, vEnd, v, c, d;
10317   PetscScalar   *values, *cArray;
10318   PetscReal     *coords;
10319   PetscErrorCode ierr;
10320 
10321   PetscFunctionBegin;
10322   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10323   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10324   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10325   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10326   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10327   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10328   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10329   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10330   for (v = vStart; v < vEnd; ++v) {
10331     PetscInt dof, off;
10332 
10333     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10334     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10335     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10336     for (d = 0; d < dof; ++d) {
10337       coords[d] = PetscRealPart(cArray[off+d]);
10338     }
10339     for (c = 0; c < numComp; ++c) {
10340       values[c] = (*funcs[c])(coords);
10341     }
10342     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10343   }
10344   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10345   /* Temporary, must be replaced by a projection on the finite element basis */
10346   {
10347     PetscInt eStart = 0, eEnd = 0, e, depth;
10348 
10349     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10350     --depth;
10351     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10352     for (e = eStart; e < eEnd; ++e) {
10353       const PetscInt *cone = PETSC_NULL;
10354       PetscInt        coneSize, d;
10355       PetscScalar    *coordsA, *coordsB;
10356 
10357       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10358       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10359       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10360       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10361       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10362       for (d = 0; d < dim; ++d) {
10363         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10364       }
10365       for (c = 0; c < numComp; ++c) {
10366         values[c] = (*funcs[c])(coords);
10367       }
10368       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10369     }
10370   }
10371 
10372   ierr = PetscFree(coords);CHKERRQ(ierr);
10373   ierr = PetscFree(values);CHKERRQ(ierr);
10374 #if 0
10375   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10376   PetscReal      detJ;
10377 
10378   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10379   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10380   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10381 
10382   for (PetscInt c = cStart; c < cEnd; ++c) {
10383     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10384     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10385     const int                          oSize   = pV.getSize();
10386     int                                v       = 0;
10387 
10388     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10389     for (PetscInt cl = 0; cl < oSize; ++cl) {
10390       const PetscInt fDim;
10391 
10392       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10393       if (pointDim) {
10394         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10395           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10396         }
10397       }
10398     }
10399     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10400     pV.clear();
10401   }
10402   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10403   ierr = PetscFree(values);CHKERRQ(ierr);
10404 #endif
10405   PetscFunctionReturn(0);
10406 }
10407 
10408 #undef __FUNCT__
10409 #define __FUNCT__ "DMPlexProjectFunction"
10410 /*@C
10411   DMPlexProjectFunction - This projects the given function into the function space provided.
10412 
10413   Input Parameters:
10414 + dm      - The DM
10415 . numComp - The number of components (functions)
10416 . funcs   - The coordinate functions to evaluate
10417 - mode    - The insertion mode for values
10418 
10419   Output Parameter:
10420 . X - vector
10421 
10422   Level: developer
10423 
10424   Note:
10425   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10426   We will eventually fix it.
10427 
10428 ,seealso: DMPlexComputeL2Diff()
10429 */
10430 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10431 {
10432   Vec            localX;
10433   PetscErrorCode ierr;
10434 
10435   PetscFunctionBegin;
10436   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10437   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10438   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10439   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10440   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10441   PetscFunctionReturn(0);
10442 }
10443 
10444 #undef __FUNCT__
10445 #define __FUNCT__ "DMPlexComputeL2Diff"
10446 /*@C
10447   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10448 
10449   Input Parameters:
10450 + dm    - The DM
10451 . quad  - The PetscQuadrature object for each field
10452 . funcs - The functions to evaluate for each field component
10453 - X     - The coefficient vector u_h
10454 
10455   Output Parameter:
10456 . diff - The diff ||u - u_h||_2
10457 
10458   Level: developer
10459 
10460 .seealso: DMPlexProjectFunction()
10461 */
10462 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10463 {
10464   const PetscInt   debug = 0;
10465   PetscSection     section;
10466   Vec              localX;
10467   PetscReal       *coords, *v0, *J, *invJ, detJ;
10468   PetscReal        localDiff = 0.0;
10469   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10470   PetscErrorCode   ierr;
10471 
10472   PetscFunctionBegin;
10473   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10474   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10475   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10476   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10477   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10478   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10479   for (field = 0; field < numFields; ++field) {
10480     numComponents += quad[field].numComponents;
10481   }
10482   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10483   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10484   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10485   for (c = cStart; c < cEnd; ++c) {
10486     const PetscScalar *x;
10487     PetscReal          elemDiff = 0.0;
10488 
10489     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10490     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10491     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10492 
10493     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10494       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10495       const PetscReal *quadPoints    = quad[field].quadPoints;
10496       const PetscReal *quadWeights   = quad[field].quadWeights;
10497       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10498       const PetscInt   numBasisComps = quad[field].numComponents;
10499       const PetscReal *basis         = quad[field].basis;
10500       PetscInt         q, d, e, fc, f;
10501 
10502       if (debug) {
10503         char title[1024];
10504         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10505         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10506       }
10507       for (q = 0; q < numQuadPoints; ++q) {
10508         for (d = 0; d < dim; d++) {
10509           coords[d] = v0[d];
10510           for (e = 0; e < dim; e++) {
10511             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10512           }
10513         }
10514         for (fc = 0; fc < numBasisComps; ++fc) {
10515           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10516           PetscReal       interpolant = 0.0;
10517           for (f = 0; f < numBasisFuncs; ++f) {
10518             const PetscInt fidx = f*numBasisComps+fc;
10519             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10520           }
10521           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10522           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10523         }
10524       }
10525       comp        += numBasisComps;
10526       fieldOffset += numBasisFuncs*numBasisComps;
10527     }
10528     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10529     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10530     localDiff += elemDiff;
10531   }
10532   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10533   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10534   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10535   *diff = PetscSqrtReal(*diff);
10536   PetscFunctionReturn(0);
10537 }
10538 
10539 #undef __FUNCT__
10540 #define __FUNCT__ "DMPlexComputeResidualFEM"
10541 /*@
10542   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10543 
10544   Input Parameters:
10545 + dm - The mesh
10546 . X  - Local input vector
10547 - user - The user context
10548 
10549   Output Parameter:
10550 . F  - Local output vector
10551 
10552   Note:
10553   The second member of the user context must be an FEMContext.
10554 
10555   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10556   like a GPU, or vectorize on a multicore machine.
10557 
10558 .seealso: DMPlexComputeJacobianActionFEM()
10559 */
10560 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10561 {
10562   DM_Plex      *mesh = (DM_Plex *) dm->data;
10563   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10564   PetscQuadrature *quad = fem->quad;
10565   PetscSection     section;
10566   PetscReal       *v0, *J, *invJ, *detJ;
10567   PetscScalar     *elemVec, *u;
10568   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10569   PetscInt         cellDof = 0, numComponents = 0;
10570   PetscErrorCode   ierr;
10571 
10572   PetscFunctionBegin;
10573   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10574   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10575   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10576   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10577   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10578   numCells = cEnd - cStart;
10579   for (field = 0; field < numFields; ++field) {
10580     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10581     numComponents += quad[field].numComponents;
10582   }
10583   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10584   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10585   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);
10586   for (c = cStart; c < cEnd; ++c) {
10587     const PetscScalar *x;
10588     PetscInt           i;
10589 
10590     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10591     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10592     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10593 
10594     for (i = 0; i < cellDof; ++i) {
10595       u[c*cellDof+i] = x[i];
10596     }
10597     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10598   }
10599   for (field = 0; field < numFields; ++field) {
10600     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10601     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10602     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10603     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10604     /* Conforming batches */
10605     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10606     PetscInt numBlocks  = 1;
10607     PetscInt batchSize  = numBlocks * blockSize;
10608     PetscInt numBatches = numBatchesTmp;
10609     PetscInt numChunks  = numCells / (numBatches*batchSize);
10610     /* Remainder */
10611     PetscInt numRemainder = numCells % (numBatches * batchSize);
10612     PetscInt offset       = numCells - numRemainder;
10613 
10614     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10615     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10616                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10617   }
10618   for (c = cStart; c < cEnd; ++c) {
10619     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10620     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10621   }
10622   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10623   if (mesh->printFEM) {
10624     PetscMPIInt rank, numProcs;
10625     PetscInt    p;
10626 
10627     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10628     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10629     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10630     for (p = 0; p < numProcs; ++p) {
10631       if (p == rank) {
10632         Vec f;
10633 
10634         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10635         ierr = VecCopy(F, f);CHKERRQ(ierr);
10636         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10637         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10638         ierr = VecDestroy(&f);CHKERRQ(ierr);
10639         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10640       }
10641       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10642     }
10643   }
10644   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10645   PetscFunctionReturn(0);
10646 }
10647 
10648 #undef __FUNCT__
10649 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10650 /*@C
10651   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10652 
10653   Input Parameters:
10654 + dm - The mesh
10655 . J  - The Jacobian shell matrix
10656 . X  - Local input vector
10657 - user - The user context
10658 
10659   Output Parameter:
10660 . F  - Local output vector
10661 
10662   Note:
10663   The second member of the user context must be an FEMContext.
10664 
10665   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10666   like a GPU, or vectorize on a multicore machine.
10667 
10668 .seealso: DMPlexComputeResidualFEM()
10669 */
10670 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10671 {
10672   DM_Plex      *mesh = (DM_Plex *) dm->data;
10673   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10674   PetscQuadrature *quad = fem->quad;
10675   PetscSection     section;
10676   JacActionCtx    *jctx;
10677   PetscReal       *v0, *J, *invJ, *detJ;
10678   PetscScalar     *elemVec, *u, *a;
10679   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10680   PetscInt         cellDof = 0;
10681   PetscErrorCode   ierr;
10682 
10683   PetscFunctionBegin;
10684   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10685   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10686   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10687   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10688   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10689   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10690   numCells = cEnd - cStart;
10691   for (field = 0; field < numFields; ++field) {
10692     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10693   }
10694   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10695   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);
10696   for (c = cStart; c < cEnd; ++c) {
10697     const PetscScalar *x;
10698     PetscInt           i;
10699 
10700     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10701     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10702     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10703     for (i = 0; i < cellDof; ++i) {
10704       u[c*cellDof+i] = x[i];
10705     }
10706     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10707     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10708     for (i = 0; i < cellDof; ++i) {
10709       a[c*cellDof+i] = x[i];
10710     }
10711     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10712   }
10713   for (field = 0; field < numFields; ++field) {
10714     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10715     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10716     /* Conforming batches */
10717     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10718     PetscInt numBlocks  = 1;
10719     PetscInt batchSize  = numBlocks * blockSize;
10720     PetscInt numBatches = numBatchesTmp;
10721     PetscInt numChunks  = numCells / (numBatches*batchSize);
10722     /* Remainder */
10723     PetscInt numRemainder = numCells % (numBatches * batchSize);
10724     PetscInt offset       = numCells - numRemainder;
10725 
10726     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);
10727     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],
10728                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10729   }
10730   for (c = cStart; c < cEnd; ++c) {
10731     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10732     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10733   }
10734   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10735   if (mesh->printFEM) {
10736     PetscMPIInt rank, numProcs;
10737     PetscInt    p;
10738 
10739     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10740     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10741     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10742     for (p = 0; p < numProcs; ++p) {
10743       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10744       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10745     }
10746   }
10747   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10748   PetscFunctionReturn(0);
10749 }
10750 
10751 #undef __FUNCT__
10752 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10753 /*@
10754   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10755 
10756   Input Parameters:
10757 + dm - The mesh
10758 . X  - Local input vector
10759 - user - The user context
10760 
10761   Output Parameter:
10762 . Jac  - Jacobian matrix
10763 
10764   Note:
10765   The second member of the user context must be an FEMContext.
10766 
10767   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10768   like a GPU, or vectorize on a multicore machine.
10769 
10770 .seealso: FormFunctionLocal()
10771 */
10772 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10773 {
10774   DM_Plex      *mesh = (DM_Plex *) dm->data;
10775   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10776   PetscQuadrature *quad = fem->quad;
10777   PetscSection     section;
10778   PetscReal       *v0, *J, *invJ, *detJ;
10779   PetscScalar     *elemMat, *u;
10780   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10781   PetscInt         cellDof = 0, numComponents = 0;
10782   PetscBool        isShell;
10783   PetscErrorCode   ierr;
10784 
10785   PetscFunctionBegin;
10786   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);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     numComponents += quad[field].numComponents;
10795   }
10796   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10797   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10798   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);
10799   for (c = cStart; c < cEnd; ++c) {
10800     const PetscScalar *x;
10801     PetscInt           i;
10802 
10803     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10804     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10805     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10806 
10807     for (i = 0; i < cellDof; ++i) {
10808       u[c*cellDof+i] = x[i];
10809     }
10810     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10811   }
10812   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10813   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10814     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10815     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10816     PetscInt       fieldJ;
10817 
10818     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10819       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10820       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10821       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10822       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10823       /* Conforming batches */
10824       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10825       PetscInt numBlocks  = 1;
10826       PetscInt batchSize  = numBlocks * blockSize;
10827       PetscInt numBatches = numBatchesTmp;
10828       PetscInt numChunks  = numCells / (numBatches*batchSize);
10829       /* Remainder */
10830       PetscInt numRemainder = numCells % (numBatches * batchSize);
10831       PetscInt offset       = numCells - numRemainder;
10832 
10833       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10834       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10835                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10836     }
10837   }
10838   for (c = cStart; c < cEnd; ++c) {
10839     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10840     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10841   }
10842   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10843 
10844   /* Assemble matrix, using the 2-step process:
10845        MatAssemblyBegin(), MatAssemblyEnd(). */
10846   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10847   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10848 
10849   if (mesh->printFEM) {
10850     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10851     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10852     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10853   }
10854   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10855   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10856   if (isShell) {
10857     JacActionCtx *jctx;
10858 
10859     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10860     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10861   }
10862   *str = SAME_NONZERO_PATTERN;
10863   PetscFunctionReturn(0);
10864 }
10865 
10866 
10867 #undef __FUNCT__
10868 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10869 /*@C
10870   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10871   the local section and an SF describing the section point overlap.
10872 
10873   Input Parameters:
10874   + s - The PetscSection for the local field layout
10875   . sf - The SF describing parallel layout of the section points
10876   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10877   . label - The label specifying the points
10878   - labelValue - The label stratum specifying the points
10879 
10880   Output Parameter:
10881   . gsection - The PetscSection for the global field layout
10882 
10883   Note: This gives negative sizes and offsets to points not owned by this process
10884 
10885   Level: developer
10886 
10887 .seealso: PetscSectionCreate()
10888 @*/
10889 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10890 {
10891   PetscInt      *neg;
10892   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10893   PetscErrorCode ierr;
10894 
10895   PetscFunctionBegin;
10896   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10897   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10898   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10899   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10900   /* Mark ghost points with negative dof */
10901   for (p = pStart; p < pEnd; ++p) {
10902     PetscInt value;
10903 
10904     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10905     if (value != labelValue) continue;
10906     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10907     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10908     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10909     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10910     neg[p-pStart] = -(dof+1);
10911   }
10912   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10913   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10914   if (nroots >= 0) {
10915     if (nroots > pEnd - pStart) {
10916       PetscInt *tmpDof;
10917       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10918       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10919       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10920       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10921       for (p = pStart; p < pEnd; ++p) {
10922         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
10923       }
10924       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10925     } else {
10926       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10927       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10928     }
10929   }
10930   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10931   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10932     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10933     (*gsection)->atlasOff[p] = off;
10934     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10935   }
10936   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10937   globalOff -= off;
10938   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10939     (*gsection)->atlasOff[p] += globalOff;
10940     neg[p] = -((*gsection)->atlasOff[p]+1);
10941   }
10942   /* Put in negative offsets for ghost points */
10943   if (nroots >= 0) {
10944     if (nroots > pEnd - pStart) {
10945       PetscInt *tmpOff;
10946       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10947       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10948       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10949       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10950       for (p = pStart; p < pEnd; ++p) {
10951         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
10952       }
10953       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10954     } else {
10955       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10956       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10957     }
10958   }
10959   ierr = PetscFree(neg);CHKERRQ(ierr);
10960   PetscFunctionReturn(0);
10961 }
10962