xref: /petsc/src/dm/impls/plex/plex.c (revision 18e2ec274b9e92144f2ef650b9690aa28f9a6737)
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 = (PetscInt) (2*PetscMax(pow((PetscReal) mesh->maxConeSize, depth)+1, pow((PetscReal) mesh->maxSupportSize, depth)+1));
515   maxAdjSize     = (PetscInt) (pow((PetscReal) mesh->maxConeSize, depth)*pow((PetscReal) 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(pow(mesh->maxConeSize, depth)+1, pow(mesh->maxSupportSize, depth)+1);
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 #ifndef 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 = (PetscInt) (2*PetscMax(PetscMax(pow((PetscReal) mesh->maxConeSize, depth)+1, pow((PetscReal) mesh->maxSupportSize, depth)+1), depth+1));
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 = PetscOListDuplicate(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 = (PetscInt) (pow((PetscReal) mesh->maxSupportSize, depth)+1);
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 = (PetscInt) (pow((PetscReal) mesh->maxConeSize, height)+1);
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   MPI_Comm       comm = ((PetscObject) dm)->comm;
2485   PetscInt       cellDim;
2486   PetscErrorCode ierr;
2487 
2488   PetscFunctionBegin;
2489   PetscValidPointer(numFaceVertices,3);
2490   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2491   switch(cellDim) {
2492   case 0:
2493     *numFaceVertices = 0;
2494     break;
2495   case 1:
2496     *numFaceVertices = 1;
2497     break;
2498   case 2:
2499     switch(numCorners) {
2500     case 3: /* triangle */
2501       *numFaceVertices = 2; /* Edge has 2 vertices */
2502       break;
2503     case 4: /* quadrilateral */
2504       *numFaceVertices = 2; /* Edge has 2 vertices */
2505       break;
2506     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2507       *numFaceVertices = 3; /* Edge has 3 vertices */
2508       break;
2509     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2510       *numFaceVertices = 3; /* Edge has 3 vertices */
2511       break;
2512     default:
2513       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2514     }
2515     break;
2516   case 3:
2517     switch(numCorners)	{
2518     case 4: /* tetradehdron */
2519       *numFaceVertices = 3; /* Face has 3 vertices */
2520       break;
2521     case 6: /* tet cohesive cells */
2522       *numFaceVertices = 4; /* Face has 4 vertices */
2523       break;
2524     case 8: /* hexahedron */
2525       *numFaceVertices = 4; /* Face has 4 vertices */
2526       break;
2527     case 9: /* tet cohesive Lagrange cells */
2528       *numFaceVertices = 6; /* Face has 6 vertices */
2529       break;
2530     case 10: /* quadratic tetrahedron */
2531       *numFaceVertices = 6; /* Face has 6 vertices */
2532       break;
2533     case 12: /* hex cohesive Lagrange cells */
2534       *numFaceVertices = 6; /* Face has 6 vertices */
2535       break;
2536     case 18: /* quadratic tet cohesive Lagrange cells */
2537       *numFaceVertices = 6; /* Face has 6 vertices */
2538       break;
2539     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2540       *numFaceVertices = 9; /* Face has 9 vertices */
2541       break;
2542     default:
2543       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2544     }
2545     break;
2546   default:
2547     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2548   }
2549   PetscFunctionReturn(0);
2550 }
2551 
2552 #undef __FUNCT__
2553 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2554 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency) {
2555   const PetscInt maxFaceCases = 30;
2556   PetscInt       numFaceCases = 0;
2557   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2558   PetscInt      *off, *adj;
2559   PetscInt      *neighborCells, *tmpClosure;
2560   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2561   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2562   PetscErrorCode ierr;
2563 
2564   PetscFunctionBegin;
2565   /* For parallel partitioning, I think you have to communicate supports */
2566   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2567   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2568   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2569   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2570   if (cEnd - cStart == 0) {
2571     if (numVertices) *numVertices = 0;
2572     if (offsets)     *offsets     = PETSC_NULL;
2573     if (adjacency)   *adjacency   = PETSC_NULL;
2574     PetscFunctionReturn(0);
2575   }
2576   numCells = cEnd - cStart;
2577   /* Setup face recognition */
2578   {
2579     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 */
2580 
2581     for (c = cStart; c < cEnd; ++c) {
2582       PetscInt corners;
2583 
2584       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2585       if (!cornersSeen[corners]) {
2586         PetscInt nFV;
2587 
2588         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2589         cornersSeen[corners] = 1;
2590         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2591         numFaceVertices[numFaceCases++] = nFV;
2592       }
2593     }
2594   }
2595   maxClosure   = (PetscInt) (2*PetscMax(pow((PetscReal) maxConeSize, depth)+1, pow((PetscReal) maxSupportSize, depth)+1));
2596   maxNeighbors = (PetscInt) (pow((PetscReal) maxConeSize, depth)*pow((PetscReal) maxSupportSize, depth)+1);
2597   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2598   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2599   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2600   /* Count neighboring cells */
2601   for (cell = cStart; cell < cEnd; ++cell) {
2602     PetscInt numNeighbors = maxNeighbors, n;
2603 
2604     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2605     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2606     for (n = 0; n < numNeighbors; ++n) {
2607       PetscInt        cellPair[2] = {cell, neighborCells[n]};
2608       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2609       PetscInt        meetSize    = 0;
2610       const PetscInt *meet        = PETSC_NULL;
2611 
2612       if (cellPair[0] == cellPair[1]) continue;
2613       if (!found) {
2614         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2615         if (meetSize) {
2616           PetscInt f;
2617 
2618           for (f = 0; f < numFaceCases; ++f) {
2619             if (numFaceVertices[f] == meetSize) {
2620               found = PETSC_TRUE;
2621               break;
2622             }
2623           }
2624         }
2625         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2626       }
2627       if (found) {
2628         ++off[cell-cStart+1];
2629       }
2630     }
2631   }
2632   /* Prefix sum */
2633   for (cell = 1; cell <= numCells; ++cell) {
2634     off[cell] += off[cell-1];
2635   }
2636   if (adjacency) {
2637     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2638     /* Get neighboring cells */
2639     for (cell = cStart; cell < cEnd; ++cell) {
2640       PetscInt numNeighbors = maxNeighbors, n;
2641       PetscInt cellOffset   = 0;
2642 
2643       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2644       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2645       for (n = 0; n < numNeighbors; ++n) {
2646         PetscInt        cellPair[2] = {cell, neighborCells[n]};
2647         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2648         PetscInt        meetSize    = 0;
2649         const PetscInt *meet        = PETSC_NULL;
2650 
2651         if (cellPair[0] == cellPair[1]) continue;
2652         if (!found) {
2653           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2654           if (meetSize) {
2655             PetscInt f;
2656 
2657             for (f = 0; f < numFaceCases; ++f) {
2658               if (numFaceVertices[f] == meetSize) {
2659                 found = PETSC_TRUE;
2660                 break;
2661               }
2662             }
2663           }
2664           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2665         }
2666         if (found) {
2667           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2668           ++cellOffset;
2669         }
2670       }
2671     }
2672   }
2673   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2674   if (numVertices) *numVertices = numCells;
2675   if (offsets)     *offsets     = off;
2676   if (adjacency)   *adjacency   = adj;
2677   PetscFunctionReturn(0);
2678 }
2679 
2680 #ifdef PETSC_HAVE_CHACO
2681 #ifdef PETSC_HAVE_UNISTD_H
2682 #include <unistd.h>
2683 #endif
2684 /* Chaco does not have an include file */
2685 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2686                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2687                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2688                        int mesh_dims[3], double *goal, int global_method, int local_method,
2689                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2690 
2691 extern int FREE_GRAPH;
2692 
2693 #undef __FUNCT__
2694 #define __FUNCT__ "DMPlexPartition_Chaco"
2695 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2696 {
2697   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2698   MPI_Comm comm = ((PetscObject) dm)->comm;
2699   int nvtxs = numVertices;                /* number of vertices in full graph */
2700   int *vwgts = NULL;                      /* weights for all vertices */
2701   float *ewgts = NULL;                    /* weights for all edges */
2702   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2703   char *outassignname = NULL;             /*  name of assignment output file */
2704   char *outfilename = NULL;               /* output file name */
2705   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2706   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2707   int mesh_dims[3];                       /* dimensions of mesh of processors */
2708   double *goal = NULL;                    /* desired set sizes for each set */
2709   int global_method = 1;                  /* global partitioning algorithm */
2710   int local_method = 1;                   /* local partitioning algorithm */
2711   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2712   int vmax = 200;                         /* how many vertices to coarsen down to? */
2713   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2714   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2715   long seed = 123636512;                  /* for random graph mutations */
2716   short int *assignment;                  /* Output partition */
2717   int fd_stdout, fd_pipe[2];
2718   PetscInt      *points;
2719   PetscMPIInt    commSize;
2720   int            i, v, p;
2721   PetscErrorCode ierr;
2722 
2723   PetscFunctionBegin;
2724   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2725   if (!numVertices) {
2726     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2727     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2728     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2729     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2730     PetscFunctionReturn(0);
2731   }
2732   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2733   for (i = 0; i < start[numVertices]; ++i) {
2734     ++adjacency[i];
2735   }
2736   if (global_method == INERTIAL_METHOD) {
2737     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2738     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2739   }
2740   mesh_dims[0] = commSize;
2741   mesh_dims[1] = 1;
2742   mesh_dims[2] = 1;
2743   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2744   /* Chaco outputs to stdout. We redirect this to a buffer. */
2745   /* TODO: check error codes for UNIX calls */
2746 #ifdef PETSC_HAVE_UNISTD_H
2747   {
2748     int piperet;
2749     piperet = pipe(fd_pipe);
2750     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2751     fd_stdout = dup(1);
2752     close(1);
2753     dup2(fd_pipe[1], 1);
2754   }
2755 #endif
2756   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2757                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2758                    vmax, ndims, eigtol, seed);
2759 #ifdef PETSC_HAVE_UNISTD_H
2760   {
2761     char msgLog[10000];
2762     int  count;
2763 
2764     fflush(stdout);
2765     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2766     if (count < 0) count = 0;
2767     msgLog[count] = 0;
2768     close(1);
2769     dup2(fd_stdout, 1);
2770     close(fd_stdout);
2771     close(fd_pipe[0]);
2772     close(fd_pipe[1]);
2773     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2774   }
2775 #endif
2776   /* Convert to PetscSection+IS */
2777   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2778   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2779   for (v = 0; v < nvtxs; ++v) {
2780     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2781   }
2782   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2783   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2784   for (p = 0, i = 0; p < commSize; ++p) {
2785     for (v = 0; v < nvtxs; ++v) {
2786       if (assignment[v] == p) points[i++] = v;
2787     }
2788   }
2789   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2790   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2791   if (global_method == INERTIAL_METHOD) {
2792     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2793   }
2794   ierr = PetscFree(assignment);CHKERRQ(ierr);
2795   for (i = 0; i < start[numVertices]; ++i) {
2796     --adjacency[i];
2797   }
2798   PetscFunctionReturn(0);
2799 }
2800 #endif
2801 
2802 #ifdef PETSC_HAVE_PARMETIS
2803 #undef __FUNCT__
2804 #define __FUNCT__ "DMPlexPartition_ParMetis"
2805 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2806 {
2807   PetscFunctionBegin;
2808   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2809   PetscFunctionReturn(0);
2810 }
2811 #endif
2812 
2813 #undef __FUNCT__
2814 #define __FUNCT__ "DMPlexEnlargePartition"
2815 /* Expand the partition by BFS on the adjacency graph */
2816 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition) {
2817   PetscHashI      h;
2818   const PetscInt *points;
2819   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2820   PetscInt        pStart, pEnd, part, q;
2821   PetscErrorCode  ierr;
2822 
2823   PetscFunctionBegin;
2824   PetscHashICreate(h);
2825   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2826   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2827   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2828   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2829   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2830   for(part = pStart; part < pEnd; ++part) {
2831     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2832 
2833     PetscHashIClear(h);
2834     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2835     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2836     /* Add all existing points to h */
2837     for(p = 0; p < numPoints; ++p) {
2838       const PetscInt point = points[off+p];
2839       PetscHashIAdd(h, point, 1);
2840     }
2841     PetscHashISize(h, nP);
2842     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2843     /* Add all points in next BFS level */
2844     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2845     for(p = 0; p < numPoints; ++p) {
2846       const PetscInt point = points[off+p];
2847       PetscInt s = start[point], e = start[point+1], a;
2848 
2849       for(a = s; a < e; ++a) {
2850         PetscHashIAdd(h, adjacency[a], 1);
2851       }
2852     }
2853     PetscHashISize(h, numNewPoints);
2854     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2855     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2856     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2857     totPoints += numNewPoints;
2858   }
2859   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2860   PetscHashIDestroy(h);
2861   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2862   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2863   for(part = pStart, q = 0; part < pEnd; ++part) {
2864     PetscInt numPoints, p;
2865 
2866     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2867     for(p = 0; p < numPoints; ++p, ++q) {
2868       newPoints[q] = tmpPoints[part][p];
2869     }
2870     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2871   }
2872   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2873   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2874   PetscFunctionReturn(0);
2875 }
2876 
2877 #undef __FUNCT__
2878 #define __FUNCT__ "DMPlexCreatePartition"
2879 /*
2880   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2881 
2882   Collective on DM
2883 
2884   Input Parameters:
2885   + dm - The DM
2886   . height - The height for points in the partition
2887   - enlarge - Expand each partition with neighbors
2888 
2889   Output Parameters:
2890   + partSection - The PetscSection giving the division of points by partition
2891   . partition - The list of points by partition
2892   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2893   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2894 
2895   Level: developer
2896 
2897 .seealso DMPlexDistribute()
2898 */
2899 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition) {
2900   PetscMPIInt    size;
2901   PetscErrorCode ierr;
2902 
2903   PetscFunctionBegin;
2904   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2905   *origPartSection = PETSC_NULL;
2906   *origPartition   = PETSC_NULL;
2907   if (size == 1) {
2908     PetscInt *points;
2909     PetscInt  cStart, cEnd, c;
2910 
2911     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2912     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2913     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2914     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2915     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2916     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2917     for (c = cStart; c < cEnd; ++c) {
2918       points[c] = c;
2919     }
2920     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2921     PetscFunctionReturn(0);
2922   }
2923   if (height == 0) {
2924     PetscInt  numVertices;
2925     PetscInt *start     = PETSC_NULL;
2926     PetscInt *adjacency = PETSC_NULL;
2927 
2928     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2929     if (1) {
2930 #ifdef PETSC_HAVE_CHACO
2931       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2932 #endif
2933     } else {
2934 #ifdef PETSC_HAVE_PARMETIS
2935       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2936 #endif
2937     }
2938     if (enlarge) {
2939       *origPartSection = *partSection;
2940       *origPartition   = *partition;
2941       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2942     }
2943     ierr = PetscFree(start);CHKERRQ(ierr);
2944     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2945 # if 0
2946   } else if (height == 1) {
2947     /* Build the dual graph for faces and partition the hypergraph */
2948     PetscInt numEdges;
2949 
2950     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2951     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2952     destroyCSR(numEdges, start, adjacency);
2953 #endif
2954   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2955   PetscFunctionReturn(0);
2956 }
2957 
2958 #undef __FUNCT__
2959 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2960 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition) {
2961   /* const PetscInt  height = 0; */
2962   const PetscInt *partArray;
2963   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2964   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2965   PetscErrorCode  ierr;
2966 
2967   PetscFunctionBegin;
2968   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2969   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2970   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2971   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2972   for (rank = rStart; rank < rEnd; ++rank) {
2973     PetscInt partSize = 0;
2974     PetscInt numPoints, offset, p;
2975 
2976     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2977     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2978     for (p = 0; p < numPoints; ++p) {
2979       PetscInt  point   = partArray[offset+p], closureSize, c;
2980       PetscInt *closure = PETSC_NULL;
2981 
2982       /* TODO Include support for height > 0 case */
2983       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2984       /* Merge into existing points */
2985       if (partSize+closureSize > maxPartSize) {
2986         PetscInt *tmpPoints;
2987 
2988         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2989         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2990         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2991         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2992         partPoints = tmpPoints;
2993       }
2994       for (c = 0; c < closureSize; ++c) {
2995         partPoints[partSize+c] = closure[c*2];
2996       }
2997       partSize += closureSize;
2998       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2999       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3000     }
3001     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3002   }
3003   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3004   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3005   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3006 
3007   for (rank = rStart; rank < rEnd; ++rank) {
3008     PetscInt partSize = 0, newOffset;
3009     PetscInt numPoints, offset, p;
3010 
3011     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3012     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3013     for (p = 0; p < numPoints; ++p) {
3014       PetscInt  point   = partArray[offset+p], closureSize, c;
3015       PetscInt *closure = PETSC_NULL;
3016 
3017       /* TODO Include support for height > 0 case */
3018       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3019       /* Merge into existing points */
3020       for (c = 0; c < closureSize; ++c) {
3021         partPoints[partSize+c] = closure[c*2];
3022       }
3023       partSize += closureSize;
3024       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3025       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3026     }
3027     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3028     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3029   }
3030   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3031   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3032   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3033   PetscFunctionReturn(0);
3034 }
3035 
3036 #undef __FUNCT__
3037 #define __FUNCT__ "DMPlexDistributeField"
3038 /*
3039   Input Parameters:
3040 . originalSection
3041 , originalVec
3042 
3043   Output Parameters:
3044 . newSection
3045 . newVec
3046 */
3047 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3048 {
3049   PetscSF         fieldSF;
3050   PetscInt       *remoteOffsets, fieldSize;
3051   PetscScalar    *originalValues, *newValues;
3052   PetscErrorCode  ierr;
3053 
3054   PetscFunctionBegin;
3055   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3056 
3057   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3058   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3059   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3060 
3061   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3062   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3063   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3064   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3065   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3066   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3067   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3068   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3069   PetscFunctionReturn(0);
3070 }
3071 
3072 #undef __FUNCT__
3073 #define __FUNCT__ "DMPlexDistribute"
3074 /*@C
3075   DMPlexDistribute - Distributes the mesh and any associated sections.
3076 
3077   Not Collective
3078 
3079   Input Parameter:
3080 + dm  - The original DMPlex object
3081 . partitioner - The partitioning package, or NULL for the default
3082 - overlap - The overlap of partitions, 0 is the default
3083 
3084   Output Parameter:
3085 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3086 
3087   Note: If the mesh was not distributed, the return value is PETSC_NULL
3088 
3089   Level: intermediate
3090 
3091 .keywords: mesh, elements
3092 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3093 @*/
3094 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3095 {
3096   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3097   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3098   const PetscInt height = 0;
3099   PetscInt       dim, numRemoteRanks;
3100   IS             origCellPart,        cellPart,        part;
3101   PetscSection   origCellPartSection, cellPartSection, partSection;
3102   PetscSFNode   *remoteRanks;
3103   PetscSF        partSF, pointSF, coneSF;
3104   ISLocalToGlobalMapping renumbering;
3105   PetscSection   originalConeSection, newConeSection;
3106   PetscInt      *remoteOffsets;
3107   PetscInt      *cones, *newCones, newConesSize;
3108   PetscBool      flg;
3109   PetscMPIInt    rank, numProcs, p;
3110   PetscErrorCode ierr;
3111 
3112   PetscFunctionBegin;
3113   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3114   PetscValidPointer(dmParallel,4);
3115   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3116   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3117   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3118   *dmParallel = PETSC_NULL;
3119   if (numProcs == 1) PetscFunctionReturn(0);
3120 
3121   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3122   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3123   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3124   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3125   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3126   if (!rank) {
3127     numRemoteRanks = numProcs;
3128   } else {
3129     numRemoteRanks = 0;
3130   }
3131   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3132   for (p = 0; p < numRemoteRanks; ++p) {
3133     remoteRanks[p].rank  = p;
3134     remoteRanks[p].index = 0;
3135   }
3136   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3137   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3138   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3139   if (flg) {
3140     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3141     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3142     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3143     if (origCellPart) {
3144       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3145       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3146       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3147     }
3148     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3149   }
3150   /* Close the partition over the mesh */
3151   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3152   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3153   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3154   /* Create new mesh */
3155   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3156   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3157   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3158   pmesh = (DM_Plex *) (*dmParallel)->data;
3159   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3160   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3161   if (flg) {
3162     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3163     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3164     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3165     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3166     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3167     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3168   }
3169   /* Distribute cone section */
3170   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3171   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3172   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3173   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3174   {
3175     PetscInt pStart, pEnd, p;
3176 
3177     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3178     for (p = pStart; p < pEnd; ++p) {
3179       PetscInt coneSize;
3180       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3181       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3182     }
3183   }
3184   /* Communicate and renumber cones */
3185   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3186   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3187   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3188   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3189   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3190   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3191   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3192   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3193   if (flg) {
3194     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3195     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3196     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3197     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3198     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3199   }
3200   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3201   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3202   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3203   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3204   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3205   /* Create supports and stratify sieve */
3206   {
3207     PetscInt pStart, pEnd;
3208 
3209     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3210     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3211   }
3212   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3213   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3214   /* Distribute Coordinates */
3215   {
3216     PetscSection originalCoordSection, newCoordSection;
3217     Vec          originalCoordinates, newCoordinates;
3218     const char  *name;
3219 
3220     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3221     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3222     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3223     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3224     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3225     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3226 
3227     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3228     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3229     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3230   }
3231   /* Distribute labels */
3232   {
3233     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3234     PetscInt   numLabels = 0, l;
3235 
3236     /* Bcast number of labels */
3237     while(next) {++numLabels; next = next->next;}
3238     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3239     next = mesh->labels;
3240     for (l = 0; l < numLabels; ++l) {
3241       DMLabel         newLabel;
3242       const PetscInt *partArray;
3243       char           *name;
3244       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3245       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3246       PetscInt        nameSize, s, p;
3247       PetscBool       isdepth;
3248       size_t          len = 0;
3249 
3250       /* Bcast name (could filter for no points) */
3251       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3252       nameSize = len;
3253       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3254       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3255       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3256       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3257       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3258       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3259       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3260       newLabel->name = name;
3261       /* Bcast numStrata (could filter for no points in stratum) */
3262       if (!rank) {newLabel->numStrata = next->numStrata;}
3263       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3264       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3265                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3266                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3267       /* Bcast stratumValues (could filter for no points in stratum) */
3268       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3269       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3270       /* Find size on each process and Scatter */
3271       if (!rank) {
3272         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3273         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3274         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3275         for (s = 0; s < next->numStrata; ++s) {
3276           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3277             const PetscInt point = next->points[p];
3278             PetscInt       proc;
3279 
3280             for (proc = 0; proc < numProcs; ++proc) {
3281               PetscInt dof, off, pPart;
3282 
3283               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3284               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3285               for (pPart = off; pPart < off+dof; ++pPart) {
3286                 if (partArray[pPart] == point) {
3287                   ++stratumSizes[proc*next->numStrata+s];
3288                   break;
3289                 }
3290               }
3291             }
3292           }
3293         }
3294         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3295       }
3296       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3297       /* Calculate stratumOffsets */
3298       newLabel->stratumOffsets[0] = 0;
3299       for (s = 0; s < newLabel->numStrata; ++s) {
3300         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3301       }
3302       /* Pack points and Scatter */
3303       if (!rank) {
3304         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3305         displs[0] = 0;
3306         for (p = 0; p < numProcs; ++p) {
3307           sendcnts[p] = 0;
3308           for (s = 0; s < next->numStrata; ++s) {
3309             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3310           }
3311           offsets[p]  = displs[p];
3312           displs[p+1] = displs[p] + sendcnts[p];
3313         }
3314         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3315         for (s = 0; s < next->numStrata; ++s) {
3316           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3317             const PetscInt point = next->points[p];
3318             PetscInt       proc;
3319 
3320             for (proc = 0; proc < numProcs; ++proc) {
3321               PetscInt dof, off, pPart;
3322 
3323               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3324               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3325               for (pPart = off; pPart < off+dof; ++pPart) {
3326                 if (partArray[pPart] == point) {
3327                   points[offsets[proc]++] = point;
3328                   break;
3329                 }
3330               }
3331             }
3332           }
3333         }
3334       }
3335       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3336       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3337       ierr = PetscFree(points);CHKERRQ(ierr);
3338       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3339       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3340       /* Renumber points */
3341       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3342       /* Sort points */
3343       for (s = 0; s < newLabel->numStrata; ++s) {
3344         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3345       }
3346       /* Insert into list */
3347       if (newNext) {
3348         newNext->next = newLabel;
3349       } else {
3350         pmesh->labels = newLabel;
3351       }
3352       newNext = newLabel;
3353       if (!rank) {next = next->next;}
3354     }
3355   }
3356   /* Cleanup Partition */
3357   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3358   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3359   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3360   ierr = ISDestroy(&part);CHKERRQ(ierr);
3361   /* Create point SF for parallel mesh */
3362   {
3363     const PetscInt *leaves;
3364     PetscSFNode    *remotePoints, *rowners, *lowners;
3365     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3366     PetscInt        pStart, pEnd;
3367 
3368     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3369     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3370     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3371     for (p=0; p<numRoots; p++) {
3372       rowners[p].rank = -1;
3373       rowners[p].index = -1;
3374     }
3375     if (origCellPart) {
3376       /* Make sure cells in the original partition are not assigned to other procs */
3377       const PetscInt *origCells;
3378 
3379       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3380       for (p = 0; p < numProcs; ++p) {
3381         PetscInt dof, off, d;
3382 
3383         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3384         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3385         for(d = off; d < off+dof; ++d) {
3386           rowners[origCells[d]].rank = p;
3387         }
3388       }
3389       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3390     }
3391     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3392     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3393 
3394     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3395     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3396     for (p = 0; p < numLeaves; ++p) {
3397       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3398         lowners[p].rank = rank;
3399         lowners[p].index = leaves ? leaves[p] : p;
3400       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3401         lowners[p].rank = -2;
3402         lowners[p].index = -2;
3403       }
3404     }
3405     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3406       rowners[p].rank = -3;
3407       rowners[p].index = -3;
3408     }
3409     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3410     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3411     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3412     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3413     for (p = 0; p < numLeaves; ++p) {
3414       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3415       if (lowners[p].rank != rank) ++numGhostPoints;
3416     }
3417     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3418     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3419     for (p = 0, gp = 0; p < numLeaves; ++p) {
3420       if (lowners[p].rank != rank) {
3421         ghostPoints[gp]       = leaves ? leaves[p] : p;
3422         remotePoints[gp].rank  = lowners[p].rank;
3423         remotePoints[gp].index = lowners[p].index;
3424         ++gp;
3425       }
3426     }
3427     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3428     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3429     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3430   }
3431   /* Cleanup */
3432   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3433   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3434   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3435   PetscFunctionReturn(0);
3436 }
3437 
3438 #undef __FUNCT__
3439 #define __FUNCT__ "DMPlexRenumber_Private"
3440 /*
3441   Reasons to renumber:
3442 
3443   1) Permute points, e.g. bandwidth reduction (Renumber)
3444 
3445     a) Must not mix strata
3446 
3447   2) Shift numbers for point insertion (Shift)
3448 
3449     a) Want operation brken into parts so that insertion can be interleaved
3450 
3451   renumbering - An IS which provides the new numbering
3452 */
3453 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3454 {
3455   PetscFunctionBegin;
3456   PetscFunctionReturn(0);
3457 }
3458 
3459 #undef __FUNCT__
3460 #define __FUNCT__ "DMPlexShiftPoint_Private"
3461 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3462 {
3463   if (depth < 0) return p;
3464   /* Cells    */ if (p < depthEnd[depth])   return p;
3465   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3466   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3467   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3468 }
3469 
3470 #undef __FUNCT__
3471 #define __FUNCT__ "DMPlexShiftSizes_Private"
3472 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3473 {
3474   PetscInt      *depthEnd;
3475   PetscInt       depth = 0, d, pStart, pEnd, p;
3476   PetscErrorCode ierr;
3477 
3478   PetscFunctionBegin;
3479   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3480   if (depth < 0) PetscFunctionReturn(0);
3481   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3482   /* Step 1: Expand chart */
3483   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3484   for(d = 0; d <= depth; ++d) {
3485     pEnd += depthShift[d];
3486     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3487   }
3488   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3489   /* Step 2: Set cone and support sizes */
3490   for(d = 0; d <= depth; ++d) {
3491     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3492     for(p = pStart; p < pEnd; ++p) {
3493       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3494       PetscInt size;
3495 
3496       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3497       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3498       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3499       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3500     }
3501   }
3502   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3503   PetscFunctionReturn(0);
3504 }
3505 
3506 #undef __FUNCT__
3507 #define __FUNCT__ "DMPlexShiftPoints_Private"
3508 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3509 {
3510   PetscInt      *depthEnd, *newpoints;
3511   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3512   PetscErrorCode ierr;
3513 
3514   PetscFunctionBegin;
3515   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3516   if (depth < 0) PetscFunctionReturn(0);
3517   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3518   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3519   for(d = 0; d <= depth; ++d) {
3520     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3521   }
3522   /* Step 5: Set cones and supports */
3523   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3524   for(p = pStart; p < pEnd; ++p) {
3525     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3526     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3527 
3528     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3529     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3530     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3531     for(i = 0; i < size; ++i) {
3532       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3533     }
3534     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3535     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3536     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3537     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3538     for(i = 0; i < size; ++i) {
3539       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3540     }
3541     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3542   }
3543   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3544   PetscFunctionReturn(0);
3545 }
3546 
3547 #undef __FUNCT__
3548 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3549 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3550 {
3551   PetscSection   coordSection, newCoordSection;
3552   Vec            coordinates;
3553   PetscInt      *depthEnd;
3554   PetscInt       dim, depth = 0, d, vStart, vEnd, v;
3555   PetscErrorCode ierr;
3556 
3557   PetscFunctionBegin;
3558   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3559   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3560   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3561   for(d = 0; d <= depth; ++d) {
3562     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3563   }
3564   /* Step 8: Convert coordinates */
3565   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3566   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3567   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3568   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3569   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3570   ierr = PetscSectionSetChart(newCoordSection, DMPlexShiftPoint_Private(vStart, depth, depthEnd, depthShift), DMPlexShiftPoint_Private(vEnd, depth, depthEnd, depthShift));CHKERRQ(ierr);
3571   for(v = vStart; v < vEnd; ++v) {
3572     const PetscInt newv = DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift);
3573     ierr = PetscSectionSetDof(newCoordSection, newv, dim);CHKERRQ(ierr);
3574     ierr = PetscSectionSetFieldDof(newCoordSection, newv, 0, dim);CHKERRQ(ierr);
3575   }
3576   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3577   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3578   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3579   ierr = DMSetCoordinatesLocal(dmNew, coordinates);CHKERRQ(ierr);
3580   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3581   PetscFunctionReturn(0);
3582 }
3583 
3584 #undef __FUNCT__
3585 #define __FUNCT__ "DMPlexShiftSF_Private"
3586 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3587 {
3588   PetscInt          *depthEnd;
3589   PetscInt           depth = 0, d;
3590   PetscSF            sfPoint, sfPointNew;
3591   const PetscSFNode *remotePoints;
3592   PetscSFNode       *gremotePoints;
3593   const PetscInt    *localPoints;
3594   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3595   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3596   PetscMPIInt        numProcs;
3597   PetscErrorCode     ierr;
3598 
3599   PetscFunctionBegin;
3600   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3601   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3602   for(d = 0; d <= depth; ++d) {
3603     totShift += depthShift[d];
3604     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3605   }
3606   /* Step 9: Convert pointSF */
3607   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3608   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3609   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3610   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3611   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3612   if (numRoots >= 0) {
3613     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3614     for(l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3615     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3616     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3617     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3618     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3619     for(l = 0; l < numLeaves; ++l) {
3620       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3621       gremotePoints[l].rank  = remotePoints[l].rank;
3622       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3623     }
3624     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3625     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3626   }
3627   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3628   PetscFunctionReturn(0);
3629 }
3630 
3631 #undef __FUNCT__
3632 #define __FUNCT__ "DMPlexShiftLabels_Private"
3633 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3634 {
3635   PetscSF        sfPoint;
3636   DMLabel        vtkLabel, ghostLabel;
3637   PetscInt      *depthEnd;
3638   const PetscSFNode *leafRemote;
3639   const PetscInt    *leafLocal;
3640   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3641   PetscMPIInt    rank;
3642   PetscErrorCode ierr;
3643 
3644   PetscFunctionBegin;
3645   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3646   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3647   for(d = 0; d <= depth; ++d) {
3648     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3649   }
3650   /* Step 10: Convert labels */
3651   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3652   for(l = 0; l < numLabels; ++l) {
3653     DMLabel         label, newlabel;
3654     const char     *lname;
3655     PetscBool       isDepth;
3656     IS              valueIS;
3657     const PetscInt *values;
3658     PetscInt        numValues, val;
3659 
3660     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3661     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3662     if (isDepth) continue;
3663     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3664     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3665     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3666     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3667     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3668     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3669     for(val = 0; val < numValues; ++val) {
3670       IS              pointIS;
3671       const PetscInt *points;
3672       PetscInt        numPoints, p;
3673 
3674       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3675       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3676       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3677       for(p = 0; p < numPoints; ++p) {
3678         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3679 
3680         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3681       }
3682       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3683       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3684     }
3685     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3686     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3687   }
3688   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3689   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3690   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3691   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3692   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3693   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3694   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3695   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3696   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3697   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3698   for(l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3699     for(; c < leafLocal[l] && c < cEnd; ++c) {
3700       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3701     }
3702     if (leafLocal[l] >= cEnd) break;
3703     if (leafRemote[l].rank == rank) {
3704       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3705     } else {
3706       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3707     }
3708   }
3709   for(; c < cEnd; ++c) {
3710     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3711   }
3712   if (0) {
3713     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3714     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3715     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3716   }
3717   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3718   for(f = fStart; f < fEnd; ++f) {
3719     PetscInt numCells;
3720 
3721     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3722     if (numCells < 2) {
3723       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3724     } else {
3725       const PetscInt *cells = PETSC_NULL;
3726       PetscInt        vA, vB;
3727 
3728       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3729       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3730       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3731       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3732     }
3733   }
3734   if (0) {
3735     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3736     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3737     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3738   }
3739   PetscFunctionReturn(0);
3740 }
3741 
3742 #undef __FUNCT__
3743 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3744 /*@C
3745   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3746 
3747   Collective on dm
3748 
3749   Input Parameters:
3750 + dm - The original DM
3751 - labelName - The label specifying the boundary faces (this could be auto-generated)
3752 
3753   Output Parameters:
3754 + numGhostCells - The number of ghost cells added to the DM
3755 - dmGhosted - The new DM
3756 
3757   Level: developer
3758 
3759 .seealso: DMCreate()
3760 */
3761 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3762 {
3763   DMLabel         label;
3764   IS              valueIS;
3765   const PetscInt *values;
3766   PetscInt       *depthShift;
3767   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3768   PetscErrorCode  ierr;
3769 
3770   PetscFunctionBegin;
3771   /* Count ghost cells */
3772   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3773   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3774   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3775   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3776   *numGhostCells = 0;
3777   for(fs = 0; fs < numFS; ++fs) {
3778     PetscInt numBdFaces;
3779 
3780     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3781     *numGhostCells += numBdFaces;
3782   }
3783   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3784   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3785   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3786   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3787   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3788   /* Step 3: Set cone/support sizes for new points */
3789   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3790   for(c = cEnd; c < cEnd + *numGhostCells; ++c) {
3791     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3792   }
3793   for(fs = 0; fs < numFS; ++fs) {
3794     IS              faceIS;
3795     const PetscInt *faces;
3796     PetscInt        numFaces, f;
3797 
3798     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3799     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3800     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3801     for(f = 0; f < numFaces; ++f) {
3802       PetscInt size;
3803 
3804       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3805       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3806       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3807     }
3808     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3809     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3810   }
3811   /* Step 4: Setup ghosted DM */
3812   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3813   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3814   /* Step 6: Set cones and supports for new points */
3815   ghostCell = cEnd;
3816   for(fs = 0; fs < numFS; ++fs) {
3817     IS              faceIS;
3818     const PetscInt *faces;
3819     PetscInt        numFaces, f;
3820 
3821     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3822     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3823     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3824     for(f = 0; f < numFaces; ++f, ++ghostCell) {
3825       PetscInt newFace = faces[f] + *numGhostCells;
3826 
3827       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3828       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3829     }
3830     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3831     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3832   }
3833   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3834   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3835   /* Step 7: Stratify */
3836   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3837   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3838   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3839   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3840   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3841   PetscFunctionReturn(0);
3842 }
3843 
3844 #undef __FUNCT__
3845 #define __FUNCT__ "DMPlexConstructGhostCells"
3846 /*@C
3847   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3848 
3849   Collective on dm
3850 
3851   Input Parameters:
3852 + dm - The original DM
3853 - labelName - The label specifying the boundary faces (this could be auto-generated)
3854 
3855   Output Parameters:
3856 + numGhostCells - The number of ghost cells added to the DM
3857 - dmGhosted - The new DM
3858 
3859   Level: developer
3860 
3861 .seealso: DMCreate()
3862 */
3863 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3864 {
3865   DM             gdm;
3866   PetscInt       dim;
3867   PetscErrorCode ierr;
3868 
3869   PetscFunctionBegin;
3870   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3871   PetscValidPointer(numGhostCells, 3);
3872   PetscValidPointer(dmGhosted, 4);
3873   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3874   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3875   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3876   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3877   switch(dim) {
3878   case 2:
3879     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3880     break;
3881   default:
3882     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3883   }
3884   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3885   *dmGhosted = gdm;
3886   PetscFunctionReturn(0);
3887 }
3888 
3889 #undef __FUNCT__
3890 #define __FUNCT__ "DMPlexInterpolate_2D"
3891 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
3892 {
3893   DM             idm;
3894   DM_Plex    *mesh;
3895   PetscHashIJ    edgeTable;
3896   PetscInt      *off;
3897   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
3898   PetscInt       numEdges, firstEdge, edge, e;
3899   PetscErrorCode ierr;
3900 
3901   PetscFunctionBegin;
3902   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3903   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3904   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3905   numCells    = cEnd - cStart;
3906   numVertices = vEnd - vStart;
3907   firstEdge   = numCells + numVertices;
3908   numEdges    = 0 ;
3909   /* Count edges using algorithm from CreateNeighborCSR */
3910   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
3911   if (off) {
3912     PetscInt numCorners = 0;
3913 
3914     numEdges = off[numCells]/2;
3915 #if 0
3916     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
3917     numEdges += 3*numCells - off[numCells];
3918 #else
3919     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
3920     for(c = cStart; c < cEnd; ++c) {
3921       PetscInt coneSize;
3922 
3923       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
3924       numCorners += coneSize;
3925     }
3926     numEdges += numCorners - off[numCells];
3927 #endif
3928   }
3929 #if 0
3930   /* Check Euler characteristic V - E + F = 1 */
3931   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
3932 #endif
3933   /* Create interpolated mesh */
3934   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
3935   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
3936   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
3937   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
3938   for (c = 0; c < numCells; ++c) {
3939     PetscInt numCorners;
3940 
3941     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
3942     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
3943   }
3944   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
3945     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
3946   }
3947   ierr = DMSetUp(idm);CHKERRQ(ierr);
3948   /* Get edge cones from subsets of cell vertices */
3949   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
3950   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
3951 
3952   for (c = 0, edge = firstEdge; c < numCells; ++c) {
3953     const PetscInt *cellFaces;
3954     PetscInt        numCellFaces, faceSize, cf;
3955 
3956     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
3957     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
3958     for (cf = 0; cf < numCellFaces; ++cf) {
3959 #if 1
3960       PetscHashIJKey key = {PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]),
3961                             PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1])};
3962 
3963       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
3964       if (e < 0) {
3965         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3966         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
3967         e    = edge++;
3968       }
3969 #else
3970       PetscBool found = PETSC_FALSE;
3971 
3972       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
3973       for (e = firstEdge; e < edge; ++e) {
3974         const PetscInt *cone;
3975 
3976         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
3977         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
3978             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
3979           found = PETSC_TRUE;
3980           break;
3981         }
3982       }
3983       if (!found) {
3984         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3985         ++edge;
3986       }
3987 #endif
3988       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
3989     }
3990   }
3991   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
3992   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
3993   ierr = PetscFree(off);CHKERRQ(ierr);
3994   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
3995   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
3996   mesh = (DM_Plex *) (idm)->data;
3997   /* Orient edges */
3998   for (c = 0; c < numCells; ++c) {
3999     const PetscInt *cone = PETSC_NULL, *cellFaces;
4000     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4001 
4002     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4003     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4004     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4005     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4006     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4007     for (cf = 0; cf < numCellFaces; ++cf) {
4008       const PetscInt *econe = PETSC_NULL;
4009       PetscInt        esize;
4010 
4011       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4012       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4013       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]);
4014       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4015         /* Correctly oriented */
4016         mesh->coneOrientations[coff+cf] = 0;
4017       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4018         /* Start at index 1, and reverse orientation */
4019         mesh->coneOrientations[coff+cf] = -(1+1);
4020       }
4021     }
4022   }
4023   *dmInt  = idm;
4024   PetscFunctionReturn(0);
4025 }
4026 
4027 #undef __FUNCT__
4028 #define __FUNCT__ "DMPlexInterpolate_3D"
4029 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4030 {
4031   DM             idm, fdm;
4032   DM_Plex    *mesh;
4033   PetscInt      *off;
4034   const PetscInt numCorners = 4;
4035   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4036   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4037   PetscErrorCode ierr;
4038 
4039   PetscFunctionBegin;
4040   {
4041     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4042     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4043     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4044   }
4045   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4046   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4047   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4048   numCells    = cEnd - cStart;
4049   numVertices = vEnd - vStart;
4050   firstFace   = numCells + numVertices;
4051   numFaces    = 0 ;
4052   /* Count faces using algorithm from CreateNeighborCSR */
4053   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4054   if (off) {
4055     numFaces = off[numCells]/2;
4056     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4057     numFaces += 4*numCells - off[numCells];
4058   }
4059   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4060   firstEdge = firstFace + numFaces;
4061   numEdges  = numVertices + numFaces - numCells - 1;
4062   /* Create interpolated mesh */
4063   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4064   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4065   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4066   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4067   for (c = 0; c < numCells; ++c) {
4068     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4069   }
4070   for (f = firstFace; f < firstFace+numFaces; ++f) {
4071     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4072   }
4073   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4074     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4075   }
4076   ierr = DMSetUp(idm);CHKERRQ(ierr);
4077   /* Get face cones from subsets of cell vertices */
4078   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4079   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4080   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4081   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4082   for (f = firstFace; f < firstFace+numFaces; ++f) {
4083     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4084   }
4085   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4086   for (c = 0, face = firstFace; c < numCells; ++c) {
4087     const PetscInt *cellFaces;
4088     PetscInt        numCellFaces, faceSize, cf;
4089 
4090     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4091     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4092     for (cf = 0; cf < numCellFaces; ++cf) {
4093       PetscBool found = PETSC_FALSE;
4094 
4095       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4096       for (f = firstFace; f < face; ++f) {
4097         const PetscInt *cone = PETSC_NULL;
4098 
4099         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4100         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4101             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4102             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4103             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4104             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4105             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4106           found = PETSC_TRUE;
4107           break;
4108         }
4109       }
4110       if (!found) {
4111         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4112         /* Save the vertices for orientation calculation */
4113         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4114         ++face;
4115       }
4116       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4117     }
4118   }
4119   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4120   /* Get edge cones from subsets of face vertices */
4121   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4122     const PetscInt *cellFaces;
4123     PetscInt        numCellFaces, faceSize, cf;
4124 
4125     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4126     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4127     for (cf = 0; cf < numCellFaces; ++cf) {
4128       PetscBool found = PETSC_FALSE;
4129 
4130       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4131       for (e = firstEdge; e < edge; ++e) {
4132         const PetscInt *cone = PETSC_NULL;
4133 
4134         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4135         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4136             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4137           found = PETSC_TRUE;
4138           break;
4139         }
4140       }
4141       if (!found) {
4142         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4143         ++edge;
4144       }
4145       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4146     }
4147   }
4148   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4149   ierr = PetscFree(off);CHKERRQ(ierr);
4150   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4151   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4152   mesh = (DM_Plex *) (idm)->data;
4153   /* Orient edges */
4154   for (f = firstFace; f < firstFace+numFaces; ++f) {
4155     const PetscInt *cone, *cellFaces;
4156     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4157 
4158     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4159     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4160     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4161     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4162     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4163     for (cf = 0; cf < numCellFaces; ++cf) {
4164       const PetscInt *econe;
4165       PetscInt        esize;
4166 
4167       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4168       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4169       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]);
4170       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4171         /* Correctly oriented */
4172         mesh->coneOrientations[coff+cf] = 0;
4173       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4174         /* Start at index 1, and reverse orientation */
4175         mesh->coneOrientations[coff+cf] = -(1+1);
4176       }
4177     }
4178   }
4179   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4180   /* Orient faces */
4181   for (c = 0; c < numCells; ++c) {
4182     const PetscInt *cone, *cellFaces;
4183     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4184 
4185     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4186     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4187     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4188     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4189     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4190     for (cf = 0; cf < numCellFaces; ++cf) {
4191       PetscInt *origClosure = PETSC_NULL, *closure;
4192       PetscInt  closureSize, i;
4193 
4194       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4195       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4196       for (i = 4; i < 7; ++i) {
4197         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);
4198       }
4199       closure = &origClosure[4*2];
4200       /* Remember that this is the orientation for edges, not vertices */
4201       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4202         /* Correctly oriented */
4203         mesh->coneOrientations[coff+cf] = 0;
4204       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4205         /* Shifted by 1 */
4206         mesh->coneOrientations[coff+cf] = 1;
4207       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4208         /* Shifted by 2 */
4209         mesh->coneOrientations[coff+cf] = 2;
4210       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4211         /* Start at edge 1, and reverse orientation */
4212         mesh->coneOrientations[coff+cf] = -(1+1);
4213       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4214         /* Start at index 0, and reverse orientation */
4215         mesh->coneOrientations[coff+cf] = -(0+1);
4216       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4217         /* Start at index 2, and reverse orientation */
4218         mesh->coneOrientations[coff+cf] = -(2+1);
4219       } 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);
4220       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4221     }
4222   }
4223   {
4224     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4225     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4226     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4227   }
4228   *dmInt  = idm;
4229   PetscFunctionReturn(0);
4230 }
4231 
4232 #undef __FUNCT__
4233 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4234 /*
4235   This takes as input the common mesh generator output, a list of the vertices for each cell
4236 */
4237 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4238 {
4239   PetscInt      *cone, c, p;
4240   PetscErrorCode ierr;
4241 
4242   PetscFunctionBegin;
4243   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4244   for (c = 0; c < numCells; ++c) {
4245     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4246   }
4247   ierr = DMSetUp(dm);CHKERRQ(ierr);
4248   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4249   for (c = 0; c < numCells; ++c) {
4250     for (p = 0; p < numCorners; ++p) {
4251       cone[p] = cells[c*numCorners+p]+numCells;
4252     }
4253     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4254   }
4255   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4256   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4257   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4258   PetscFunctionReturn(0);
4259 }
4260 
4261 #undef __FUNCT__
4262 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4263 /*
4264   This takes as input the coordinates for each vertex
4265 */
4266 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4267 {
4268   PetscSection   coordSection;
4269   Vec            coordinates;
4270   PetscScalar   *coords;
4271   PetscInt       coordSize, v, d;
4272   PetscErrorCode ierr;
4273 
4274   PetscFunctionBegin;
4275   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4276   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4277   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4278   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4279   for (v = numCells; v < numCells+numVertices; ++v) {
4280     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4281     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4282   }
4283   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4284   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4285   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4286   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4287   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4288   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4289   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4290   for (v = 0; v < numVertices; ++v) {
4291     for (d = 0; d < spaceDim; ++d) {
4292       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4293     }
4294   }
4295   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4296   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4297   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4298   PetscFunctionReturn(0);
4299 }
4300 
4301 #undef __FUNCT__
4302 #define __FUNCT__ "DMPlexCreateFromCellList"
4303 /*
4304   This takes as input the common mesh generator output, a list of the vertices for each cell
4305 */
4306 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4307 {
4308   PetscErrorCode ierr;
4309 
4310   PetscFunctionBegin;
4311   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4312   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4313   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4314   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4315   if (interpolate) {
4316     DM idm;
4317 
4318     switch(dim) {
4319     case 2:
4320       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4321     case 3:
4322       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4323     default:
4324       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4325     }
4326     ierr = DMDestroy(dm);CHKERRQ(ierr);
4327     *dm  = idm;
4328   }
4329   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4330   PetscFunctionReturn(0);
4331 }
4332 
4333 #ifdef PETSC_HAVE_TRIANGLE
4334 #include <triangle.h>
4335 
4336 #undef __FUNCT__
4337 #define __FUNCT__ "InitInput_Triangle"
4338 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx) {
4339   PetscFunctionBegin;
4340   inputCtx->numberofpoints = 0;
4341   inputCtx->numberofpointattributes = 0;
4342   inputCtx->pointlist = PETSC_NULL;
4343   inputCtx->pointattributelist = PETSC_NULL;
4344   inputCtx->pointmarkerlist = PETSC_NULL;
4345   inputCtx->numberofsegments = 0;
4346   inputCtx->segmentlist = PETSC_NULL;
4347   inputCtx->segmentmarkerlist = PETSC_NULL;
4348   inputCtx->numberoftriangleattributes = 0;
4349   inputCtx->trianglelist = PETSC_NULL;
4350   inputCtx->numberofholes = 0;
4351   inputCtx->holelist = PETSC_NULL;
4352   inputCtx->numberofregions = 0;
4353   inputCtx->regionlist = PETSC_NULL;
4354   PetscFunctionReturn(0);
4355 }
4356 
4357 #undef __FUNCT__
4358 #define __FUNCT__ "InitOutput_Triangle"
4359 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx) {
4360   PetscFunctionBegin;
4361   outputCtx->numberofpoints = 0;
4362   outputCtx->pointlist = PETSC_NULL;
4363   outputCtx->pointattributelist = PETSC_NULL;
4364   outputCtx->pointmarkerlist = PETSC_NULL;
4365   outputCtx->numberoftriangles = 0;
4366   outputCtx->trianglelist = PETSC_NULL;
4367   outputCtx->triangleattributelist = PETSC_NULL;
4368   outputCtx->neighborlist = PETSC_NULL;
4369   outputCtx->segmentlist = PETSC_NULL;
4370   outputCtx->segmentmarkerlist = PETSC_NULL;
4371   outputCtx->numberofedges = 0;
4372   outputCtx->edgelist = PETSC_NULL;
4373   outputCtx->edgemarkerlist = PETSC_NULL;
4374   PetscFunctionReturn(0);
4375 }
4376 
4377 #undef __FUNCT__
4378 #define __FUNCT__ "FiniOutput_Triangle"
4379 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx) {
4380   PetscFunctionBegin;
4381   free(outputCtx->pointmarkerlist);
4382   free(outputCtx->edgelist);
4383   free(outputCtx->edgemarkerlist);
4384   free(outputCtx->trianglelist);
4385   free(outputCtx->neighborlist);
4386   PetscFunctionReturn(0);
4387 }
4388 
4389 #undef __FUNCT__
4390 #define __FUNCT__ "DMPlexGenerate_Triangle"
4391 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4392 {
4393   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4394   PetscInt             dim              = 2;
4395   const PetscBool      createConvexHull = PETSC_FALSE;
4396   const PetscBool      constrained      = PETSC_FALSE;
4397   struct triangulateio in;
4398   struct triangulateio out;
4399   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4400   PetscMPIInt          rank;
4401   PetscErrorCode       ierr;
4402 
4403   PetscFunctionBegin;
4404   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4405   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4406   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4407   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4408   in.numberofpoints = vEnd - vStart;
4409   if (in.numberofpoints > 0) {
4410     PetscSection coordSection;
4411     Vec          coordinates;
4412     PetscScalar *array;
4413 
4414     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4415     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4416     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4417     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4418     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4419     for (v = vStart; v < vEnd; ++v) {
4420       const PetscInt idx = v - vStart;
4421       PetscInt       off, d;
4422 
4423       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4424       for (d = 0; d < dim; ++d) {
4425         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4426       }
4427       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4428     }
4429     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4430   }
4431   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4432   in.numberofsegments = eEnd - eStart;
4433   if (in.numberofsegments > 0) {
4434     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4435     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4436     for (e = eStart; e < eEnd; ++e) {
4437       const PetscInt  idx = e - eStart;
4438       const PetscInt *cone;
4439 
4440       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4441       in.segmentlist[idx*2+0] = cone[0] - vStart;
4442       in.segmentlist[idx*2+1] = cone[1] - vStart;
4443       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4444     }
4445   }
4446 #if 0 /* Do not currently support holes */
4447   PetscReal *holeCoords;
4448   PetscInt   h, d;
4449 
4450   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4451   if (in.numberofholes > 0) {
4452     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4453     for (h = 0; h < in.numberofholes; ++h) {
4454       for (d = 0; d < dim; ++d) {
4455         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4456       }
4457     }
4458   }
4459 #endif
4460   if (!rank) {
4461     char args[32];
4462 
4463     /* Take away 'Q' for verbose output */
4464     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4465     if (createConvexHull) {
4466       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4467     }
4468     if (constrained) {
4469       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4470     }
4471     triangulate(args, &in, &out, PETSC_NULL);
4472   }
4473   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4474   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4475   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4476   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4477   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4478 
4479   {
4480     const PetscInt numCorners  = 3;
4481     const PetscInt numCells    = out.numberoftriangles;
4482     const PetscInt numVertices = out.numberofpoints;
4483     const int     *cells       = out.trianglelist;
4484     const double  *meshCoords  = out.pointlist;
4485 
4486     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4487     /* Set labels */
4488     for (v = 0; v < numVertices; ++v) {
4489       if (out.pointmarkerlist[v]) {
4490         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4491       }
4492     }
4493     if (interpolate) {
4494       for (e = 0; e < out.numberofedges; e++) {
4495         if (out.edgemarkerlist[e]) {
4496           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4497           const PetscInt *edges;
4498           PetscInt        numEdges;
4499 
4500           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4501           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4502           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4503           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4504         }
4505       }
4506     }
4507     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4508   }
4509 #if 0 /* Do not currently support holes */
4510   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4511 #endif
4512   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4513   PetscFunctionReturn(0);
4514 }
4515 
4516 #undef __FUNCT__
4517 #define __FUNCT__ "DMPlexRefine_Triangle"
4518 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4519 {
4520   MPI_Comm             comm = ((PetscObject) dm)->comm;
4521   PetscInt             dim  = 2;
4522   struct triangulateio in;
4523   struct triangulateio out;
4524   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4525   PetscMPIInt          rank;
4526   PetscErrorCode       ierr;
4527 
4528   PetscFunctionBegin;
4529   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4530   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4531   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4532   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4533   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4534   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4535   in.numberofpoints = vEnd - vStart;
4536   if (in.numberofpoints > 0) {
4537     PetscSection coordSection;
4538     Vec          coordinates;
4539     PetscScalar *array;
4540 
4541     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4542     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4543     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4544     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4545     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4546     for (v = vStart; v < vEnd; ++v) {
4547       const PetscInt idx = v - vStart;
4548       PetscInt       off, d;
4549 
4550       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4551       for (d = 0; d < dim; ++d) {
4552         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4553       }
4554       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4555     }
4556     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4557   }
4558   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4559   in.numberofcorners   = 3;
4560   in.numberoftriangles = cEnd - cStart;
4561   in.trianglearealist  = (double *) maxVolumes;
4562   if (in.numberoftriangles > 0) {
4563     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4564     for (c = cStart; c < cEnd; ++c) {
4565       const PetscInt idx     = c - cStart;
4566       PetscInt      *closure = PETSC_NULL;
4567       PetscInt       closureSize;
4568 
4569       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4570       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4571       for (v = 0; v < 3; ++v) {
4572         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4573       }
4574       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4575     }
4576   }
4577   /* TODO: Segment markers are missing on input */
4578 #if 0 /* Do not currently support holes */
4579   PetscReal *holeCoords;
4580   PetscInt   h, d;
4581 
4582   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4583   if (in.numberofholes > 0) {
4584     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4585     for (h = 0; h < in.numberofholes; ++h) {
4586       for (d = 0; d < dim; ++d) {
4587         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4588       }
4589     }
4590   }
4591 #endif
4592   if (!rank) {
4593     char args[32];
4594 
4595     /* Take away 'Q' for verbose output */
4596     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4597     triangulate(args, &in, &out, PETSC_NULL);
4598   }
4599   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4600   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4601   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4602   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4603   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4604 
4605   {
4606     const PetscInt numCorners  = 3;
4607     const PetscInt numCells    = out.numberoftriangles;
4608     const PetscInt numVertices = out.numberofpoints;
4609     const int     *cells       = out.trianglelist;
4610     const double  *meshCoords  = out.pointlist;
4611     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4612 
4613     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4614     /* Set labels */
4615     for (v = 0; v < numVertices; ++v) {
4616       if (out.pointmarkerlist[v]) {
4617         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4618       }
4619     }
4620     if (interpolate) {
4621       PetscInt e;
4622 
4623       for (e = 0; e < out.numberofedges; e++) {
4624         if (out.edgemarkerlist[e]) {
4625           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4626           const PetscInt *edges;
4627           PetscInt        numEdges;
4628 
4629           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4630           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4631           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4632           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4633         }
4634       }
4635     }
4636     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4637   }
4638 #if 0 /* Do not currently support holes */
4639   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4640 #endif
4641   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4642   PetscFunctionReturn(0);
4643 }
4644 #endif
4645 
4646 #ifdef PETSC_HAVE_TETGEN
4647 #include <tetgen.h>
4648 #undef __FUNCT__
4649 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4650 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4651 {
4652   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4653   const PetscInt dim  = 3;
4654   ::tetgenio     in;
4655   ::tetgenio     out;
4656   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4657   PetscMPIInt    rank;
4658   PetscErrorCode ierr;
4659 
4660   PetscFunctionBegin;
4661   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4662   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4663   in.numberofpoints = vEnd - vStart;
4664   if (in.numberofpoints > 0) {
4665     PetscSection coordSection;
4666     Vec          coordinates;
4667     PetscScalar *array;
4668 
4669     in.pointlist       = new double[in.numberofpoints*dim];
4670     in.pointmarkerlist = new int[in.numberofpoints];
4671     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4672     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4673     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4674     for (v = vStart; v < vEnd; ++v) {
4675       const PetscInt idx = v - vStart;
4676       PetscInt       off, d;
4677 
4678       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4679       for (d = 0; d < dim; ++d) {
4680         in.pointlist[idx*dim + d] = array[off+d];
4681       }
4682       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4683     }
4684     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4685   }
4686   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4687   in.numberoffacets = fEnd - fStart;
4688   if (in.numberoffacets > 0) {
4689     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4690     in.facetmarkerlist = new int[in.numberoffacets];
4691     for (f = fStart; f < fEnd; ++f) {
4692       const PetscInt idx    = f - fStart;
4693       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
4694 
4695       in.facetlist[idx].numberofpolygons = 1;
4696       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4697       in.facetlist[idx].numberofholes    = 0;
4698       in.facetlist[idx].holelist         = NULL;
4699 
4700       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4701       for (p = 0; p < numPoints*2; p += 2) {
4702         const PetscInt point = points[p];
4703         if ((point >= vStart) && (point < vEnd)) {
4704           points[numVertices++] = point;
4705         }
4706       }
4707 
4708       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4709       poly->numberofvertices = numVertices;
4710       poly->vertexlist       = new int[poly->numberofvertices];
4711       for (v = 0; v < numVertices; ++v) {
4712         const PetscInt vIdx = points[v] - vStart;
4713         poly->vertexlist[v] = vIdx;
4714       }
4715       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4716       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4717     }
4718   }
4719   if (!rank) {
4720     char args[32];
4721 
4722     /* Take away 'Q' for verbose output */
4723     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4724     ::tetrahedralize(args, &in, &out);
4725   }
4726   {
4727     const PetscInt numCorners  = 4;
4728     const PetscInt numCells    = out.numberoftetrahedra;
4729     const PetscInt numVertices = out.numberofpoints;
4730     const int     *cells       = out.tetrahedronlist;
4731     const double  *meshCoords  = out.pointlist;
4732 
4733     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4734     /* Set labels */
4735     for (v = 0; v < numVertices; ++v) {
4736       if (out.pointmarkerlist[v]) {
4737         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4738       }
4739     }
4740     if (interpolate) {
4741       PetscInt e;
4742 
4743       for (e = 0; e < out.numberofedges; e++) {
4744         if (out.edgemarkerlist[e]) {
4745           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4746           const PetscInt *edges;
4747           PetscInt        numEdges;
4748 
4749           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4750           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4751           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4752           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4753         }
4754       }
4755       for (f = 0; f < out.numberoftrifaces; f++) {
4756         if (out.trifacemarkerlist[f]) {
4757           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4758           const PetscInt *faces;
4759           PetscInt        numFaces;
4760 
4761           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4762           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4763           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4764           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4765         }
4766       }
4767     }
4768     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4769   }
4770   PetscFunctionReturn(0);
4771 }
4772 
4773 #undef __FUNCT__
4774 #define __FUNCT__ "DMPlexRefine_Tetgen"
4775 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4776 {
4777   MPI_Comm       comm = ((PetscObject) dm)->comm;
4778   const PetscInt dim  = 3;
4779   ::tetgenio     in;
4780   ::tetgenio     out;
4781   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4782   PetscMPIInt    rank;
4783   PetscErrorCode ierr;
4784 
4785   PetscFunctionBegin;
4786   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4787   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4788   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4789   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4790   in.numberofpoints = vEnd - vStart;
4791   if (in.numberofpoints > 0) {
4792     PetscSection coordSection;
4793     Vec          coordinates;
4794     PetscScalar *array;
4795 
4796     in.pointlist       = new double[in.numberofpoints*dim];
4797     in.pointmarkerlist = new int[in.numberofpoints];
4798     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4799     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4800     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4801     for (v = vStart; v < vEnd; ++v) {
4802       const PetscInt idx = v - vStart;
4803       PetscInt       off, d;
4804 
4805       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4806       for (d = 0; d < dim; ++d) {
4807         in.pointlist[idx*dim + d] = array[off+d];
4808       }
4809       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4810     }
4811     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4812   }
4813   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4814   in.numberofcorners       = 4;
4815   in.numberoftetrahedra    = cEnd - cStart;
4816   in.tetrahedronvolumelist = (double *) maxVolumes;
4817   if (in.numberoftetrahedra > 0) {
4818     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
4819     for (c = cStart; c < cEnd; ++c) {
4820       const PetscInt idx     = c - cStart;
4821       PetscInt      *closure = PETSC_NULL;
4822       PetscInt       closureSize;
4823 
4824       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4825       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4826       for (v = 0; v < 4; ++v) {
4827         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4828       }
4829       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4830     }
4831   }
4832   /* TODO: Put in boundary faces with markers */
4833   if (!rank) {
4834     char args[32];
4835 
4836     /* Take away 'Q' for verbose output */
4837     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
4838     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
4839     ::tetrahedralize(args, &in, &out);
4840   }
4841   in.tetrahedronvolumelist = NULL;
4842 
4843   {
4844     const PetscInt numCorners  = 4;
4845     const PetscInt numCells    = out.numberoftetrahedra;
4846     const PetscInt numVertices = out.numberofpoints;
4847     const int     *cells       = out.tetrahedronlist;
4848     const double  *meshCoords  = out.pointlist;
4849     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4850 
4851     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4852     /* Set labels */
4853     for (v = 0; v < numVertices; ++v) {
4854       if (out.pointmarkerlist[v]) {
4855         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4856       }
4857     }
4858     if (interpolate) {
4859       PetscInt e, f;
4860 
4861       for (e = 0; e < out.numberofedges; e++) {
4862         if (out.edgemarkerlist[e]) {
4863           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4864           const PetscInt *edges;
4865           PetscInt        numEdges;
4866 
4867           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4868           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4869           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4870           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4871         }
4872       }
4873       for (f = 0; f < out.numberoftrifaces; f++) {
4874         if (out.trifacemarkerlist[f]) {
4875           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4876           const PetscInt *faces;
4877           PetscInt        numFaces;
4878 
4879           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4880           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4881           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4882           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4883         }
4884       }
4885     }
4886     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4887   }
4888   PetscFunctionReturn(0);
4889 }
4890 #endif
4891 
4892 #ifdef PETSC_HAVE_CTETGEN
4893 #include "ctetgen.h"
4894 
4895 #undef __FUNCT__
4896 #define __FUNCT__ "DMPlexGenerate_CTetgen"
4897 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4898 {
4899   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4900   const PetscInt dim  = 3;
4901   PLC           *in, *out;
4902   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4903   PetscMPIInt    rank;
4904   PetscErrorCode ierr;
4905 
4906   PetscFunctionBegin;
4907   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
4908   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4909   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4910   ierr = PLCCreate(&in);CHKERRQ(ierr);
4911   ierr = PLCCreate(&out);CHKERRQ(ierr);
4912   in->numberofpoints = vEnd - vStart;
4913   if (in->numberofpoints > 0) {
4914     PetscSection coordSection;
4915     Vec          coordinates;
4916     PetscScalar *array;
4917 
4918     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4919     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4920     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4921     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4922     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4923     for (v = vStart; v < vEnd; ++v) {
4924       const PetscInt idx = v - vStart;
4925       PetscInt       off, d, m;
4926 
4927       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4928       for (d = 0; d < dim; ++d) {
4929         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4930       }
4931       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
4932       in->pointmarkerlist[idx] = (int) m;
4933     }
4934     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4935   }
4936   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4937   in->numberoffacets = fEnd - fStart;
4938   if (in->numberoffacets > 0) {
4939     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
4940     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
4941     for (f = fStart; f < fEnd; ++f) {
4942       const PetscInt idx    = f - fStart;
4943       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
4944       polygon       *poly;
4945 
4946       in->facetlist[idx].numberofpolygons = 1;
4947       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
4948       in->facetlist[idx].numberofholes    = 0;
4949       in->facetlist[idx].holelist         = PETSC_NULL;
4950 
4951       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4952       for (p = 0; p < numPoints*2; p += 2) {
4953         const PetscInt point = points[p];
4954         if ((point >= vStart) && (point < vEnd)) {
4955           points[numVertices++] = point;
4956         }
4957       }
4958 
4959       poly = in->facetlist[idx].polygonlist;
4960       poly->numberofvertices = numVertices;
4961       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
4962       for (v = 0; v < numVertices; ++v) {
4963         const PetscInt vIdx = points[v] - vStart;
4964         poly->vertexlist[v] = vIdx;
4965       }
4966       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
4967       in->facetmarkerlist[idx] = (int) m;
4968       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4969     }
4970   }
4971   if (!rank) {
4972     TetGenOpts t;
4973 
4974     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4975     t.in        = boundary; /* Should go away */
4976     t.plc       = 1;
4977     t.quality   = 1;
4978     t.edgesout  = 1;
4979     t.zeroindex = 1;
4980     t.quiet     = 1;
4981     t.verbose   = verbose;
4982     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4983     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4984   }
4985   {
4986     const PetscInt numCorners  = 4;
4987     const PetscInt numCells    = out->numberoftetrahedra;
4988     const PetscInt numVertices = out->numberofpoints;
4989     const int     *cells       = out->tetrahedronlist;
4990     const double  *meshCoords  = out->pointlist;
4991 
4992     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4993     /* Set labels */
4994     for (v = 0; v < numVertices; ++v) {
4995       if (out->pointmarkerlist[v]) {
4996         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
4997       }
4998     }
4999     if (interpolate) {
5000       PetscInt e;
5001 
5002       for (e = 0; e < out->numberofedges; e++) {
5003         if (out->edgemarkerlist[e]) {
5004           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5005           const PetscInt *edges;
5006           PetscInt        numEdges;
5007 
5008           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5009           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5010           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5011           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5012         }
5013       }
5014       for (f = 0; f < out->numberoftrifaces; f++) {
5015         if (out->trifacemarkerlist[f]) {
5016           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5017           const PetscInt *faces;
5018           PetscInt        numFaces;
5019 
5020           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5021           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5022           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5023           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5024         }
5025       }
5026     }
5027     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5028   }
5029 
5030   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5031   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5032   PetscFunctionReturn(0);
5033 }
5034 
5035 #undef __FUNCT__
5036 #define __FUNCT__ "DMPlexRefine_CTetgen"
5037 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5038 {
5039   MPI_Comm       comm = ((PetscObject) dm)->comm;
5040   const PetscInt dim  = 3;
5041   PLC           *in, *out;
5042   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5043   PetscMPIInt    rank;
5044   PetscErrorCode ierr;
5045 
5046   PetscFunctionBegin;
5047   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5048   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5049   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5050   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5051   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5052   ierr = PLCCreate(&in);CHKERRQ(ierr);
5053   ierr = PLCCreate(&out);CHKERRQ(ierr);
5054   in->numberofpoints = vEnd - vStart;
5055   if (in->numberofpoints > 0) {
5056     PetscSection coordSection;
5057     Vec          coordinates;
5058     PetscScalar *array;
5059 
5060     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5061     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5062     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5063     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5064     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5065     for (v = vStart; v < vEnd; ++v) {
5066       const PetscInt idx = v - vStart;
5067       PetscInt       off, d, m;
5068 
5069       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5070       for (d = 0; d < dim; ++d) {
5071         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5072       }
5073       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5074       in->pointmarkerlist[idx] = (int) m;
5075     }
5076     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5077   }
5078   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5079   in->numberofcorners       = 4;
5080   in->numberoftetrahedra    = cEnd - cStart;
5081   in->tetrahedronvolumelist = maxVolumes;
5082   if (in->numberoftetrahedra > 0) {
5083     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5084     for (c = cStart; c < cEnd; ++c) {
5085       const PetscInt idx     = c - cStart;
5086       PetscInt      *closure = PETSC_NULL;
5087       PetscInt       closureSize;
5088 
5089       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5090       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5091       for (v = 0; v < 4; ++v) {
5092         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5093       }
5094       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5095     }
5096   }
5097   if (!rank) {
5098     TetGenOpts t;
5099 
5100     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5101     t.in        = dm; /* Should go away */
5102     t.refine    = 1;
5103     t.varvolume = 1;
5104     t.quality   = 1;
5105     t.edgesout  = 1;
5106     t.zeroindex = 1;
5107     t.quiet     = 1;
5108     t.verbose   = verbose; /* Change this */
5109     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5110     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5111   }
5112   {
5113     const PetscInt numCorners  = 4;
5114     const PetscInt numCells    = out->numberoftetrahedra;
5115     const PetscInt numVertices = out->numberofpoints;
5116     const int     *cells       = out->tetrahedronlist;
5117     const double  *meshCoords  = out->pointlist;
5118     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5119 
5120     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5121     /* Set labels */
5122     for (v = 0; v < numVertices; ++v) {
5123       if (out->pointmarkerlist[v]) {
5124         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5125       }
5126     }
5127     if (interpolate) {
5128       PetscInt e, f;
5129 
5130       for (e = 0; e < out->numberofedges; e++) {
5131         if (out->edgemarkerlist[e]) {
5132           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5133           const PetscInt *edges;
5134           PetscInt        numEdges;
5135 
5136           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5137           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5138           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5139           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5140         }
5141       }
5142       for (f = 0; f < out->numberoftrifaces; f++) {
5143         if (out->trifacemarkerlist[f]) {
5144           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5145           const PetscInt *faces;
5146           PetscInt        numFaces;
5147 
5148           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5149           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5150           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5151           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5152         }
5153       }
5154     }
5155     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5156   }
5157   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5158   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5159   PetscFunctionReturn(0);
5160 }
5161 #endif
5162 
5163 #undef __FUNCT__
5164 #define __FUNCT__ "DMPlexGenerate"
5165 /*@C
5166   DMPlexGenerate - Generates a mesh.
5167 
5168   Not Collective
5169 
5170   Input Parameters:
5171 + boundary - The DMPlex boundary object
5172 . name - The mesh generation package name
5173 - interpolate - Flag to create intermediate mesh elements
5174 
5175   Output Parameter:
5176 . mesh - The DMPlex object
5177 
5178   Level: intermediate
5179 
5180 .keywords: mesh, elements
5181 .seealso: DMPlexCreate(), DMRefine()
5182 @*/
5183 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5184 {
5185   PetscInt       dim;
5186   char           genname[1024];
5187   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5188   PetscErrorCode ierr;
5189 
5190   PetscFunctionBegin;
5191   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5192   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5193   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5194   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5195   if (flg) {name = genname;}
5196   if (name) {
5197     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5198     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5199     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5200   }
5201   switch(dim) {
5202   case 1:
5203     if (!name || isTriangle) {
5204 #ifdef PETSC_HAVE_TRIANGLE
5205       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5206 #else
5207       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5208 #endif
5209     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5210     break;
5211   case 2:
5212     if (!name || isCTetgen) {
5213 #ifdef PETSC_HAVE_CTETGEN
5214       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5215 #else
5216       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5217 #endif
5218     } else if (isTetgen) {
5219 #ifdef PETSC_HAVE_TETGEN
5220       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5221 #else
5222       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5223 #endif
5224     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5225     break;
5226   default:
5227     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5228   }
5229   PetscFunctionReturn(0);
5230 }
5231 
5232 typedef PetscInt CellRefiner;
5233 
5234 #undef __FUNCT__
5235 #define __FUNCT__ "GetDepthStart_Private"
5236 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5237 {
5238   PetscFunctionBegin;
5239   if (cStart) *cStart = 0;
5240   if (vStart) *vStart = depthSize[depth];
5241   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5242   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5243   PetscFunctionReturn(0);
5244 }
5245 
5246 #undef __FUNCT__
5247 #define __FUNCT__ "GetDepthEnd_Private"
5248 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5249 {
5250   PetscFunctionBegin;
5251   if (cEnd) *cEnd = depthSize[depth];
5252   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5253   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5254   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5255   PetscFunctionReturn(0);
5256 }
5257 
5258 #undef __FUNCT__
5259 #define __FUNCT__ "CellRefinerGetSizes"
5260 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5261 {
5262   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5263   PetscErrorCode ierr;
5264 
5265   PetscFunctionBegin;
5266   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5267   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5268   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5269   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5270   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5271   switch(refiner) {
5272   case 1:
5273     /* Simplicial 2D */
5274     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5275     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5276     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5277     break;
5278   case 3:
5279     /* Hybrid 2D */
5280     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5281     cMax = PetscMin(cEnd, cMax);
5282     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5283     fMax = PetscMin(fEnd, fMax);
5284     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5285     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 */
5286     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5287     break;
5288   case 2:
5289     /* Hex 2D */
5290     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5291     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5292     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5293     break;
5294   default:
5295     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5296   }
5297   PetscFunctionReturn(0);
5298 }
5299 
5300 #undef __FUNCT__
5301 #define __FUNCT__ "CellRefinerSetConeSizes"
5302 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5303 {
5304   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5305   PetscErrorCode ierr;
5306 
5307   PetscFunctionBegin;
5308   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5309   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5310   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5311   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5312   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5313   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5314   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5315   switch(refiner) {
5316   case 1:
5317     /* Simplicial 2D */
5318     /* All cells have 3 faces */
5319     for(c = cStart; c < cEnd; ++c) {
5320       for(r = 0; r < 4; ++r) {
5321         const PetscInt newp = (c - cStart)*4 + r;
5322 
5323         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5324       }
5325     }
5326     /* Split faces have 2 vertices and the same cells as the parent */
5327     for(f = fStart; f < fEnd; ++f) {
5328       for(r = 0; r < 2; ++r) {
5329         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5330         PetscInt       size;
5331 
5332         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5333         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5334         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5335       }
5336     }
5337     /* Interior faces have 2 vertices and 2 cells */
5338     for(c = cStart; c < cEnd; ++c) {
5339       for(r = 0; r < 3; ++r) {
5340         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5341 
5342         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5343         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5344       }
5345     }
5346     /* Old vertices have identical supports */
5347     for(v = vStart; v < vEnd; ++v) {
5348       const PetscInt newp = vStartNew + (v - vStart);
5349       PetscInt       size;
5350 
5351       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5352       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5353     }
5354     /* Face vertices have 2 + cells*2 supports */
5355     for(f = fStart; f < fEnd; ++f) {
5356       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5357       PetscInt       size;
5358 
5359       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5360       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5361     }
5362     break;
5363   case 2:
5364     /* Hex 2D */
5365     /* All cells have 4 faces */
5366     for(c = cStart; c < cEnd; ++c) {
5367       for(r = 0; r < 4; ++r) {
5368         const PetscInt newp = (c - cStart)*4 + r;
5369 
5370         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5371       }
5372     }
5373     /* Split faces have 2 vertices and the same cells as the parent */
5374     for(f = fStart; f < fEnd; ++f) {
5375       for(r = 0; r < 2; ++r) {
5376         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5377         PetscInt       size;
5378 
5379         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5380         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5381         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5382       }
5383     }
5384     /* Interior faces have 2 vertices and 2 cells */
5385     for(c = cStart; c < cEnd; ++c) {
5386       for(r = 0; r < 4; ++r) {
5387         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5388 
5389         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5390         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5391       }
5392     }
5393     /* Old vertices have identical supports */
5394     for(v = vStart; v < vEnd; ++v) {
5395       const PetscInt newp = vStartNew + (v - vStart);
5396       PetscInt       size;
5397 
5398       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5399       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5400     }
5401     /* Face vertices have 2 + cells supports */
5402     for(f = fStart; f < fEnd; ++f) {
5403       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5404       PetscInt       size;
5405 
5406       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5407       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5408     }
5409     /* Cell vertices have 4 supports */
5410     for(c = cStart; c < cEnd; ++c) {
5411       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5412 
5413       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5414     }
5415     break;
5416   case 3:
5417     /* Hybrid 2D */
5418     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5419     cMax = PetscMin(cEnd, cMax);
5420     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5421     fMax = PetscMin(fEnd, fMax);
5422     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5423     /* Interior cells have 3 faces */
5424     for(c = cStart; c < cMax; ++c) {
5425       for(r = 0; r < 4; ++r) {
5426         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5427 
5428         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5429       }
5430     }
5431     /* Hybrid cells have 4 faces */
5432     for(c = cMax; c < cEnd; ++c) {
5433       for(r = 0; r < 2; ++r) {
5434         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5435 
5436         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5437       }
5438     }
5439     /* Interior split faces have 2 vertices and the same cells as the parent */
5440     for(f = fStart; f < fMax; ++f) {
5441       for(r = 0; r < 2; ++r) {
5442         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5443         PetscInt       size;
5444 
5445         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5446         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5447         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5448       }
5449     }
5450     /* Interior cell faces have 2 vertices and 2 cells */
5451     for(c = cStart; c < cMax; ++c) {
5452       for(r = 0; r < 3; ++r) {
5453         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5454 
5455         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5456         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5457       }
5458     }
5459     /* Hybrid faces have 2 vertices and the same cells */
5460     for(f = fMax; f < fEnd; ++f) {
5461       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5462       PetscInt       size;
5463 
5464       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5465       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5466       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5467     }
5468     /* Hybrid cell faces have 2 vertices and 2 cells */
5469     for(c = cMax; c < cEnd; ++c) {
5470       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5471 
5472       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5473       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5474     }
5475     /* Old vertices have identical supports */
5476     for(v = vStart; v < vEnd; ++v) {
5477       const PetscInt newp = vStartNew + (v - vStart);
5478       PetscInt       size;
5479 
5480       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5481       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5482     }
5483     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5484     for(f = fStart; f < fMax; ++f) {
5485       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5486       const PetscInt *support;
5487       PetscInt        size, newSize = 2, s;
5488 
5489       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5490       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5491       for(s = 0; s < size; ++s) {
5492         if (support[s] >= cMax) {
5493           newSize += 1;
5494         } else {
5495           newSize += 2;
5496         }
5497       }
5498       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5499     }
5500     break;
5501   default:
5502     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5503   }
5504   PetscFunctionReturn(0);
5505 }
5506 
5507 #undef __FUNCT__
5508 #define __FUNCT__ "CellRefinerSetCones"
5509 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5510 {
5511   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;
5512   PetscInt       maxSupportSize, *supportRef;
5513   PetscErrorCode ierr;
5514 
5515   PetscFunctionBegin;
5516   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5517   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5518   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5519   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5520   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5521   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5522   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5523   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5524   switch(refiner) {
5525   case 1:
5526     /* Simplicial 2D */
5527     /*
5528      2
5529      |\
5530      | \
5531      |  \
5532      |   \
5533      | C  \
5534      |     \
5535      |      \
5536      2---1---1
5537      |\  D  / \
5538      | 2   0   \
5539      |A \ /  B  \
5540      0---0-------1
5541      */
5542     /* All cells have 3 faces */
5543     for(c = cStart; c < cEnd; ++c) {
5544       const PetscInt  newp = cStartNew + (c - cStart)*4;
5545       const PetscInt *cone, *ornt;
5546       PetscInt        coneNew[3], orntNew[3];
5547 
5548       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5549       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5550       /* A triangle */
5551       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5552       orntNew[0] = ornt[0];
5553       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5554       orntNew[1] = -2;
5555       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5556       orntNew[2] = ornt[2];
5557       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5558       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5559 #if 1
5560       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);
5561       for(p = 0; p < 3; ++p) {
5562         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);
5563       }
5564 #endif
5565       /* B triangle */
5566       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5567       orntNew[0] = ornt[0];
5568       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5569       orntNew[1] = ornt[1];
5570       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5571       orntNew[2] = -2;
5572       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5573       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5574 #if 1
5575       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);
5576       for(p = 0; p < 3; ++p) {
5577         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);
5578       }
5579 #endif
5580       /* C triangle */
5581       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5582       orntNew[0] = -2;
5583       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5584       orntNew[1] = ornt[1];
5585       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5586       orntNew[2] = ornt[2];
5587       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5588       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5589 #if 1
5590       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);
5591       for(p = 0; p < 3; ++p) {
5592         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);
5593       }
5594 #endif
5595       /* D triangle */
5596       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5597       orntNew[0] = 0;
5598       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5599       orntNew[1] = 0;
5600       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5601       orntNew[2] = 0;
5602       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5603       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5604 #if 1
5605       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);
5606       for(p = 0; p < 3; ++p) {
5607         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);
5608       }
5609 #endif
5610     }
5611     /* Split faces have 2 vertices and the same cells as the parent */
5612     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5613     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5614     for(f = fStart; f < fEnd; ++f) {
5615       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5616 
5617       for(r = 0; r < 2; ++r) {
5618         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5619         const PetscInt *cone, *support;
5620         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5621 
5622         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5623         coneNew[0] = vStartNew + (cone[0] - vStart);
5624         coneNew[1] = vStartNew + (cone[1] - vStart);
5625         coneNew[(r+1)%2] = newv;
5626         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5627 #if 1
5628         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5629         for(p = 0; p < 2; ++p) {
5630           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);
5631         }
5632 #endif
5633         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5634         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5635         for(s = 0; s < supportSize; ++s) {
5636           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5637           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5638           for(c = 0; c < coneSize; ++c) {
5639             if (cone[c] == f) {
5640               break;
5641             }
5642           }
5643           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5644         }
5645         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5646 #if 1
5647         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5648         for(p = 0; p < supportSize; ++p) {
5649           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);
5650         }
5651 #endif
5652       }
5653     }
5654     /* Interior faces have 2 vertices and 2 cells */
5655     for(c = cStart; c < cEnd; ++c) {
5656       const PetscInt *cone;
5657 
5658       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5659       for(r = 0; r < 3; ++r) {
5660         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5661         PetscInt       coneNew[2];
5662         PetscInt       supportNew[2];
5663 
5664         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5665         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5666         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5667 #if 1
5668         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5669         for(p = 0; p < 2; ++p) {
5670           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);
5671         }
5672 #endif
5673         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5674         supportNew[1] = (c - cStart)*4 + 3;
5675         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5676 #if 1
5677         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5678         for(p = 0; p < 2; ++p) {
5679           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);
5680         }
5681 #endif
5682       }
5683     }
5684     /* Old vertices have identical supports */
5685     for(v = vStart; v < vEnd; ++v) {
5686       const PetscInt  newp = vStartNew + (v - vStart);
5687       const PetscInt *support, *cone;
5688       PetscInt        size, s;
5689 
5690       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5691       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5692       for(s = 0; s < size; ++s) {
5693         PetscInt r = 0;
5694 
5695         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5696         if (cone[1] == v) r = 1;
5697         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5698       }
5699       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5700 #if 1
5701       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5702       for(p = 0; p < size; ++p) {
5703         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);
5704       }
5705 #endif
5706     }
5707     /* Face vertices have 2 + cells*2 supports */
5708     for(f = fStart; f < fEnd; ++f) {
5709       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5710       const PetscInt *cone, *support;
5711       PetscInt        size, s;
5712 
5713       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5714       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5715       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5716       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5717       for(s = 0; s < size; ++s) {
5718         PetscInt r = 0;
5719 
5720         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5721         if      (cone[1] == f) r = 1;
5722         else if (cone[2] == f) r = 2;
5723         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5724         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5725       }
5726       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5727 #if 1
5728       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5729       for(p = 0; p < 2+size*2; ++p) {
5730         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);
5731       }
5732 #endif
5733     }
5734     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5735     break;
5736   case 2:
5737     /* Hex 2D */
5738     /*
5739      3---------2---------2
5740      |         |         |
5741      |    D    2    C    |
5742      |         |         |
5743      3----3----0----1----1
5744      |         |         |
5745      |    A    0    B    |
5746      |         |         |
5747      0---------0---------1
5748      */
5749     /* All cells have 4 faces */
5750     for(c = cStart; c < cEnd; ++c) {
5751       const PetscInt  newp = (c - cStart)*4;
5752       const PetscInt *cone, *ornt;
5753       PetscInt        coneNew[4], orntNew[4];
5754 
5755       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5756       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5757       /* A quad */
5758       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5759       orntNew[0] = ornt[0];
5760       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5761       orntNew[1] = 0;
5762       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5763       orntNew[2] = -2;
5764       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5765       orntNew[3] = ornt[3];
5766       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5767       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5768 #if 1
5769       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);
5770       for(p = 0; p < 4; ++p) {
5771         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);
5772       }
5773 #endif
5774       /* B quad */
5775       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5776       orntNew[0] = ornt[0];
5777       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5778       orntNew[1] = ornt[1];
5779       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5780       orntNew[2] = 0;
5781       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5782       orntNew[3] = -2;
5783       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5784       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5785 #if 1
5786       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);
5787       for(p = 0; p < 4; ++p) {
5788         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);
5789       }
5790 #endif
5791       /* C quad */
5792       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5793       orntNew[0] = -2;
5794       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5795       orntNew[1] = ornt[1];
5796       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5797       orntNew[2] = ornt[2];
5798       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5799       orntNew[3] = 0;
5800       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5801       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5802 #if 1
5803       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);
5804       for(p = 0; p < 4; ++p) {
5805         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);
5806       }
5807 #endif
5808       /* D quad */
5809       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5810       orntNew[0] = 0;
5811       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5812       orntNew[1] = -2;
5813       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5814       orntNew[2] = ornt[2];
5815       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
5816       orntNew[3] = ornt[3];
5817       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5818       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5819 #if 1
5820       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);
5821       for(p = 0; p < 4; ++p) {
5822         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);
5823       }
5824 #endif
5825     }
5826     /* Split faces have 2 vertices and the same cells as the parent */
5827     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5828     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5829     for(f = fStart; f < fEnd; ++f) {
5830       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5831 
5832       for(r = 0; r < 2; ++r) {
5833         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5834         const PetscInt *cone, *support;
5835         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5836 
5837         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5838         coneNew[0] = vStartNew + (cone[0] - vStart);
5839         coneNew[1] = vStartNew + (cone[1] - vStart);
5840         coneNew[(r+1)%2] = newv;
5841         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5842 #if 1
5843         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5844         for(p = 0; p < 2; ++p) {
5845           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);
5846         }
5847 #endif
5848         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5849         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5850         for(s = 0; s < supportSize; ++s) {
5851           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5852           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5853           for(c = 0; c < coneSize; ++c) {
5854             if (cone[c] == f) {
5855               break;
5856             }
5857           }
5858           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
5859         }
5860         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5861 #if 1
5862         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5863         for(p = 0; p < supportSize; ++p) {
5864           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);
5865         }
5866 #endif
5867       }
5868     }
5869     /* Interior faces have 2 vertices and 2 cells */
5870     for(c = cStart; c < cEnd; ++c) {
5871       const PetscInt *cone;
5872       PetscInt        coneNew[2], supportNew[2];
5873 
5874       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5875       for(r = 0; r < 4; ++r) {
5876         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5877 
5878         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5879         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5880         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5881 #if 1
5882         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5883         for(p = 0; p < 2; ++p) {
5884           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);
5885         }
5886 #endif
5887         supportNew[0] = (c - cStart)*4 + r;
5888         supportNew[1] = (c - cStart)*4 + (r+1)%4;
5889         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5890 #if 1
5891         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5892         for(p = 0; p < 2; ++p) {
5893           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);
5894         }
5895 #endif
5896       }
5897     }
5898     /* Old vertices have identical supports */
5899     for(v = vStart; v < vEnd; ++v) {
5900       const PetscInt  newp = vStartNew + (v - vStart);
5901       const PetscInt *support, *cone;
5902       PetscInt        size, s;
5903 
5904       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5905       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5906       for(s = 0; s < size; ++s) {
5907         PetscInt r = 0;
5908 
5909         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5910         if (cone[1] == v) r = 1;
5911         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5912       }
5913       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5914 #if 1
5915       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5916       for(p = 0; p < size; ++p) {
5917         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);
5918       }
5919 #endif
5920     }
5921     /* Face vertices have 2 + cells supports */
5922     for(f = fStart; f < fEnd; ++f) {
5923       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5924       const PetscInt *cone, *support;
5925       PetscInt        size, s;
5926 
5927       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5928       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5929       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5930       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5931       for(s = 0; s < size; ++s) {
5932         PetscInt r = 0;
5933 
5934         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5935         if      (cone[1] == f) r = 1;
5936         else if (cone[2] == f) r = 2;
5937         else if (cone[3] == f) r = 3;
5938         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
5939       }
5940       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5941 #if 1
5942       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5943       for(p = 0; p < 2+size; ++p) {
5944         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);
5945       }
5946 #endif
5947     }
5948     /* Cell vertices have 4 supports */
5949     for(c = cStart; c < cEnd; ++c) {
5950       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5951       PetscInt       supportNew[4];
5952 
5953       for(r = 0; r < 4; ++r) {
5954         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5955       }
5956       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5957     }
5958     break;
5959   case 3:
5960     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5961     cMax = PetscMin(cEnd, cMax);
5962     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5963     fMax = PetscMin(fEnd, fMax);
5964     /* Interior cells have 3 faces */
5965     for(c = cStart; c < cMax; ++c) {
5966       const PetscInt  newp = cStartNew + (c - cStart)*4;
5967       const PetscInt *cone, *ornt;
5968       PetscInt        coneNew[3], orntNew[3];
5969 
5970       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5971       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5972       /* A triangle */
5973       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5974       orntNew[0] = ornt[0];
5975       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
5976       orntNew[1] = -2;
5977       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5978       orntNew[2] = ornt[2];
5979       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5980       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5981 #if 1
5982       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);
5983       for(p = 0; p < 3; ++p) {
5984         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);
5985       }
5986 #endif
5987       /* B triangle */
5988       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5989       orntNew[0] = ornt[0];
5990       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5991       orntNew[1] = ornt[1];
5992       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
5993       orntNew[2] = -2;
5994       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5995       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5996 #if 1
5997       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);
5998       for(p = 0; p < 3; ++p) {
5999         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);
6000       }
6001 #endif
6002       /* C triangle */
6003       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6004       orntNew[0] = -2;
6005       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6006       orntNew[1] = ornt[1];
6007       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6008       orntNew[2] = ornt[2];
6009       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6010       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6011 #if 1
6012       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);
6013       for(p = 0; p < 3; ++p) {
6014         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);
6015       }
6016 #endif
6017       /* D triangle */
6018       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6019       orntNew[0] = 0;
6020       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6021       orntNew[1] = 0;
6022       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6023       orntNew[2] = 0;
6024       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6025       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6026 #if 1
6027       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);
6028       for(p = 0; p < 3; ++p) {
6029         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);
6030       }
6031 #endif
6032     }
6033     /*
6034      2----3----3
6035      |         |
6036      |    B    |
6037      |         |
6038      0----4--- 1
6039      |         |
6040      |    A    |
6041      |         |
6042      0----2----1
6043      */
6044     /* Hybrid cells have 4 faces */
6045     for(c = cMax; c < cEnd; ++c) {
6046       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6047       const PetscInt *cone, *ornt;
6048       PetscInt        coneNew[4], orntNew[4];
6049 
6050       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6051       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6052       /* A quad */
6053       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6054       orntNew[0] = ornt[0];
6055       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6056       orntNew[1] = ornt[1];
6057       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6058       orntNew[2] = 0;
6059       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6060       orntNew[3] = 0;
6061       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6062       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6063 #if 1
6064       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);
6065       for(p = 0; p < 4; ++p) {
6066         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);
6067       }
6068 #endif
6069       /* B quad */
6070       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6071       orntNew[0] = ornt[0];
6072       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6073       orntNew[1] = ornt[1];
6074       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6075       orntNew[2] = 0;
6076       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6077       orntNew[3] = 0;
6078       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6079       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6080 #if 1
6081       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);
6082       for(p = 0; p < 4; ++p) {
6083         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);
6084       }
6085 #endif
6086     }
6087     /* Interior split faces have 2 vertices and the same cells as the parent */
6088     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6089     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6090     for(f = fStart; f < fMax; ++f) {
6091       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6092 
6093       for(r = 0; r < 2; ++r) {
6094         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6095         const PetscInt *cone, *support;
6096         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6097 
6098         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6099         coneNew[0] = vStartNew + (cone[0] - vStart);
6100         coneNew[1] = vStartNew + (cone[1] - vStart);
6101         coneNew[(r+1)%2] = newv;
6102         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6103 #if 1
6104         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6105         for(p = 0; p < 2; ++p) {
6106           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);
6107         }
6108 #endif
6109         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6110         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6111         for(s = 0; s < supportSize; ++s) {
6112           if (support[s] >= cMax) {
6113             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6114           } else {
6115             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6116             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6117             for(c = 0; c < coneSize; ++c) {
6118               if (cone[c] == f) {
6119                 break;
6120               }
6121             }
6122             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6123           }
6124         }
6125         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6126 #if 1
6127         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6128         for(p = 0; p < supportSize; ++p) {
6129           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);
6130         }
6131 #endif
6132       }
6133     }
6134     /* Interior cell faces have 2 vertices and 2 cells */
6135     for(c = cStart; c < cMax; ++c) {
6136       const PetscInt *cone;
6137 
6138       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6139       for(r = 0; r < 3; ++r) {
6140         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6141         PetscInt       coneNew[2];
6142         PetscInt       supportNew[2];
6143 
6144         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6145         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6146         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6147 #if 1
6148         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6149         for(p = 0; p < 2; ++p) {
6150           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);
6151         }
6152 #endif
6153         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6154         supportNew[1] = (c - cStart)*4 + 3;
6155         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6156 #if 1
6157         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6158         for(p = 0; p < 2; ++p) {
6159           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);
6160         }
6161 #endif
6162       }
6163     }
6164     /* Interior hybrid faces have 2 vertices and the same cells */
6165     for(f = fMax; f < fEnd; ++f) {
6166       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6167       const PetscInt *cone;
6168       const PetscInt *support;
6169       PetscInt        coneNew[2];
6170       PetscInt        supportNew[2];
6171       PetscInt        size, s, r;
6172 
6173       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6174       coneNew[0] = vStartNew + (cone[0] - vStart);
6175       coneNew[1] = vStartNew + (cone[1] - vStart);
6176       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6177 #if 1
6178       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6179       for(p = 0; p < 2; ++p) {
6180         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6181       }
6182 #endif
6183       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6184       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6185       for(s = 0; s < size; ++s) {
6186         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6187         for(r = 0; r < 2; ++r) {
6188           if (cone[r+2] == f) break;
6189         }
6190         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6191       }
6192       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6193 #if 1
6194       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6195       for(p = 0; p < size; ++p) {
6196         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);
6197       }
6198 #endif
6199     }
6200     /* Cell hybrid faces have 2 vertices and 2 cells */
6201     for(c = cMax; c < cEnd; ++c) {
6202       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6203       const PetscInt *cone;
6204       PetscInt        coneNew[2];
6205       PetscInt        supportNew[2];
6206 
6207       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6208       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6209       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6210       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6211 #if 1
6212       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6213       for(p = 0; p < 2; ++p) {
6214         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);
6215       }
6216 #endif
6217       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6218       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6219       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6220 #if 1
6221       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6222       for(p = 0; p < 2; ++p) {
6223         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);
6224       }
6225 #endif
6226     }
6227     /* Old vertices have identical supports */
6228     for(v = vStart; v < vEnd; ++v) {
6229       const PetscInt  newp = vStartNew + (v - vStart);
6230       const PetscInt *support, *cone;
6231       PetscInt        size, s;
6232 
6233       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6234       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6235       for(s = 0; s < size; ++s) {
6236         if (support[s] >= fMax) {
6237           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6238         } else {
6239           PetscInt r = 0;
6240 
6241           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6242           if (cone[1] == v) r = 1;
6243           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6244         }
6245       }
6246       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6247 #if 1
6248       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6249       for(p = 0; p < size; ++p) {
6250         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);
6251       }
6252 #endif
6253     }
6254     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6255     for(f = fStart; f < fMax; ++f) {
6256       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6257       const PetscInt *cone, *support;
6258       PetscInt        size, newSize = 2, s;
6259 
6260       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6261       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6262       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6263       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6264       for(s = 0; s < size; ++s) {
6265         PetscInt r = 0;
6266 
6267         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6268         if (support[s] >= cMax) {
6269           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6270           newSize += 1;
6271         } else {
6272           if      (cone[1] == f) r = 1;
6273           else if (cone[2] == f) r = 2;
6274           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6275           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6276           newSize += 2;
6277         }
6278       }
6279       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6280 #if 1
6281       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6282       for(p = 0; p < newSize; ++p) {
6283         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);
6284       }
6285 #endif
6286     }
6287     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6288     break;
6289   default:
6290     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6291   }
6292   PetscFunctionReturn(0);
6293 }
6294 
6295 #undef __FUNCT__
6296 #define __FUNCT__ "CellRefinerSetCoordinates"
6297 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6298 {
6299   PetscSection   coordSection, coordSectionNew;
6300   Vec            coordinates, coordinatesNew;
6301   PetscScalar   *coords, *coordsNew;
6302   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6303   PetscErrorCode ierr;
6304 
6305   PetscFunctionBegin;
6306   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6307   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6308   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6309   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6310   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6311   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6312   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6313   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6314   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6315   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6316   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6317   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6318   if (fMax < 0) fMax = fEnd;
6319   switch(refiner) {
6320   case 1:
6321   case 2:
6322   case 3:
6323     /* Simplicial and Hex 2D */
6324     /* All vertices have the dim coordinates */
6325     for(v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6326       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6327       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6328     }
6329     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6330     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6331     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6332     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6333     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6334     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6335     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6336     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6337     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6338     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6339     /* Old vertices have the same coordinates */
6340     for(v = vStart; v < vEnd; ++v) {
6341       const PetscInt newv = vStartNew + (v - vStart);
6342       PetscInt       off, offnew, d;
6343 
6344       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6345       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6346       for(d = 0; d < dim; ++d) {
6347         coordsNew[offnew+d] = coords[off+d];
6348       }
6349     }
6350     /* Face vertices have the average of endpoint coordinates */
6351     for(f = fStart; f < fMax; ++f) {
6352       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6353       const PetscInt *cone;
6354       PetscInt        coneSize, offA, offB, offnew, d;
6355 
6356       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6357       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6358       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6359       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6360       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6361       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6362       for(d = 0; d < dim; ++d) {
6363         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6364       }
6365     }
6366     /* Just Hex 2D */
6367     if (refiner == 2) {
6368       /* Cell vertices have the average of corner coordinates */
6369       for(c = cStart; c < cEnd; ++c) {
6370         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6371         PetscInt      *cone = PETSC_NULL;
6372         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6373 
6374         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6375         for(p = 0; p < closureSize*2; p += 2) {
6376           const PetscInt point = cone[p];
6377           if ((point >= vStart) && (point < vEnd)) {
6378             cone[coneSize++] = point;
6379           }
6380         }
6381         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6382         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6383         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6384         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6385         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6386         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6387         for(d = 0; d < dim; ++d) {
6388           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6389         }
6390         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6391       }
6392     }
6393     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6394     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6395     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6396     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6397     break;
6398   default:
6399     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6400   }
6401   PetscFunctionReturn(0);
6402 }
6403 
6404 #undef __FUNCT__
6405 #define __FUNCT__ "DMPlexCreateProcessSF"
6406 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6407 {
6408   PetscInt           numRoots, numLeaves, l;
6409   const PetscInt    *localPoints;
6410   const PetscSFNode *remotePoints;
6411   PetscInt          *localPointsNew;
6412   PetscSFNode       *remotePointsNew;
6413   PetscInt          *ranks, *ranksNew;
6414   PetscErrorCode     ierr;
6415 
6416   PetscFunctionBegin;
6417   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6418   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6419   for(l = 0; l < numLeaves; ++l) {
6420     ranks[l] = remotePoints[l].rank;
6421   }
6422   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6423   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6424   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6425   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6426   for(l = 0; l < numLeaves; ++l) {
6427     ranksNew[l]              = ranks[l];
6428     localPointsNew[l]        = l;
6429     remotePointsNew[l].index = 0;
6430     remotePointsNew[l].rank  = ranksNew[l];
6431   }
6432   ierr = PetscFree(ranks);CHKERRQ(ierr);
6433   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6434   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6435   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6436   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6437   PetscFunctionReturn(0);
6438 }
6439 
6440 #undef __FUNCT__
6441 #define __FUNCT__ "CellRefinerCreateSF"
6442 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6443 {
6444   PetscSF            sf, sfNew, sfProcess;
6445   IS                 processRanks;
6446   MPI_Datatype       depthType;
6447   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6448   const PetscInt    *localPoints, *neighbors;
6449   const PetscSFNode *remotePoints;
6450   PetscInt          *localPointsNew;
6451   PetscSFNode       *remotePointsNew;
6452   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6453   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6454   PetscErrorCode     ierr;
6455 
6456   PetscFunctionBegin;
6457   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6458   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6459   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6460   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6461   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6462   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6463   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6464   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6465   switch(refiner) {
6466   case 3:
6467     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6468     cMax = PetscMin(cEnd, cMax);
6469     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6470     fMax = PetscMin(fEnd, fMax);
6471   }
6472   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6473   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6474   /* Caculate size of new SF */
6475   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6476   if (numRoots < 0) PetscFunctionReturn(0);
6477   for(l = 0; l < numLeaves; ++l) {
6478     const PetscInt p = localPoints[l];
6479 
6480     switch(refiner) {
6481     case 1:
6482       /* Simplicial 2D */
6483       if ((p >= vStart) && (p < vEnd)) {
6484         /* Old vertices stay the same */
6485         ++numLeavesNew;
6486       } else if ((p >= fStart) && (p < fEnd)) {
6487         /* Old faces add new faces and vertex */
6488         numLeavesNew += 1 + 2;
6489       } else if ((p >= cStart) && (p < cEnd)) {
6490         /* Old cells add new cells and interior faces */
6491         numLeavesNew += 4 + 3;
6492       }
6493       break;
6494     case 2:
6495       /* Hex 2D */
6496       if ((p >= vStart) && (p < vEnd)) {
6497         /* Old vertices stay the same */
6498         ++numLeavesNew;
6499       } else if ((p >= fStart) && (p < fEnd)) {
6500         /* Old faces add new faces and vertex */
6501         numLeavesNew += 1 + 2;
6502       } else if ((p >= cStart) && (p < cEnd)) {
6503         /* Old cells add new cells and interior faces */
6504         numLeavesNew += 4 + 4;
6505       }
6506       break;
6507     default:
6508       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6509     }
6510   }
6511   /* Communicate depthSizes for each remote rank */
6512   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6513   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6514   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6515   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);
6516   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6517   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6518   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6519   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6520   for(n = 0; n < numNeighbors; ++n) {
6521     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6522   }
6523   depthSizeOld[depth]   = cMax;
6524   depthSizeOld[0]       = vMax;
6525   depthSizeOld[depth-1] = fMax;
6526   depthSizeOld[1]       = eMax;
6527   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6528   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6529   depthSizeOld[depth]   = cEnd - cStart;
6530   depthSizeOld[0]       = vEnd - vStart;
6531   depthSizeOld[depth-1] = fEnd - fStart;
6532   depthSizeOld[1]       = eEnd - eStart;
6533   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6534   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6535   for(n = 0; n < numNeighbors; ++n) {
6536     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6537   }
6538   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6539   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6540   /* Calculate new point SF */
6541   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6542   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6543   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6544   for(l = 0, m = 0; l < numLeaves; ++l) {
6545     PetscInt    p     = localPoints[l];
6546     PetscInt    rp    = remotePoints[l].index, n;
6547     PetscMPIInt rrank = remotePoints[l].rank;
6548 
6549     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6550     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6551     switch(refiner) {
6552     case 1:
6553       /* Simplicial 2D */
6554       if ((p >= vStart) && (p < vEnd)) {
6555         /* Old vertices stay the same */
6556         localPointsNew[m]        = vStartNew     + (p  - vStart);
6557         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6558         remotePointsNew[m].rank  = rrank;
6559         ++m;
6560       } else if ((p >= fStart) && (p < fEnd)) {
6561         /* Old faces add new faces and vertex */
6562         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6563         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6564         remotePointsNew[m].rank  = rrank;
6565         ++m;
6566         for(r = 0; r < 2; ++r, ++m) {
6567           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6568           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6569           remotePointsNew[m].rank  = rrank;
6570         }
6571       } else if ((p >= cStart) && (p < cEnd)) {
6572         /* Old cells add new cells and interior faces */
6573         for(r = 0; r < 4; ++r, ++m) {
6574           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6575           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6576           remotePointsNew[m].rank  = rrank;
6577         }
6578         for(r = 0; r < 3; ++r, ++m) {
6579           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6580           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6581           remotePointsNew[m].rank  = rrank;
6582         }
6583       }
6584       break;
6585     case 2:
6586       /* Hex 2D */
6587       if ((p >= vStart) && (p < vEnd)) {
6588         /* Old vertices stay the same */
6589         localPointsNew[m]        = vStartNew     + (p  - vStart);
6590         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6591         remotePointsNew[m].rank  = rrank;
6592         ++m;
6593       } else if ((p >= fStart) && (p < fEnd)) {
6594         /* Old faces add new faces and vertex */
6595         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6596         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6597         remotePointsNew[m].rank  = rrank;
6598         ++m;
6599         for(r = 0; r < 2; ++r, ++m) {
6600           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6601           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6602           remotePointsNew[m].rank  = rrank;
6603         }
6604       } else if ((p >= cStart) && (p < cEnd)) {
6605         /* Old cells add new cells and interior faces */
6606         for(r = 0; r < 4; ++r, ++m) {
6607           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6608           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6609           remotePointsNew[m].rank  = rrank;
6610         }
6611         for(r = 0; r < 4; ++r, ++m) {
6612           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6613           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6614           remotePointsNew[m].rank  = rrank;
6615         }
6616       }
6617       break;
6618     case 3:
6619       /* Hybrid simplicial 2D */
6620       if ((p >= vStart) && (p < vEnd)) {
6621         /* Old vertices stay the same */
6622         localPointsNew[m]        = vStartNew     + (p  - vStart);
6623         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6624         remotePointsNew[m].rank  = rrank;
6625         ++m;
6626       } else if ((p >= fStart) && (p < fMax)) {
6627         /* Old interior faces add new faces and vertex */
6628         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6629         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6630         remotePointsNew[m].rank  = rrank;
6631         ++m;
6632         for(r = 0; r < 2; ++r, ++m) {
6633           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6634           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6635           remotePointsNew[m].rank  = rrank;
6636         }
6637       } else if ((p >= fMax) && (p < fEnd)) {
6638         /* Old hybrid faces stay the same */
6639         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6640         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6641         remotePointsNew[m].rank  = rrank;
6642         ++m;
6643       } else if ((p >= cStart) && (p < cMax)) {
6644         /* Old interior cells add new cells and interior faces */
6645         for(r = 0; r < 4; ++r, ++m) {
6646           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6647           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6648           remotePointsNew[m].rank  = rrank;
6649         }
6650         for(r = 0; r < 3; ++r, ++m) {
6651           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6652           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6653           remotePointsNew[m].rank  = rrank;
6654         }
6655       } else if ((p >= cStart) && (p < cMax)) {
6656         /* Old hybrid cells add new cells and hybrid face */
6657         for(r = 0; r < 2; ++r, ++m) {
6658           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6659           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6660           remotePointsNew[m].rank  = rrank;
6661         }
6662         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6663         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]);
6664         remotePointsNew[m].rank  = rrank;
6665         ++m;
6666       }
6667       break;
6668     default:
6669       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6670     }
6671   }
6672   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6673   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6674   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6675   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6676   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6677   PetscFunctionReturn(0);
6678 }
6679 
6680 #undef __FUNCT__
6681 #define __FUNCT__ "CellRefinerCreateLabels"
6682 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6683 {
6684   PetscInt       numLabels, l;
6685   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6686   PetscErrorCode ierr;
6687 
6688   PetscFunctionBegin;
6689   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6690   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6691   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6692   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6693   cStartNew = 0;
6694   vStartNew = depthSize[2];
6695   fStartNew = depthSize[2] + depthSize[0];
6696   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6697   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6698   switch(refiner) {
6699   case 3:
6700     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6701     cMax = PetscMin(cEnd, cMax);
6702     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6703     fMax = PetscMin(fEnd, fMax);
6704   }
6705   for(l = 0; l < numLabels; ++l) {
6706     DMLabel         label, labelNew;
6707     const char     *lname;
6708     PetscBool       isDepth;
6709     IS              valueIS;
6710     const PetscInt *values;
6711     PetscInt        numValues, val;
6712 
6713     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6714     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6715     if (isDepth) continue;
6716     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6717     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6718     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6719     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6720     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6721     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6722     for(val = 0; val < numValues; ++val) {
6723       IS              pointIS;
6724       const PetscInt *points;
6725       PetscInt        numPoints, n;
6726 
6727       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6728       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6729       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6730       for(n = 0; n < numPoints; ++n) {
6731         const PetscInt p = points[n];
6732         switch(refiner) {
6733         case 1:
6734           /* Simplicial 2D */
6735           if ((p >= vStart) && (p < vEnd)) {
6736             /* Old vertices stay the same */
6737             newp = vStartNew + (p - vStart);
6738             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6739           } else if ((p >= fStart) && (p < fEnd)) {
6740             /* Old faces add new faces and vertex */
6741             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6742             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6743             for(r = 0; r < 2; ++r) {
6744               newp = fStartNew + (p - fStart)*2 + r;
6745               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6746             }
6747           } else if ((p >= cStart) && (p < cEnd)) {
6748             /* Old cells add new cells and interior faces */
6749             for(r = 0; r < 4; ++r) {
6750               newp = cStartNew + (p - cStart)*4 + r;
6751               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6752             }
6753             for(r = 0; r < 3; ++r) {
6754               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6755               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6756             }
6757           }
6758           break;
6759         case 2:
6760           /* Hex 2D */
6761           if ((p >= vStart) && (p < vEnd)) {
6762             /* Old vertices stay the same */
6763             newp = vStartNew + (p - vStart);
6764             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6765           } else if ((p >= fStart) && (p < fEnd)) {
6766             /* Old faces add new faces and vertex */
6767             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6768             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6769             for(r = 0; r < 2; ++r) {
6770               newp = fStartNew + (p - fStart)*2 + r;
6771               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6772             }
6773           } else if ((p >= cStart) && (p < cEnd)) {
6774             /* Old cells add new cells and interior faces and vertex */
6775             for(r = 0; r < 4; ++r) {
6776               newp = cStartNew + (p - cStart)*4 + r;
6777               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6778             }
6779             for(r = 0; r < 4; ++r) {
6780               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6781               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6782             }
6783             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6784             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6785           }
6786           break;
6787         case 3:
6788           /* Hybrid simplicial 2D */
6789           if ((p >= vStart) && (p < vEnd)) {
6790             /* Old vertices stay the same */
6791             newp = vStartNew + (p - vStart);
6792             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6793           } else if ((p >= fStart) && (p < fMax)) {
6794             /* Old interior faces add new faces and vertex */
6795             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6796             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6797             for(r = 0; r < 2; ++r) {
6798               newp = fStartNew + (p - fStart)*2 + r;
6799               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6800             }
6801           } else if ((p >= fMax) && (p < fEnd)) {
6802             /* Old hybrid faces stay the same */
6803             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6804             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6805           } else if ((p >= cStart) && (p < cMax)) {
6806             /* Old interior cells add new cells and interior faces */
6807             for(r = 0; r < 4; ++r) {
6808               newp = cStartNew + (p - cStart)*4 + r;
6809               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6810             }
6811             for(r = 0; r < 3; ++r) {
6812               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6813               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6814             }
6815           } else if ((p >= cMax) && (p < cEnd)) {
6816             /* Old hybrid cells add new cells and hybrid face */
6817             for(r = 0; r < 2; ++r) {
6818               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6819               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6820             }
6821             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6822             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6823           }
6824           break;
6825         default:
6826           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6827         }
6828       }
6829       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6830       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6831     }
6832     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6833     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6834     if (0) {
6835       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6836       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6837       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6838     }
6839   }
6840   PetscFunctionReturn(0);
6841 }
6842 
6843 #undef __FUNCT__
6844 #define __FUNCT__ "DMPlexRefine_Uniform"
6845 /* This will only work for interpolated meshes */
6846 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6847 {
6848   DM              rdm;
6849   PetscInt       *depthSize;
6850   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
6851   PetscErrorCode  ierr;
6852 
6853   PetscFunctionBegin;
6854   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
6855   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6856   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6857   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6858   /* Calculate number of new points of each depth */
6859   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6860   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
6861   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6862   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6863   /* Step 1: Set chart */
6864   for(d = 0; d <= depth; ++d) {
6865     pEnd += depthSize[d];
6866   }
6867   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6868   /* Step 2: Set cone/support sizes */
6869   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6870   /* Step 3: Setup refined DM */
6871   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6872   /* Step 4: Set cones and supports */
6873   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6874   /* Step 5: Stratify */
6875   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6876   /* Step 6: Set coordinates for vertices */
6877   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6878   /* Step 7: Create pointSF */
6879   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6880   /* Step 8: Create labels */
6881   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6882   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6883 
6884   *dmRefined = rdm;
6885 #if 0
6886   DM_Plex *mesh = (DM_Plex *) dm->data;
6887   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
6888   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
6889 
6890   PetscFunctionBegin;
6891   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6892   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
6893   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6894   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6895   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
6896 
6897   /* Count number of new cells which are normal and extra */
6898   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
6899   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
6900   for(c = cStart; c < cEnd2; ++c) {
6901     PetscInt n;
6902     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
6903     newNumCellsNormal += n;
6904   }
6905   for(c = cEnd2; c < cEnd; ++c) {
6906     PetscInt n;
6907     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
6908     newNumCellsExtra += n;
6909   }
6910   newNumCells = newNumCellsNormal + newNumCellsExtra;
6911   /* Count number of new vertices which are normal and extra */
6912   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
6913   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
6914   for(c = cStart; c < cEnd; ++c) {
6915     PetscInt *closure = PETSC_NULL;
6916     PetscInt  closureSize, numCorners = 0, p;
6917 
6918     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6919     for(p = 0; p < closureSize*2; p += 2) {
6920       const PetscInt point = closure[p];
6921       if ((point >= vStart) && (point < vEnd)) {
6922         closure[numCorners++] = point;
6923       }
6924     }
6925     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
6926     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6927   }
6928   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
6929   for(c = cEnd2; c < cEnd; ++c) {
6930     PetscInt *closure = PETSC_NULL;
6931     PetscInt  closureSize, numCorners = 0, p;
6932 
6933     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6934     for(p = 0; p < closureSize*2; p += 2) {
6935       const PetscInt point = closure[p];
6936       if ((point >= vStart) && (point < vEnd)) {
6937         closure[numCorners++] = point;
6938       }
6939     }
6940     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
6941     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6942   } /* for */
6943   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
6944   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
6945 
6946 #if 1
6947   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
6948   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
6949   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
6950   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
6951   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
6952   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
6953   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
6954   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
6955   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
6956   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
6957   ierr = PetscSynchronizedFlush(comm);
6958 #endif
6959 
6960   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
6961   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
6962   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
6963   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
6964   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
6965   /* Set cone and support sizes for new normal cells */
6966   PetscInt newCell = 0;
6967   for(c = cStart; c < cEnd2; ++c) {
6968     PetscInt coneSize, n, i;
6969 
6970     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6971     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
6972     for(i = 0; i < n; ++i, ++newCell) {
6973       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
6974     }
6975 
6976     PetscInt *closure = PETSC_NULL;
6977     PetscInt  closureSize, numCorners = 0, p;
6978 
6979     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6980     for(p = 0; p < closureSize*2; p += 2) {
6981       const PetscInt point = closure[p];
6982       if ((point >= vStart) && (point < vEnd)) {
6983         closure[numCorners++] = point;
6984       }
6985     }
6986     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); // refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
6987     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6988   }
6989 
6990   /* Reset current new cell value and loop over censored cells. */
6991   curNewCell = _orderNewMesh->cellsCensored().min();
6992   oldCellsEnd = _orderOldMesh->cellsCensored().end();
6993   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
6994     /* Set new cone and support sizes */
6995     cV.clear();
6996     sieve->cone(*c_iter, cV);
6997     const point_type* cone = cV.getPoints();
6998     const int coneSize = cV.getSize();
6999 
7000     const point_type* newCells;
7001     int numNewCells = 0;
7002     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7003 
7004     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7005       newSieve->setConeSize(curNewCell, coneSize);
7006       for(int iVertex=0; iVertex < coneSize; ++iVertex) {
7007 	newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7008       } /* for */
7009     } /* for */
7010   } /* for */
7011   newSieve->allocate();
7012 
7013   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7014 
7015   /* Create refined cells in new sieve. */
7016   curNewCell = _orderNewMesh->cellsNormal().min();
7017   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7018   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7019     cV.clear();
7020     sieve->cone(*c_iter, cV);
7021     const point_type *cone = cV.getPoints();
7022     const int coneSize = cV.getSize();
7023 
7024     const point_type* newCells;
7025     int numNewCells = 0;
7026     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7027 
7028     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7029       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7030     } /* for */
7031   } /* for */
7032   curNewCell = _orderNewMesh->cellsCensored().min();
7033   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7034   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7035     cV.clear();
7036     sieve->cone(*c_iter, cV);
7037     const point_type *cone = cV.getPoints();
7038     const int coneSize = cV.getSize();
7039 
7040     const point_type* newCells;
7041     int numNewCells = 0;
7042     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7043 
7044     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7045       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7046     } /* for */
7047   } /* for */
7048   newSieve->symmetrize();
7049 
7050   /* Set coordinates in refined mesh. */
7051   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7052   assert(!coordinates.isNull());
7053   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7054   assert(!newCoordinates.isNull());
7055 
7056   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7057   assert(vertices->size() > 0);
7058   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7059   assert(spaceDim > 0);
7060   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7061 
7062   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7063   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7064     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7065   } /* for */
7066   newCoordinates->allocatePoint();
7067 
7068   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7069   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7070     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7071     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7072   } /* for */
7073   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7074   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7075     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7076     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7077   } /* for */
7078 
7079   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7080 
7081   /* Create sensored depth */
7082   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7083   assert(!censoredLabel.isNull());
7084 
7085   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7086 
7087   newSieve->roots(depthVisitor);
7088   while(depthVisitor.isModified()) {
7089     /* FIX: Avoid the copy here somehow by fixing the traversal */
7090     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7091 
7092     depthVisitor.clear();
7093     newSieve->support(modifiedPoints, depthVisitor);
7094   } /* while */
7095   /* Stratify refined mesh */
7096   /* Calculate new point SF */
7097   _calcNewOverlap(newMesh, mesh, refiner);
7098   /* Calculate new labels */
7099   _createLabels(newMesh, mesh, refiner);
7100 #endif
7101   PetscFunctionReturn(0);
7102 }
7103 
7104 #undef __FUNCT__
7105 #define __FUNCT__ "DMPlexSetRefinementUniform"
7106 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7107 {
7108   DM_Plex *mesh = (DM_Plex *) dm->data;
7109 
7110   PetscFunctionBegin;
7111   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7112   mesh->refinementUniform = refinementUniform;
7113   PetscFunctionReturn(0);
7114 }
7115 
7116 #undef __FUNCT__
7117 #define __FUNCT__ "DMPlexGetRefinementUniform"
7118 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7119 {
7120   DM_Plex *mesh = (DM_Plex *) dm->data;
7121 
7122   PetscFunctionBegin;
7123   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7124   PetscValidPointer(refinementUniform,  2);
7125   *refinementUniform = mesh->refinementUniform;
7126   PetscFunctionReturn(0);
7127 }
7128 
7129 #undef __FUNCT__
7130 #define __FUNCT__ "DMPlexSetRefinementLimit"
7131 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7132 {
7133   DM_Plex *mesh = (DM_Plex *) dm->data;
7134 
7135   PetscFunctionBegin;
7136   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7137   mesh->refinementLimit = refinementLimit;
7138   PetscFunctionReturn(0);
7139 }
7140 
7141 #undef __FUNCT__
7142 #define __FUNCT__ "DMPlexGetRefinementLimit"
7143 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7144 {
7145   DM_Plex *mesh = (DM_Plex *) dm->data;
7146 
7147   PetscFunctionBegin;
7148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7149   PetscValidPointer(refinementLimit,  2);
7150   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7151   *refinementLimit = mesh->refinementLimit;
7152   PetscFunctionReturn(0);
7153 }
7154 
7155 #undef __FUNCT__
7156 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7157 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7158 {
7159   PetscInt       dim, cStart, coneSize, cMax;
7160   PetscErrorCode ierr;
7161 
7162   PetscFunctionBegin;
7163   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7164   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7165   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7166   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7167   switch(dim) {
7168   case 2:
7169     switch(coneSize) {
7170     case 3:
7171       if (cMax >= 0) {
7172         *cellRefiner = 3; /* Hybrid */
7173       } else {
7174         *cellRefiner = 1; /* Triangular */
7175       }
7176       break;
7177     case 4:
7178       if (cMax >= 0) {
7179         *cellRefiner = 4; /* Hybrid */
7180       } else {
7181         *cellRefiner = 2; /* Quadrilateral */
7182       }
7183       break;
7184     default:
7185       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7186     }
7187     break;
7188   default:
7189     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7190   }
7191   PetscFunctionReturn(0);
7192 }
7193 
7194 #undef __FUNCT__
7195 #define __FUNCT__ "DMRefine_Plex"
7196 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7197 {
7198   PetscReal      refinementLimit;
7199   PetscInt       dim, cStart, cEnd;
7200   char           genname[1024], *name = PETSC_NULL;
7201   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7202   PetscErrorCode ierr;
7203 
7204   PetscFunctionBegin;
7205   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7206   if (isUniform) {
7207     CellRefiner cellRefiner;
7208 
7209     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7210     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7211     PetscFunctionReturn(0);
7212   }
7213   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7214   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7215   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7216   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7217   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7218   if (flg) {name = genname;}
7219   if (name) {
7220     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7221     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7222     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7223   }
7224   switch(dim) {
7225   case 2:
7226     if (!name || isTriangle) {
7227 #ifdef PETSC_HAVE_TRIANGLE
7228       double  *maxVolumes;
7229       PetscInt c;
7230 
7231       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7232       for (c = 0; c < cEnd-cStart; ++c) {
7233         maxVolumes[c] = refinementLimit;
7234       }
7235       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7236 #else
7237       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7238 #endif
7239     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7240     break;
7241   case 3:
7242     if (!name || isCTetgen) {
7243 #ifdef PETSC_HAVE_CTETGEN
7244       PetscReal *maxVolumes;
7245       PetscInt   c;
7246 
7247       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7248       for (c = 0; c < cEnd-cStart; ++c) {
7249         maxVolumes[c] = refinementLimit;
7250       }
7251       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7252 #else
7253       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7254 #endif
7255     } else if (isTetgen) {
7256 #ifdef PETSC_HAVE_TETGEN
7257       double  *maxVolumes;
7258       PetscInt c;
7259 
7260       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7261       for (c = 0; c < cEnd-cStart; ++c) {
7262         maxVolumes[c] = refinementLimit;
7263       }
7264       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7265 #else
7266       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7267 #endif
7268     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7269     break;
7270   default:
7271     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7272   }
7273   PetscFunctionReturn(0);
7274 }
7275 
7276 #undef __FUNCT__
7277 #define __FUNCT__ "DMPlexGetDepth"
7278 /*@
7279   DMPlexGetDepth - get the number of strata
7280 
7281   Not Collective
7282 
7283   Input Parameters:
7284 . dm           - The DMPlex object
7285 
7286   Output Parameters:
7287 . depth - number of strata
7288 
7289   Level: developer
7290 
7291   Notes:
7292   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7293 
7294 .keywords: mesh, points
7295 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7296 @*/
7297 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7298 {
7299   PetscInt       d;
7300   PetscErrorCode ierr;
7301 
7302   PetscFunctionBegin;
7303   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7304   PetscValidPointer(depth, 2);
7305   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7306   *depth = d-1;
7307   PetscFunctionReturn(0);
7308 }
7309 
7310 #undef __FUNCT__
7311 #define __FUNCT__ "DMPlexGetDepthStratum"
7312 /*@
7313   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7314 
7315   Not Collective
7316 
7317   Input Parameters:
7318 + dm           - The DMPlex object
7319 - stratumValue - The requested depth
7320 
7321   Output Parameters:
7322 + start - The first point at this depth
7323 - end   - One beyond the last point at this depth
7324 
7325   Level: developer
7326 
7327 .keywords: mesh, points
7328 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7329 @*/
7330 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) {
7331   DM_Plex    *mesh = (DM_Plex *) dm->data;
7332   DMLabel        next = mesh->labels;
7333   PetscBool      flg  = PETSC_FALSE;
7334   PetscInt       depth;
7335   PetscErrorCode ierr;
7336 
7337   PetscFunctionBegin;
7338   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7339   if (stratumValue < 0) {
7340     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7341     PetscFunctionReturn(0);
7342   } else {
7343     PetscInt pStart, pEnd;
7344 
7345     if (start) {*start = 0;}
7346     if (end)   {*end   = 0;}
7347     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7348     if (pStart == pEnd) {PetscFunctionReturn(0);}
7349   }
7350   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7351   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7352   /* We should have a generic GetLabel() and a Label class */
7353   while(next) {
7354     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7355     if (flg) break;
7356     next = next->next;
7357   }
7358   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7359   depth = stratumValue;
7360   if ((depth < 0) || (depth >= next->numStrata)) {
7361     if (start) {*start = 0;}
7362     if (end)   {*end   = 0;}
7363   } else {
7364     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7365     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7366   }
7367   PetscFunctionReturn(0);
7368 }
7369 
7370 #undef __FUNCT__
7371 #define __FUNCT__ "DMPlexGetHeightStratum"
7372 /*@
7373   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7374 
7375   Not Collective
7376 
7377   Input Parameters:
7378 + dm           - The DMPlex object
7379 - stratumValue - The requested height
7380 
7381   Output Parameters:
7382 + start - The first point at this height
7383 - end   - One beyond the last point at this height
7384 
7385   Level: developer
7386 
7387 .keywords: mesh, points
7388 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7389 @*/
7390 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) {
7391   DM_Plex    *mesh = (DM_Plex *) dm->data;
7392   DMLabel        next = mesh->labels;
7393   PetscBool      flg  = PETSC_FALSE;
7394   PetscInt       depth;
7395   PetscErrorCode ierr;
7396 
7397   PetscFunctionBegin;
7398   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7399   if (stratumValue < 0) {
7400     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7401   } else {
7402     PetscInt pStart, pEnd;
7403 
7404     if (start) {*start = 0;}
7405     if (end)   {*end   = 0;}
7406     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7407     if (pStart == pEnd) {PetscFunctionReturn(0);}
7408   }
7409   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7410   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7411   /* We should have a generic GetLabel() and a Label class */
7412   while(next) {
7413     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7414     if (flg) break;
7415     next = next->next;
7416   }
7417   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7418   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7419   if ((depth < 0) || (depth >= next->numStrata)) {
7420     if (start) {*start = 0;}
7421     if (end)   {*end   = 0;}
7422   } else {
7423     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7424     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7425   }
7426   PetscFunctionReturn(0);
7427 }
7428 
7429 #undef __FUNCT__
7430 #define __FUNCT__ "DMPlexCreateSectionInitial"
7431 /* Set the number of dof on each point and separate by fields */
7432 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section) {
7433   PetscInt      *numDofTot;
7434   PetscInt       pStart = 0, pEnd = 0;
7435   PetscInt       p, d, f;
7436   PetscErrorCode ierr;
7437 
7438   PetscFunctionBegin;
7439   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7440   for(d = 0; d <= dim; ++d) {
7441     numDofTot[d] = 0;
7442     for(f = 0; f < numFields; ++f) {
7443       numDofTot[d] += numDof[f*(dim+1)+d];
7444     }
7445   }
7446   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7447   if (numFields > 0) {
7448     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7449     if (numComp) {
7450       for(f = 0; f < numFields; ++f) {
7451         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7452       }
7453     }
7454   }
7455   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7456   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7457   for(d = 0; d <= dim; ++d) {
7458     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7459     for(p = pStart; p < pEnd; ++p) {
7460       for(f = 0; f < numFields; ++f) {
7461         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7462       }
7463       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7464     }
7465   }
7466   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7467   PetscFunctionReturn(0);
7468 }
7469 
7470 #undef __FUNCT__
7471 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7472 /* Set the number of dof on each point and separate by fields
7473    If constDof is PETSC_DETERMINE, constrain every dof on the point
7474 */
7475 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section) {
7476   PetscInt       numFields;
7477   PetscInt       bc;
7478   PetscErrorCode ierr;
7479 
7480   PetscFunctionBegin;
7481   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7482   for (bc = 0; bc < numBC; ++bc) {
7483     PetscInt        field = 0;
7484     const PetscInt *idx;
7485     PetscInt        n, i;
7486 
7487     if (numFields) {field = bcField[bc];}
7488     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7489     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7490     for (i = 0; i < n; ++i) {
7491       const PetscInt p = idx[i];
7492       PetscInt       numConst = constDof;
7493 
7494       /* Constrain every dof on the point */
7495       if (numConst < 0) {
7496         if (numFields) {
7497           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7498         } else {
7499           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7500         }
7501       }
7502       if (numFields) {
7503         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7504       }
7505       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7506     }
7507     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7508   }
7509   PetscFunctionReturn(0);
7510 }
7511 
7512 #undef __FUNCT__
7513 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7514 /* Set the constrained indices on each point and separate by fields */
7515 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section) {
7516   PetscInt      *maxConstraints;
7517   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7518   PetscErrorCode ierr;
7519 
7520   PetscFunctionBegin;
7521   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7522   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7523   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7524   for(f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
7525   for(p = pStart; p < pEnd; ++p) {
7526     PetscInt cdof;
7527 
7528     if (numFields) {
7529       for(f = 0; f < numFields; ++f) {
7530         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7531         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7532       }
7533     } else {
7534       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7535       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7536     }
7537   }
7538   for (f = 0; f < numFields; ++f) {
7539     maxConstraints[numFields] += maxConstraints[f];
7540   }
7541   if (maxConstraints[numFields]) {
7542     PetscInt *indices;
7543 
7544     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7545     for (p = pStart; p < pEnd; ++p) {
7546       PetscInt cdof, d;
7547 
7548       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7549       if (cdof) {
7550         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7551         if (numFields) {
7552           PetscInt numConst = 0, foff = 0;
7553 
7554           for (f = 0; f < numFields; ++f) {
7555             PetscInt cfdof, fdof;
7556 
7557             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7558             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7559             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7560             for(d = 0; d < cfdof; ++d) {
7561               indices[numConst+d] = d;
7562             }
7563             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7564             for(d = 0; d < cfdof; ++d) {
7565               indices[numConst+d] += foff;
7566             }
7567             numConst += cfdof;
7568             foff     += fdof;
7569           }
7570           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7571         } else {
7572           for (d = 0; d < cdof; ++d) {
7573             indices[d] = d;
7574           }
7575         }
7576         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7577       }
7578     }
7579     ierr = PetscFree(indices);CHKERRQ(ierr);
7580   }
7581   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7582   PetscFunctionReturn(0);
7583 }
7584 
7585 #undef __FUNCT__
7586 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7587 /* Set the constrained field indices on each point */
7588 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section) {
7589   const PetscInt *points, *indices;
7590   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7591   PetscErrorCode  ierr;
7592 
7593   PetscFunctionBegin;
7594   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7595   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7596 
7597   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7598   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7599   if (!constraintIndices) {
7600     PetscInt *idx, i;
7601 
7602     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7603     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7604     for(i = 0; i < maxDof; ++i) {idx[i] = i;}
7605     for(p = 0; p < numPoints; ++p) {
7606       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7607     }
7608     ierr = PetscFree(idx);CHKERRQ(ierr);
7609   } else {
7610     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7611     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7612     for(p = 0; p < numPoints; ++p) {
7613       PetscInt fcdof;
7614 
7615       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7616       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);
7617       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7618     }
7619     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7620   }
7621   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7622   PetscFunctionReturn(0);
7623 }
7624 
7625 #undef __FUNCT__
7626 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7627 /* Set the constrained indices on each point and separate by fields */
7628 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section) {
7629   PetscInt      *indices;
7630   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7631   PetscErrorCode ierr;
7632 
7633   PetscFunctionBegin;
7634   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7635   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7636   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7637   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7638   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7639   for (p = pStart; p < pEnd; ++p) {
7640     PetscInt cdof, d;
7641 
7642     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7643     if (cdof) {
7644       PetscInt numConst = 0, foff = 0;
7645 
7646       for (f = 0; f < numFields; ++f) {
7647         const PetscInt *fcind;
7648         PetscInt        fdof, fcdof;
7649 
7650         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7651         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7652         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7653         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7654         for(d = 0; d < fcdof; ++d) {
7655           indices[numConst+d] = fcind[d]+foff;
7656         }
7657         foff     += fdof;
7658         numConst += fcdof;
7659       }
7660       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7661       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7662     }
7663   }
7664   ierr = PetscFree(indices);CHKERRQ(ierr);
7665   PetscFunctionReturn(0);
7666 }
7667 
7668 #undef __FUNCT__
7669 #define __FUNCT__ "DMPlexCreateSection"
7670 /*@C
7671   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7672 
7673   Not Collective
7674 
7675   Input Parameters:
7676 + dm        - The DMPlex object
7677 . dim       - The spatial dimension of the problem
7678 . numFields - The number of fields in the problem
7679 . numComp   - An array of size numFields that holds the number of components for each field
7680 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7681 . numBC     - The number of boundary conditions
7682 . bcField   - An array of size numBC giving the field number for each boundry condition
7683 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7684 
7685   Output Parameter:
7686 . section - The PetscSection object
7687 
7688   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
7689   nubmer of dof for field 0 on each edge.
7690 
7691   Level: developer
7692 
7693 .keywords: mesh, elements
7694 .seealso: DMPlexCreate(), PetscSectionCreate()
7695 @*/
7696 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section) {
7697   PetscErrorCode ierr;
7698 
7699   PetscFunctionBegin;
7700   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7701   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7702   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7703   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7704   {
7705     PetscBool view = PETSC_FALSE;
7706 
7707     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7708     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7709   }
7710   PetscFunctionReturn(0);
7711 }
7712 
7713 #undef __FUNCT__
7714 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7715 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) {
7716   PetscSection   section;
7717   PetscErrorCode ierr;
7718 
7719   PetscFunctionBegin;
7720   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7721   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
7722   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7723   PetscFunctionReturn(0);
7724 }
7725 
7726 #undef __FUNCT__
7727 #define __FUNCT__ "DMPlexGetCoordinateSection"
7728 /*@
7729   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7730 
7731   Not Collective
7732 
7733   Input Parameter:
7734 . dm - The DMPlex object
7735 
7736   Output Parameter:
7737 . section - The PetscSection object
7738 
7739   Level: intermediate
7740 
7741 .keywords: mesh, coordinates
7742 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7743 @*/
7744 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section) {
7745   DM cdm;
7746   PetscErrorCode ierr;
7747 
7748   PetscFunctionBegin;
7749   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7750   PetscValidPointer(section, 2);
7751   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7752   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7753   PetscFunctionReturn(0);
7754 }
7755 
7756 #undef __FUNCT__
7757 #define __FUNCT__ "DMPlexSetCoordinateSection"
7758 /*@
7759   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7760 
7761   Not Collective
7762 
7763   Input Parameters:
7764 + dm      - The DMPlex object
7765 - section - The PetscSection object
7766 
7767   Level: intermediate
7768 
7769 .keywords: mesh, coordinates
7770 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7771 @*/
7772 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section) {
7773   DM             cdm;
7774   PetscErrorCode ierr;
7775 
7776   PetscFunctionBegin;
7777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7778   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7779   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7780   PetscFunctionReturn(0);
7781 }
7782 
7783 #undef __FUNCT__
7784 #define __FUNCT__ "DMPlexGetConeSection"
7785 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) {
7786   DM_Plex *mesh = (DM_Plex *) dm->data;
7787 
7788   PetscFunctionBegin;
7789   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7790   if (section) *section = mesh->coneSection;
7791   PetscFunctionReturn(0);
7792 }
7793 
7794 #undef __FUNCT__
7795 #define __FUNCT__ "DMPlexGetCones"
7796 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) {
7797   DM_Plex *mesh = (DM_Plex *) dm->data;
7798 
7799   PetscFunctionBegin;
7800   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7801   if (cones) *cones = mesh->cones;
7802   PetscFunctionReturn(0);
7803 }
7804 
7805 #undef __FUNCT__
7806 #define __FUNCT__ "DMPlexGetConeOrientations"
7807 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) {
7808   DM_Plex *mesh = (DM_Plex *) dm->data;
7809 
7810   PetscFunctionBegin;
7811   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7812   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7813   PetscFunctionReturn(0);
7814 }
7815 
7816 #undef __FUNCT__
7817 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7818 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7819 {
7820   const PetscInt embedDim = 2;
7821   PetscReal      x = PetscRealPart(point[0]);
7822   PetscReal      y = PetscRealPart(point[1]);
7823   PetscReal      v0[2], J[4], invJ[4], detJ;
7824   PetscReal      xi, eta;
7825   PetscErrorCode ierr;
7826 
7827   PetscFunctionBegin;
7828   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7829   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7830   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7831 
7832   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
7833     *cell = c;
7834   } else {
7835     *cell = -1;
7836   }
7837   PetscFunctionReturn(0);
7838 }
7839 
7840 #undef __FUNCT__
7841 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7842 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7843 {
7844   PetscSection       coordSection;
7845   Vec                coordsLocal;
7846   const PetscScalar *coords;
7847   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7848   PetscReal          x         = PetscRealPart(point[0]);
7849   PetscReal          y         = PetscRealPart(point[1]);
7850   PetscInt           crossings = 0, f;
7851   PetscErrorCode     ierr;
7852 
7853   PetscFunctionBegin;
7854   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7855   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7856   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7857   for(f = 0; f < 4; ++f) {
7858     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7859     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7860     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7861     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7862     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7863     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7864     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7865     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7866     if ((cond1 || cond2)  && above) ++crossings;
7867   }
7868   if (crossings % 2) {
7869     *cell = c;
7870   } else {
7871     *cell = -1;
7872   }
7873   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7874   PetscFunctionReturn(0);
7875 }
7876 
7877 #undef __FUNCT__
7878 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7879 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7880 {
7881   const PetscInt embedDim = 3;
7882   PetscReal      v0[3], J[9], invJ[9], detJ;
7883   PetscReal      x = PetscRealPart(point[0]);
7884   PetscReal      y = PetscRealPart(point[1]);
7885   PetscReal      z = PetscRealPart(point[2]);
7886   PetscReal      xi, eta, zeta;
7887   PetscErrorCode ierr;
7888 
7889   PetscFunctionBegin;
7890   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7891   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7892   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7893   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7894 
7895   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
7896     *cell = c;
7897   } else {
7898     *cell = -1;
7899   }
7900   PetscFunctionReturn(0);
7901 }
7902 
7903 #undef __FUNCT__
7904 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7905 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7906 {
7907   PetscSection       coordSection;
7908   Vec                coordsLocal;
7909   const PetscScalar *coords;
7910   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7911                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7912   PetscBool          found     = PETSC_TRUE;
7913   PetscInt           f;
7914   PetscErrorCode     ierr;
7915 
7916   PetscFunctionBegin;
7917   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7918   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7919   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7920   for(f = 0; f < 6; ++f) {
7921     /* Check the point is under plane */
7922     /*   Get face normal */
7923     PetscReal v_i[3]    = {PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]),
7924                            PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]),
7925                            PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2])};
7926     PetscReal v_j[3]    = {PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]),
7927                            PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]),
7928                            PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2])};
7929     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]};
7930     PetscReal pp[3]     = {PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]),
7931                            PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]),
7932                            PetscRealPart(coords[faces[f*4+0]*3+2] - point[2])};
7933     PetscReal dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7934     /* Check that projected point is in face (2D location problem) */
7935     if (dot < 0.0) {
7936       found = PETSC_FALSE;
7937       break;
7938     }
7939   }
7940   if (found) {
7941     *cell = c;
7942   } else {
7943     *cell = -1;
7944   }
7945   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7946   PetscFunctionReturn(0);
7947 }
7948 
7949 #undef __FUNCT__
7950 #define __FUNCT__ "DMLocatePoints_Plex"
7951 /*
7952  Need to implement using the guess
7953 */
7954 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7955 {
7956   PetscInt       cell = -1/*, guess = -1*/;
7957   PetscInt       bs, numPoints, p;
7958   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7959   PetscInt      *cells;
7960   PetscScalar   *a;
7961   PetscErrorCode ierr;
7962 
7963   PetscFunctionBegin;
7964   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7965   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7966   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7967   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
7968   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7969   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7970   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7971   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);
7972   numPoints /= bs;
7973   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7974   for(p = 0; p < numPoints; ++p) {
7975     const PetscScalar *point = &a[p*bs];
7976 
7977     switch(dim) {
7978     case 2:
7979       for(c = cStart; c < cEnd; ++c) {
7980         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7981         switch(coneSize) {
7982         case 3:
7983           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7984           break;
7985         case 4:
7986           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7987           break;
7988         default:
7989           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7990         }
7991         if (cell >= 0) break;
7992       }
7993       break;
7994     case 3:
7995       for(c = cStart; c < cEnd; ++c) {
7996         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7997         switch(coneSize) {
7998         case 4:
7999           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8000           break;
8001         case 8:
8002           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8003           break;
8004         default:
8005           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8006         }
8007         if (cell >= 0) break;
8008       }
8009       break;
8010     default:
8011       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8012     }
8013     cells[p] = cell;
8014   }
8015   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8016   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8017   PetscFunctionReturn(0);
8018 }
8019 
8020 /******************************** FEM Support **********************************/
8021 
8022 #undef __FUNCT__
8023 #define __FUNCT__ "DMPlexVecGetClosure"
8024 /*@C
8025   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8026 
8027   Not collective
8028 
8029   Input Parameters:
8030 + dm - The DM
8031 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8032 . v - The local vector
8033 - point - The sieve point in the DM
8034 
8035   Output Parameters:
8036 + csize - The number of values in the closure, or PETSC_NULL
8037 - values - The array of values, which is a borrowed array and should not be freed
8038 
8039   Level: intermediate
8040 
8041 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8042 @*/
8043 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
8044   PetscScalar    *array, *vArray;
8045   PetscInt       *points = PETSC_NULL;
8046   PetscInt        offsets[32];
8047   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8048   PetscErrorCode  ierr;
8049 
8050   PetscFunctionBegin;
8051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8052   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8053   if (!section) {
8054     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8055   }
8056   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8057   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8058   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8059   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8060   /* Compress out points not in the section */
8061   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8062   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8063     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8064       points[q*2]   = points[p];
8065       points[q*2+1] = points[p+1];
8066       ++q;
8067     }
8068   }
8069   numPoints = q;
8070   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8071     PetscInt dof, fdof;
8072 
8073     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8074     for (f = 0; f < numFields; ++f) {
8075       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8076       offsets[f+1] += fdof;
8077     }
8078     size += dof;
8079   }
8080   for (f = 1; f < numFields; ++f) {
8081     offsets[f+1] += offsets[f];
8082   }
8083   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8084   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8085   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8086   for (p = 0; p < numPoints*2; p += 2) {
8087     PetscInt     o = points[p+1];
8088     PetscInt     dof, off, d;
8089     PetscScalar *varr;
8090 
8091     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8092     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8093     varr = &vArray[off];
8094     if (numFields) {
8095       PetscInt fdof, foff, fcomp, f, c;
8096 
8097       for (f = 0, foff = 0; f < numFields; ++f) {
8098         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8099         if (o >= 0) {
8100           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8101             array[offsets[f]] = varr[foff+d];
8102           }
8103         } else {
8104           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8105           for (d = fdof/fcomp-1; d >= 0; --d) {
8106             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8107               array[offsets[f]] = varr[foff+d*fcomp+c];
8108             }
8109           }
8110         }
8111         foff += fdof;
8112       }
8113     } else {
8114       if (o >= 0) {
8115         for (d = 0; d < dof; ++d, ++offsets[0]) {
8116           array[offsets[0]] = varr[d];
8117         }
8118       } else {
8119         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8120           array[offsets[0]] = varr[d];
8121         }
8122       }
8123     }
8124   }
8125   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8126   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8127   if (csize) *csize = size;
8128   *values = array;
8129   PetscFunctionReturn(0);
8130 }
8131 
8132 #undef __FUNCT__
8133 #define __FUNCT__ "DMPlexVecRestoreClosure"
8134 /*@C
8135   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8136 
8137   Not collective
8138 
8139   Input Parameters:
8140 + dm - The DM
8141 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8142 . v - The local vector
8143 . point - The sieve point in the DM
8144 . csize - The number of values in the closure, or PETSC_NULL
8145 - values - The array of values, which is a borrowed array and should not be freed
8146 
8147   Level: intermediate
8148 
8149 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8150 @*/
8151 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
8152   PetscInt        size = 0;
8153   PetscErrorCode  ierr;
8154 
8155   PetscFunctionBegin;
8156   /* Should work without recalculating size */
8157   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8158   PetscFunctionReturn(0);
8159 }
8160 
8161 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8162 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8163 
8164 #undef __FUNCT__
8165 #define __FUNCT__ "updatePoint_private"
8166 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8167 {
8168   PetscInt        cdof;  /* The number of constraints on this point */
8169   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8170   PetscScalar    *a;
8171   PetscInt        off, cind = 0, k;
8172   PetscErrorCode  ierr;
8173 
8174   PetscFunctionBegin;
8175   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8176   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8177   a    = &array[off];
8178   if (!cdof || setBC) {
8179     if (orientation >= 0) {
8180       for (k = 0; k < dof; ++k) {
8181         fuse(&a[k], values[k]);
8182       }
8183     } else {
8184       for (k = 0; k < dof; ++k) {
8185         fuse(&a[k], values[dof-k-1]);
8186       }
8187     }
8188   } else {
8189     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8190     if (orientation >= 0) {
8191       for (k = 0; k < dof; ++k) {
8192         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8193         fuse(&a[k], values[k]);
8194       }
8195     } else {
8196       for (k = 0; k < dof; ++k) {
8197         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8198         fuse(&a[k], values[dof-k-1]);
8199       }
8200     }
8201   }
8202   PetscFunctionReturn(0);
8203 }
8204 
8205 #undef __FUNCT__
8206 #define __FUNCT__ "updatePointFields_private"
8207 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[]) {
8208   PetscScalar   *a;
8209   PetscInt       numFields, off, foff, f;
8210   PetscErrorCode ierr;
8211 
8212   PetscFunctionBegin;
8213   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8214   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8215   a    = &array[off];
8216   for (f = 0, foff = 0; f < numFields; ++f) {
8217     PetscInt        fdof, fcomp, fcdof;
8218     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8219     PetscInt        cind = 0, k, c;
8220 
8221     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8222     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8223     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8224     if (!fcdof || setBC) {
8225       if (orientation >= 0) {
8226         for (k = 0; k < fdof; ++k) {
8227           fuse(&a[foff+k], values[foffs[f]+k]);
8228         }
8229       } else {
8230         for (k = fdof/fcomp-1; k >= 0; --k) {
8231           for (c = 0; c < fcomp; ++c) {
8232             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8233           }
8234         }
8235       }
8236     } else {
8237       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8238       if (orientation >= 0) {
8239         for (k = 0; k < fdof; ++k) {
8240           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8241           fuse(&a[foff+k], values[foffs[f]+k]);
8242         }
8243       } else {
8244         for (k = fdof/fcomp-1; k >= 0; --k) {
8245           for (c = 0; c < fcomp; ++c) {
8246             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8247             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8248           }
8249         }
8250       }
8251     }
8252     foff     += fdof;
8253     foffs[f] += fdof;
8254   }
8255   PetscFunctionReturn(0);
8256 }
8257 
8258 #undef __FUNCT__
8259 #define __FUNCT__ "DMPlexVecSetClosure"
8260 /*@C
8261   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8262 
8263   Not collective
8264 
8265   Input Parameters:
8266 + dm - The DM
8267 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8268 . v - The local vector
8269 . point - The sieve point in the DM
8270 . values - The array of values, which is a borrowed array and should not be freed
8271 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8272 
8273   Level: intermediate
8274 
8275 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8276 @*/
8277 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) {
8278   PetscScalar    *array;
8279   PetscInt       *points = PETSC_NULL;
8280   PetscInt        offsets[32];
8281   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8282   PetscErrorCode  ierr;
8283 
8284   PetscFunctionBegin;
8285   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8286   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8287   if (!section) {
8288     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8289   }
8290   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8291   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8292   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8293   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8294   /* Compress out points not in the section */
8295   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8296   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8297     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8298       points[q*2]   = points[p];
8299       points[q*2+1] = points[p+1];
8300       ++q;
8301     }
8302   }
8303   numPoints = q;
8304   for (p = 0; p < numPoints*2; p += 2) {
8305     PetscInt fdof;
8306 
8307     for (f = 0; f < numFields; ++f) {
8308       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8309       offsets[f+1] += fdof;
8310     }
8311   }
8312   for (f = 1; f < numFields; ++f) {
8313     offsets[f+1] += offsets[f];
8314   }
8315   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8316   if (numFields) {
8317     switch(mode) {
8318     case INSERT_VALUES:
8319       for (p = 0; p < numPoints*2; p += 2) {
8320         PetscInt o = points[p+1];
8321         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8322       } break;
8323     case INSERT_ALL_VALUES:
8324       for (p = 0; p < numPoints*2; p += 2) {
8325         PetscInt o = points[p+1];
8326         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8327       } break;
8328     case ADD_VALUES:
8329       for (p = 0; p < numPoints*2; p += 2) {
8330         PetscInt o = points[p+1];
8331         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8332       } break;
8333     case ADD_ALL_VALUES:
8334       for (p = 0; p < numPoints*2; p += 2) {
8335         PetscInt o = points[p+1];
8336         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8337       } break;
8338     default:
8339       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8340     }
8341   } else {
8342     switch(mode) {
8343     case INSERT_VALUES:
8344       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8345         PetscInt o = points[p+1];
8346         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8347         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8348       } break;
8349     case INSERT_ALL_VALUES:
8350       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8351         PetscInt o = points[p+1];
8352         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8353         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8354       } break;
8355     case ADD_VALUES:
8356       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8357         PetscInt o = points[p+1];
8358         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8359         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8360       } break;
8361     case ADD_ALL_VALUES:
8362       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8363         PetscInt o = points[p+1];
8364         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8365         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8366       } break;
8367     default:
8368       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8369     }
8370   }
8371   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8372   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8373   PetscFunctionReturn(0);
8374 }
8375 
8376 #undef __FUNCT__
8377 #define __FUNCT__ "DMPlexPrintMatSetValues"
8378 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8379 {
8380   PetscMPIInt    rank;
8381   PetscInt       i, j;
8382   PetscErrorCode ierr;
8383 
8384   PetscFunctionBegin;
8385   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8386   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8387   for (i = 0; i < numIndices; i++) {
8388     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8389   }
8390   for (i = 0; i < numIndices; i++) {
8391     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8392     for (j = 0; j < numIndices; j++) {
8393 #ifdef PETSC_USE_COMPLEX
8394       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8395 #else
8396       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8397 #endif
8398     }
8399     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8400   }
8401   PetscFunctionReturn(0);
8402 }
8403 
8404 #undef __FUNCT__
8405 #define __FUNCT__ "indicesPoint_private"
8406 /* . off - The global offset of this point */
8407 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
8408   PetscInt        cdof;  /* The number of constraints on this point */
8409   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8410   PetscInt        cind = 0, k;
8411   PetscErrorCode  ierr;
8412 
8413   PetscFunctionBegin;
8414   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8415   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8416   if (!cdof || setBC) {
8417     if (orientation >= 0) {
8418       for (k = 0; k < dof; ++k) {
8419         indices[k] = off+k;
8420       }
8421     } else {
8422       for (k = 0; k < dof; ++k) {
8423         indices[dof-k-1] = off+k;
8424       }
8425     }
8426   } else {
8427     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8428     if (orientation >= 0) {
8429       for (k = 0; k < dof; ++k) {
8430         if ((cind < cdof) && (k == cdofs[cind])) {
8431           /* Insert check for returning constrained indices */
8432           indices[k] = -(off+k+1);
8433           ++cind;
8434         } else {
8435           indices[k] = off+k-cind;
8436         }
8437       }
8438     } else {
8439       for (k = 0; k < dof; ++k) {
8440         if ((cind < cdof) && (k == cdofs[cind])) {
8441           /* Insert check for returning constrained indices */
8442           indices[dof-k-1] = -(off+k+1);
8443           ++cind;
8444         } else {
8445           indices[dof-k-1] = off+k-cind;
8446         }
8447       }
8448     }
8449   }
8450   PetscFunctionReturn(0);
8451 }
8452 
8453 #undef __FUNCT__
8454 #define __FUNCT__ "indicesPointFields_private"
8455 /* . off - The global offset of this point */
8456 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
8457   PetscInt       numFields, foff, f;
8458   PetscErrorCode ierr;
8459 
8460   PetscFunctionBegin;
8461   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8462   for (f = 0, foff = 0; f < numFields; ++f) {
8463     PetscInt        fdof, fcomp, cfdof;
8464     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8465     PetscInt        cind = 0, k, c;
8466 
8467     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8468     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8469     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8470     if (!cfdof || setBC) {
8471       if (orientation >= 0) {
8472         for (k = 0; k < fdof; ++k) {
8473           indices[foffs[f]+k] = off+foff+k;
8474         }
8475       } else {
8476         for (k = fdof/fcomp-1; k >= 0; --k) {
8477           for (c = 0; c < fcomp; ++c) {
8478             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8479           }
8480         }
8481       }
8482     } else {
8483       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8484       if (orientation >= 0) {
8485         for (k = 0; k < fdof; ++k) {
8486           if ((cind < cfdof) && (k == fcdofs[cind])) {
8487             indices[foffs[f]+k] = -(off+foff+k+1);
8488             ++cind;
8489           } else {
8490             indices[foffs[f]+k] = off+foff+k-cind;
8491           }
8492         }
8493       } else {
8494         for (k = fdof/fcomp-1; k >= 0; --k) {
8495           for (c = 0; c < fcomp; ++c) {
8496             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8497               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8498               ++cind;
8499             } else {
8500               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8501             }
8502           }
8503         }
8504       }
8505     }
8506     foff     += fdof - cfdof;
8507     foffs[f] += fdof;
8508   }
8509   PetscFunctionReturn(0);
8510 }
8511 
8512 #undef __FUNCT__
8513 #define __FUNCT__ "DMPlexMatSetClosure"
8514 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8515 {
8516   DM_Plex     *mesh   = (DM_Plex *) dm->data;
8517   PetscInt       *points = PETSC_NULL;
8518   PetscInt       *indices;
8519   PetscInt        offsets[32];
8520   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8521   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8522   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8523   PetscErrorCode  ierr;
8524 
8525   PetscFunctionBegin;
8526   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8527   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8528   if (useDefault) {
8529     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8530   }
8531   if (useGlobalDefault) {
8532     if (useDefault) {
8533       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8534     } else {
8535       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8536     }
8537   }
8538   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8539   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8540   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8541   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8542   /* Compress out points not in the section */
8543   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8544   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8545     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8546       points[q*2]   = points[p];
8547       points[q*2+1] = points[p+1];
8548       ++q;
8549     }
8550   }
8551   numPoints = q;
8552   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8553     PetscInt fdof;
8554 
8555     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8556     for (f = 0; f < numFields; ++f) {
8557       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8558       offsets[f+1] += fdof;
8559     }
8560     numIndices += dof;
8561   }
8562   for (f = 1; f < numFields; ++f) {
8563     offsets[f+1] += offsets[f];
8564   }
8565   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8566   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8567   if (numFields) {
8568     for (p = 0; p < numPoints*2; p += 2) {
8569       PetscInt o = points[p+1];
8570       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8571       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8572     }
8573   } else {
8574     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8575       PetscInt o = points[p+1];
8576       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8577       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8578     }
8579   }
8580   if (useGlobalDefault && !useDefault) {
8581     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8582   }
8583   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8584   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8585   if (ierr) {
8586     PetscMPIInt    rank;
8587     PetscErrorCode ierr2;
8588 
8589     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8590     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8591     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8592     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8593     CHKERRQ(ierr);
8594   }
8595   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8596   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8597   PetscFunctionReturn(0);
8598 }
8599 
8600 #undef __FUNCT__
8601 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8602 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8603 {
8604   PetscSection       coordSection;
8605   Vec                coordinates;
8606   const PetscScalar *coords;
8607   const PetscInt     dim = 2;
8608   PetscInt           d, f;
8609   PetscErrorCode     ierr;
8610 
8611   PetscFunctionBegin;
8612   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8613   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8614   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8615   if (v0) {
8616     for (d = 0; d < dim; d++) {
8617       v0[d] = PetscRealPart(coords[d]);
8618     }
8619   }
8620   if (J) {
8621     for (d = 0; d < dim; d++) {
8622       for (f = 0; f < dim; f++) {
8623         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8624       }
8625     }
8626     *detJ = J[0]*J[3] - J[1]*J[2];
8627 #if 0
8628     if (detJ < 0.0) {
8629       const PetscReal xLength = mesh->periodicity[0];
8630 
8631       if (xLength != 0.0) {
8632         PetscReal v0x = coords[0*dim+0];
8633 
8634         if (v0x == 0.0) {
8635           v0x = v0[0] = xLength;
8636         }
8637         for (f = 0; f < dim; f++) {
8638           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8639 
8640           J[0*dim+f] = 0.5*(px - v0x);
8641         }
8642       }
8643       detJ = J[0]*J[3] - J[1]*J[2];
8644     }
8645 #endif
8646     PetscLogFlops(8.0 + 3.0);
8647   }
8648   if (invJ) {
8649     const PetscReal invDet = 1.0/(*detJ);
8650 
8651     invJ[0] =  invDet*J[3];
8652     invJ[1] = -invDet*J[1];
8653     invJ[2] = -invDet*J[2];
8654     invJ[3] =  invDet*J[0];
8655     PetscLogFlops(5.0);
8656   }
8657   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8658   PetscFunctionReturn(0);
8659 }
8660 
8661 #undef __FUNCT__
8662 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8663 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8664 {
8665   PetscSection       coordSection;
8666   Vec                coordinates;
8667   const PetscScalar *coords;
8668   const PetscInt     dim = 2;
8669   PetscInt           d, f;
8670   PetscErrorCode     ierr;
8671 
8672   PetscFunctionBegin;
8673   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8674   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8675   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8676   if (v0) {
8677     for (d = 0; d < dim; d++) {
8678       v0[d] = PetscRealPart(coords[d]);
8679     }
8680   }
8681   if (J) {
8682     for (d = 0; d < dim; d++) {
8683       for (f = 0; f < dim; f++) {
8684         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8685       }
8686     }
8687     *detJ = J[0]*J[3] - J[1]*J[2];
8688     PetscLogFlops(8.0 + 3.0);
8689   }
8690   if (invJ) {
8691     const PetscReal invDet = 1.0/(*detJ);
8692 
8693     invJ[0] =  invDet*J[3];
8694     invJ[1] = -invDet*J[1];
8695     invJ[2] = -invDet*J[2];
8696     invJ[3] =  invDet*J[0];
8697     PetscLogFlops(5.0);
8698   }
8699   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8700   PetscFunctionReturn(0);
8701 }
8702 
8703 #undef __FUNCT__
8704 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8705 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8706 {
8707   PetscSection       coordSection;
8708   Vec                coordinates;
8709   const PetscScalar *coords;
8710   const PetscInt     dim = 3;
8711   PetscInt           d, f;
8712   PetscErrorCode     ierr;
8713 
8714   PetscFunctionBegin;
8715   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8716   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8717   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8718   if (v0) {
8719     for (d = 0; d < dim; d++) {
8720       v0[d] = PetscRealPart(coords[d]);
8721     }
8722   }
8723   if (J) {
8724     for (d = 0; d < dim; d++) {
8725       for (f = 0; f < dim; f++) {
8726         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8727       }
8728     }
8729     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8730     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8731              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8732              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8733     PetscLogFlops(18.0 + 12.0);
8734   }
8735   if (invJ) {
8736     const PetscReal invDet = 1.0/(*detJ);
8737 
8738     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8739     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8740     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8741     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8742     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8743     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8744     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8745     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8746     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8747     PetscLogFlops(37.0);
8748   }
8749   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8750   PetscFunctionReturn(0);
8751 }
8752 
8753 #undef __FUNCT__
8754 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8755 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8756 {
8757   PetscSection       coordSection;
8758   Vec                coordinates;
8759   const PetscScalar *coords;
8760   const PetscInt     dim = 3;
8761   PetscInt           d;
8762   PetscErrorCode     ierr;
8763 
8764   PetscFunctionBegin;
8765   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8766   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8767   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8768   if (v0) {
8769     for (d = 0; d < dim; d++) {
8770       v0[d] = PetscRealPart(coords[d]);
8771     }
8772   }
8773   if (J) {
8774     for (d = 0; d < dim; d++) {
8775       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8776       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8777       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8778     }
8779     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8780              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8781              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8782     PetscLogFlops(18.0 + 12.0);
8783   }
8784   if (invJ) {
8785     const PetscReal invDet = -1.0/(*detJ);
8786 
8787     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8788     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8789     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8790     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8791     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8792     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8793     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8794     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8795     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8796     PetscLogFlops(37.0);
8797   }
8798   *detJ *= 8.0;
8799   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8800   PetscFunctionReturn(0);
8801 }
8802 
8803 #undef __FUNCT__
8804 #define __FUNCT__ "DMPlexComputeCellGeometry"
8805 /*@C
8806   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8807 
8808   Collective on DM
8809 
8810   Input Arguments:
8811 + dm   - the DM
8812 - cell - the cell
8813 
8814   Output Arguments:
8815 + v0   - the translation part of this affine transform
8816 . J    - the Jacobian of the transform to the reference element
8817 . invJ - the inverse of the Jacobian
8818 - detJ - the Jacobian determinant
8819 
8820   Level: advanced
8821 
8822 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8823 @*/
8824 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ) {
8825   PetscInt       dim, coneSize;
8826   PetscErrorCode ierr;
8827 
8828   PetscFunctionBegin;
8829   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8830   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8831   switch(dim) {
8832   case 2:
8833     switch(coneSize) {
8834     case 3:
8835       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8836       break;
8837     case 4:
8838       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8839       break;
8840     default:
8841       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8842     }
8843     break;
8844   case 3:
8845     switch(coneSize) {
8846     case 4:
8847       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8848       break;
8849     case 8:
8850       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8851       break;
8852     default:
8853       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8854     }
8855     break;
8856   default:
8857     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8858   }
8859   PetscFunctionReturn(0);
8860 }
8861 
8862 #undef __FUNCT__
8863 #define __FUNCT__ "DMPlexGetFaceOrientation"
8864 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented) {
8865   MPI_Comm       comm      = ((PetscObject) dm)->comm;
8866   PetscBool      posOrient = PETSC_FALSE;
8867   const PetscInt debug     = 0;
8868   PetscInt       cellDim, faceSize, f;
8869   PetscErrorCode ierr;
8870 
8871   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
8872   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
8873 
8874   if (cellDim == numCorners-1) {
8875     /* Simplices */
8876     faceSize  = numCorners-1;
8877     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
8878   } else if (cellDim == 1 && numCorners == 3) {
8879     /* Quadratic line */
8880     faceSize  = 1;
8881     posOrient = PETSC_TRUE;
8882   } else if (cellDim == 2 && numCorners == 4) {
8883     /* Quads */
8884     faceSize  = 2;
8885     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
8886       posOrient = PETSC_TRUE;
8887     } else if ((indices[0] == 3) && (indices[1] == 0)) {
8888       posOrient = PETSC_TRUE;
8889     } else {
8890       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
8891         posOrient = PETSC_FALSE;
8892       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
8893     }
8894   } else if (cellDim == 2 && numCorners == 6) {
8895     /* Quadratic triangle (I hate this) */
8896     /* Edges are determined by the first 2 vertices (corners of edges) */
8897     const PetscInt faceSizeTri = 3;
8898     PetscInt  sortedIndices[3], i, iFace;
8899     PetscBool found = PETSC_FALSE;
8900     PetscInt  faceVerticesTriSorted[9] = {
8901       0, 3,  4, /* bottom */
8902       1, 4,  5, /* right */
8903       2, 3,  5, /* left */
8904     };
8905     PetscInt  faceVerticesTri[9] = {
8906       0, 3,  4, /* bottom */
8907       1, 4,  5, /* right */
8908       2, 5,  3, /* left */
8909     };
8910 
8911     faceSize = faceSizeTri;
8912     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
8913     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
8914     for (iFace = 0; iFace < 3; ++iFace) {
8915       const PetscInt ii = iFace*faceSizeTri;
8916       PetscInt       fVertex, cVertex;
8917 
8918       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
8919           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
8920         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
8921           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
8922             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
8923               faceVertices[fVertex] = origVertices[cVertex];
8924               break;
8925             }
8926           }
8927         }
8928         found = PETSC_TRUE;
8929         break;
8930       }
8931     }
8932     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
8933     if (posOriented) {*posOriented = PETSC_TRUE;}
8934     PetscFunctionReturn(0);
8935   } else if (cellDim == 2 && numCorners == 9) {
8936     /* Quadratic quad (I hate this) */
8937     /* Edges are determined by the first 2 vertices (corners of edges) */
8938     const PetscInt faceSizeQuad = 3;
8939     PetscInt  sortedIndices[3], i, iFace;
8940     PetscBool found = PETSC_FALSE;
8941     PetscInt  faceVerticesQuadSorted[12] = {
8942       0, 1,  4, /* bottom */
8943       1, 2,  5, /* right */
8944       2, 3,  6, /* top */
8945       0, 3,  7, /* left */
8946     };
8947     PetscInt  faceVerticesQuad[12] = {
8948       0, 1,  4, /* bottom */
8949       1, 2,  5, /* right */
8950       2, 3,  6, /* top */
8951       3, 0,  7, /* left */
8952     };
8953 
8954     faceSize = faceSizeQuad;
8955     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
8956     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
8957     for (iFace = 0; iFace < 4; ++iFace) {
8958       const PetscInt ii = iFace*faceSizeQuad;
8959       PetscInt       fVertex, cVertex;
8960 
8961       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
8962           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
8963         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
8964           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
8965             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
8966               faceVertices[fVertex] = origVertices[cVertex];
8967               break;
8968             }
8969           }
8970         }
8971         found = PETSC_TRUE;
8972         break;
8973       }
8974     }
8975     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
8976     if (posOriented) {*posOriented = PETSC_TRUE;}
8977     PetscFunctionReturn(0);
8978   } else if (cellDim == 3 && numCorners == 8) {
8979     /* Hexes
8980        A hex is two oriented quads with the normal of the first
8981        pointing up at the second.
8982 
8983           7---6
8984          /|  /|
8985         4---5 |
8986         | 3-|-2
8987         |/  |/
8988         0---1
8989 
8990         Faces are determined by the first 4 vertices (corners of faces) */
8991     const PetscInt faceSizeHex = 4;
8992     PetscInt  sortedIndices[4], i, iFace;
8993     PetscBool found = PETSC_FALSE;
8994     PetscInt faceVerticesHexSorted[24] = {
8995       0, 1, 2, 3,  /* bottom */
8996       4, 5, 6, 7,  /* top */
8997       0, 1, 4, 5,  /* front */
8998       1, 2, 5, 6,  /* right */
8999       2, 3, 6, 7,  /* back */
9000       0, 3, 4, 7,  /* left */
9001     };
9002     PetscInt faceVerticesHex[24] = {
9003       3, 2, 1, 0,  /* bottom */
9004       4, 5, 6, 7,  /* top */
9005       0, 1, 5, 4,  /* front */
9006       1, 2, 6, 5,  /* right */
9007       2, 3, 7, 6,  /* back */
9008       3, 0, 4, 7,  /* left */
9009     };
9010 
9011     faceSize = faceSizeHex;
9012     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9013     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9014     for (iFace = 0; iFace < 6; ++iFace) {
9015       const PetscInt ii = iFace*faceSizeHex;
9016       PetscInt       fVertex, cVertex;
9017 
9018       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9019           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9020           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9021           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9022         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9023           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9024             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9025               faceVertices[fVertex] = origVertices[cVertex];
9026               break;
9027             }
9028           }
9029         }
9030         found = PETSC_TRUE;
9031         break;
9032       }
9033     }
9034     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9035     if (posOriented) {*posOriented = PETSC_TRUE;}
9036     PetscFunctionReturn(0);
9037   } else if (cellDim == 3 && numCorners == 10) {
9038     /* Quadratic tet */
9039     /* Faces are determined by the first 3 vertices (corners of faces) */
9040     const PetscInt faceSizeTet = 6;
9041     PetscInt  sortedIndices[6], i, iFace;
9042     PetscBool found = PETSC_FALSE;
9043     PetscInt faceVerticesTetSorted[24] = {
9044       0, 1, 2,  6, 7, 8, /* bottom */
9045       0, 3, 4,  6, 7, 9,  /* front */
9046       1, 4, 5,  7, 8, 9,  /* right */
9047       2, 3, 5,  6, 8, 9,  /* left */
9048     };
9049     PetscInt faceVerticesTet[24] = {
9050       0, 1, 2,  6, 7, 8, /* bottom */
9051       0, 4, 3,  6, 7, 9,  /* front */
9052       1, 5, 4,  7, 8, 9,  /* right */
9053       2, 3, 5,  8, 6, 9,  /* left */
9054     };
9055 
9056     faceSize = faceSizeTet;
9057     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9058     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9059     for (iFace=0; iFace < 4; ++iFace) {
9060       const PetscInt ii = iFace*faceSizeTet;
9061       PetscInt       fVertex, cVertex;
9062 
9063       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9064           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9065           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9066           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9067         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9068           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9069             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9070               faceVertices[fVertex] = origVertices[cVertex];
9071               break;
9072             }
9073           }
9074         }
9075         found = PETSC_TRUE;
9076         break;
9077       }
9078     }
9079     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9080     if (posOriented) {*posOriented = PETSC_TRUE;}
9081     PetscFunctionReturn(0);
9082   } else if (cellDim == 3 && numCorners == 27) {
9083     /* Quadratic hexes (I hate this)
9084        A hex is two oriented quads with the normal of the first
9085        pointing up at the second.
9086 
9087          7---6
9088         /|  /|
9089        4---5 |
9090        | 3-|-2
9091        |/  |/
9092        0---1
9093 
9094        Faces are determined by the first 4 vertices (corners of faces) */
9095     const PetscInt faceSizeQuadHex = 9;
9096     PetscInt  sortedIndices[9], i, iFace;
9097     PetscBool found = PETSC_FALSE;
9098     PetscInt faceVerticesQuadHexSorted[54] = {
9099       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9100       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9101       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9102       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9103       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9104       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9105     };
9106     PetscInt faceVerticesQuadHex[54] = {
9107       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9108       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9109       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9110       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9111       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9112       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9113     };
9114 
9115     faceSize = faceSizeQuadHex;
9116     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9117     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9118     for (iFace = 0; iFace < 6; ++iFace) {
9119       const PetscInt ii = iFace*faceSizeQuadHex;
9120       PetscInt       fVertex, cVertex;
9121 
9122       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9123           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9124           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9125           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9126         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9127           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9128             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9129               faceVertices[fVertex] = origVertices[cVertex];
9130               break;
9131             }
9132           }
9133         }
9134         found = PETSC_TRUE;
9135         break;
9136       }
9137     }
9138     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9139     if (posOriented) {*posOriented = PETSC_TRUE;}
9140     PetscFunctionReturn(0);
9141   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9142   if (!posOrient) {
9143     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9144     for (f = 0; f < faceSize; ++f) {
9145       faceVertices[f] = origVertices[faceSize-1 - f];
9146     }
9147   } else {
9148     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9149     for (f = 0; f < faceSize; ++f) {
9150       faceVertices[f] = origVertices[f];
9151     }
9152   }
9153   if (posOriented) {*posOriented = posOrient;}
9154   PetscFunctionReturn(0);
9155 }
9156 
9157 #undef __FUNCT__
9158 #define __FUNCT__ "DMPlexGetOrientedFace"
9159 /*
9160     Given a cell and a face, as a set of vertices,
9161       return the oriented face, as a set of vertices, in faceVertices
9162     The orientation is such that the face normal points out of the cell
9163 */
9164 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9165 {
9166   const PetscInt *cone = PETSC_NULL;
9167   PetscInt        coneSize, v, f, v2;
9168   PetscInt        oppositeVertex = -1;
9169   PetscErrorCode  ierr;
9170 
9171   PetscFunctionBegin;
9172   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9173   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9174   for (v = 0, v2 = 0; v < coneSize; ++v) {
9175     PetscBool found  = PETSC_FALSE;
9176 
9177     for (f = 0; f < faceSize; ++f) {
9178       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9179     }
9180     if (found) {
9181       indices[v2]      = v;
9182       origVertices[v2] = cone[v];
9183       ++v2;
9184     } else {
9185       oppositeVertex = v;
9186     }
9187   }
9188   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9189   PetscFunctionReturn(0);
9190 }
9191 
9192 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9193 {
9194   switch(i) {
9195   case 0:
9196     switch(j) {
9197     case 0: return 0;
9198     case 1:
9199       switch(k) {
9200       case 0: return 0;
9201       case 1: return 0;
9202       case 2: return 1;
9203       }
9204     case 2:
9205       switch(k) {
9206       case 0: return 0;
9207       case 1: return -1;
9208       case 2: return 0;
9209       }
9210     }
9211   case 1:
9212     switch(j) {
9213     case 0:
9214       switch(k) {
9215       case 0: return 0;
9216       case 1: return 0;
9217       case 2: return -1;
9218       }
9219     case 1: return 0;
9220     case 2:
9221       switch(k) {
9222       case 0: return 1;
9223       case 1: return 0;
9224       case 2: return 0;
9225       }
9226     }
9227   case 2:
9228     switch(j) {
9229     case 0:
9230       switch(k) {
9231       case 0: return 0;
9232       case 1: return 1;
9233       case 2: return 0;
9234       }
9235     case 1:
9236       switch(k) {
9237       case 0: return -1;
9238       case 1: return 0;
9239       case 2: return 0;
9240       }
9241     case 2: return 0;
9242     }
9243   }
9244   return 0;
9245 }
9246 
9247 #undef __FUNCT__
9248 #define __FUNCT__ "DMPlexCreateRigidBody"
9249 /*@C
9250   DMPlexCreateRigidBody - create rigid body modes from coordinates
9251 
9252   Collective on DM
9253 
9254   Input Arguments:
9255 + dm - the DM
9256 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9257 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9258 
9259   Output Argument:
9260 . sp - the null space
9261 
9262   Note: This is necessary to take account of Dirichlet conditions on the displacements
9263 
9264   Level: advanced
9265 
9266 .seealso: MatNullSpaceCreate()
9267 @*/
9268 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9269 {
9270   MPI_Comm       comm = ((PetscObject) dm)->comm;
9271   Vec            coordinates, localMode, mode[6];
9272   PetscSection   coordSection;
9273   PetscScalar   *coords;
9274   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9275   PetscErrorCode ierr;
9276 
9277   PetscFunctionBegin;
9278   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9279   if (dim == 1) {
9280     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9281     PetscFunctionReturn(0);
9282   }
9283   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9284   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9285   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9286   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9287   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9288   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9289   m    = (dim*(dim+1))/2;
9290   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9291   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9292   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9293   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9294   /* Assume P1 */
9295   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9296   for (d = 0; d < dim; ++d) {
9297     PetscScalar values[3] = {0.0, 0.0, 0.0};
9298 
9299     values[d] = 1.0;
9300     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9301     for (v = vStart; v < vEnd; ++v) {
9302       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9303     }
9304     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9305     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9306   }
9307   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9308   for (d = dim; d < dim*(dim+1)/2; ++d) {
9309     PetscInt i, j, k = dim > 2 ? d - dim : d;
9310 
9311     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9312     for (v = vStart; v < vEnd; ++v) {
9313       PetscScalar values[3] = {0.0, 0.0, 0.0};
9314       PetscInt    off;
9315 
9316       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9317       for (i = 0; i < dim; ++i) {
9318         for (j = 0; j < dim; ++j) {
9319           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9320         }
9321       }
9322       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9323     }
9324     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9325     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9326   }
9327   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9328   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9329   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9330   /* Orthonormalize system */
9331   for (i = dim; i < m; ++i) {
9332     PetscScalar dots[6];
9333 
9334     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9335     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9336     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9337     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9338   }
9339   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9340   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9341   PetscFunctionReturn(0);
9342 }
9343 
9344 #undef __FUNCT__
9345 #define __FUNCT__ "DMPlexGetHybridBounds"
9346 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9347 {
9348   DM_Plex       *mesh = (DM_Plex *) dm->data;
9349   PetscInt       dim;
9350   PetscErrorCode ierr;
9351 
9352   PetscFunctionBegin;
9353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9354   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9355   if (cMax) *cMax = mesh->hybridPointMax[dim];
9356   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9357   if (eMax) *eMax = mesh->hybridPointMax[1];
9358   if (vMax) *vMax = mesh->hybridPointMax[0];
9359   PetscFunctionReturn(0);
9360 }
9361 
9362 #undef __FUNCT__
9363 #define __FUNCT__ "DMPlexSetHybridBounds"
9364 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9365 {
9366   DM_Plex       *mesh = (DM_Plex *) dm->data;
9367   PetscInt       dim;
9368   PetscErrorCode ierr;
9369 
9370   PetscFunctionBegin;
9371   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9372   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9373   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9374   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9375   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9376   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9377   PetscFunctionReturn(0);
9378 }
9379 
9380 #undef __FUNCT__
9381 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9382 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9383 {
9384   DM_Plex *mesh = (DM_Plex *) dm->data;
9385 
9386   PetscFunctionBegin;
9387   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9388   PetscValidPointer(cellHeight, 2);
9389   *cellHeight = mesh->vtkCellHeight;
9390   PetscFunctionReturn(0);
9391 }
9392 
9393 #undef __FUNCT__
9394 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9395 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9396 {
9397   DM_Plex *mesh = (DM_Plex *) dm->data;
9398 
9399   PetscFunctionBegin;
9400   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9401   mesh->vtkCellHeight = cellHeight;
9402   PetscFunctionReturn(0);
9403 }
9404 
9405 #undef __FUNCT__
9406 #define __FUNCT__ "DMPlexInsertFace_Private"
9407 /*
9408   DMPlexInsertFace_Private - Puts a face into the mesh
9409 
9410   Not collective
9411 
9412   Input Parameters:
9413   + dm              - The DMPlex
9414   . numFaceVertex   - The number of vertices in the face
9415   . faceVertices    - The vertices in the face for dm
9416   . subfaceVertices - The vertices in the face for subdm
9417   . numCorners      - The number of vertices in the cell
9418   . cell            - A cell in dm containing the face
9419   . subcell         - A cell in subdm containing the face
9420   . firstFace       - First face in the mesh
9421   - newFacePoint    - Next face in the mesh
9422 
9423   Output Parameters:
9424   . newFacePoint - Contains next face point number on input, updated on output
9425 
9426   Level: developer
9427 */
9428 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)
9429 {
9430   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9431   DM_Plex     *submesh = (DM_Plex *) subdm->data;
9432   const PetscInt *faces;
9433   PetscInt        numFaces, coneSize;
9434   PetscErrorCode  ierr;
9435 
9436   PetscFunctionBegin;
9437   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9438   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9439 #if 0
9440   /* Cannot use this because support() has not been constructed yet */
9441   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9442 #else
9443   {
9444     PetscInt f;
9445 
9446     numFaces = 0;
9447     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
9448     for(f = firstFace; f < *newFacePoint; ++f) {
9449       PetscInt dof, off, d;
9450 
9451       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9452       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9453       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9454       for(d = 0; d < dof; ++d) {
9455         const PetscInt p = submesh->cones[off+d];
9456         PetscInt       v;
9457 
9458         for(v = 0; v < numFaceVertices; ++v) {
9459           if (subfaceVertices[v] == p) break;
9460         }
9461         if (v == numFaceVertices) break;
9462       }
9463       if (d == dof) {
9464         numFaces = 1;
9465         ((PetscInt *) faces)[0] = f;
9466       }
9467     }
9468   }
9469 #endif
9470   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
9471   else if (numFaces == 1) {
9472     /* Add the other cell neighbor for this face */
9473     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
9474   } else {
9475     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
9476     PetscBool posOriented;
9477 
9478     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9479     origVertices = &orientedVertices[numFaceVertices];
9480     indices      = &orientedVertices[numFaceVertices*2];
9481     orientedSubVertices = &orientedVertices[numFaceVertices*3];
9482     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
9483     /* TODO: I know that routine should return a permutation, not the indices */
9484     for(v = 0; v < numFaceVertices; ++v) {
9485       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
9486       for(ov = 0; ov < numFaceVertices; ++ov) {
9487         if (orientedVertices[ov] == vertex) {
9488           orientedSubVertices[ov] = subvertex;
9489           break;
9490         }
9491       }
9492       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
9493     }
9494     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
9495     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
9496     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9497     ++(*newFacePoint);
9498   }
9499   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9500   PetscFunctionReturn(0);
9501 }
9502 
9503 #undef __FUNCT__
9504 #define __FUNCT__ "DMPlexCreateSubmesh"
9505 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
9506 {
9507   MPI_Comm        comm = ((PetscObject) dm)->comm;
9508   DM_Plex     *submesh;
9509   PetscBool       boundaryFaces = PETSC_FALSE;
9510   PetscSection    coordSection, subCoordSection;
9511   Vec             coordinates, subCoordinates;
9512   PetscScalar    *coords, *subCoords;
9513   IS              labelIS;
9514   const PetscInt *subVertices;
9515   PetscInt       *subVerticesActive, *tmpPoints;
9516   PetscInt       *subCells = PETSC_NULL;
9517   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
9518   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
9519   PetscInt        dim; /* Right now, do not specify dimension */
9520   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
9521   PetscErrorCode  ierr;
9522 
9523   PetscFunctionBegin;
9524   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9525   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9526   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9527   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
9528   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9529   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9530   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9531   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9532   subface = &face[maxConeSize];
9533   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
9534   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
9535   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
9536   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
9537   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
9538   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
9539   maxSubCells = numSubVertices;
9540   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
9541   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
9542   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
9543   for(v = 0; v < numSubVertices; ++v) {
9544     const PetscInt vertex = subVertices[v];
9545     PetscInt *star = PETSC_NULL;
9546     PetscInt  starSize, numCells = 0;
9547 
9548     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9549     for(p = 0; p < starSize*2; p += 2) {
9550       const PetscInt point = star[p];
9551       if ((point >= cStart) && (point < cEnd)) {
9552         star[numCells++] = point;
9553       }
9554     }
9555     numOldSubCells = numSubCells;
9556     for(c = 0; c < numCells; ++c) {
9557       const PetscInt cell    = star[c];
9558       PetscInt      *closure = PETSC_NULL;
9559       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9560       PetscInt       cellLoc;
9561 
9562       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9563       if (cellLoc >= 0) continue;
9564       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9565       for(p = 0; p < closureSize*2; p += 2) {
9566         const PetscInt point = closure[p];
9567         if ((point >= vStart) && (point < vEnd)) {
9568           closure[numCorners++] = point;
9569         }
9570       }
9571       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9572       for(corner = 0; corner < numCorners; ++corner) {
9573         const PetscInt cellVertex = closure[corner];
9574         PetscInt       subVertex;
9575 
9576         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9577         if (subVertex >= 0) { /* contains submesh vertex */
9578           for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9579           if (i == faceSize) {
9580             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9581             face[faceSize]    = cellVertex;
9582             subface[faceSize] = subVertex;
9583             ++faceSize;
9584           }
9585         }
9586       }
9587       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9588       if (faceSize >= nFV) {
9589         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9590         if (numSubCells >= maxSubCells) {
9591           PetscInt *tmpCells;
9592           maxSubCells *= 2;
9593           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9594           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9595           ierr = PetscFree(subCells);CHKERRQ(ierr);
9596           subCells = tmpCells;
9597         }
9598         /* TOOD: Maybe overestimate then squeeze out empty faces */
9599         if (faceSize > nFV) {
9600           /* TODO: This is tricky. Maybe just add all faces */
9601           numSubFaces++;
9602         } else {
9603           numSubFaces++;
9604         }
9605         for(f = 0; f < faceSize; ++f) {
9606           subVerticesActive[subface[f]] = 1;
9607         }
9608         subCells[numSubCells++] = cell;
9609       }
9610     }
9611     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9612     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9613   }
9614   /* Pick out active subvertices */
9615   for(v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9616     if (subVerticesActive[v]) {
9617       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9618     }
9619   }
9620   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9621   /* Set cone sizes */
9622   firstSubVertex = numSubCells;
9623   firstSubFace   = numSubCells+numSubVerticesActive;
9624   newFacePoint   = firstSubFace;
9625   for(c = 0; c < numSubCells; ++c) {
9626     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
9627   }
9628   for(f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9629     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
9630   }
9631   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
9632   /* Create face cones */
9633   for(c = 0; c < numSubCells; ++c) {
9634     const PetscInt cell    = subCells[c];
9635     PetscInt      *closure = PETSC_NULL;
9636     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9637 
9638     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9639     for(p = 0; p < closureSize*2; p += 2) {
9640       const PetscInt point = closure[p];
9641       if ((point >= vStart) && (point < vEnd)) {
9642         closure[numCorners++] = point;
9643       }
9644     }
9645     for(corner = 0; corner < numCorners; ++corner) {
9646       const PetscInt cellVertex = closure[corner];
9647       PetscInt       subVertex;
9648 
9649       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9650       if (subVertex >= 0) { /* contains submesh vertex */
9651         for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9652         if (i == faceSize) {
9653           face[faceSize]    = cellVertex;
9654           subface[faceSize] = numSubCells+subVertex;
9655           ++faceSize;
9656         }
9657       }
9658     }
9659     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9660     if (faceSize >= nFV) {
9661       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9662       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
9663       /*   We have to take all the faces, and discard those in the interior */
9664       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
9665 #if 0
9666       /* This object just calls insert on each face that comes from subsets() */
9667       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
9668       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9669       PointArray                          faceVec(face->begin(), face->end());
9670 
9671       subsets(faceVec, nFV, inserter);
9672 #endif
9673       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
9674     }
9675   }
9676   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
9677   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
9678   /* Build coordinates */
9679   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9680   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9681   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
9682   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
9683   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
9684     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
9685   }
9686   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
9687   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
9688   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
9689   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
9690   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
9691   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
9692   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9693   for(v = 0; v < numSubVerticesActive; ++v) {
9694     const PetscInt vertex    = subVerticesActive[v];
9695     const PetscInt subVertex = firstSubVertex+v;
9696     PetscInt dof, off, sdof, soff;
9697 
9698     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
9699     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
9700     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
9701     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
9702     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
9703     for(d = 0; d < dof; ++d) {
9704       subCoords[soff+d] = coords[off+d];
9705     }
9706   }
9707   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
9708   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9709   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
9710   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
9711 
9712   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
9713   /* Create map from submesh points to original mesh points */
9714   submesh = (DM_Plex *) (*subdm)->data;
9715   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
9716   for(c = 0; c < numSubCells; ++c) {
9717     tmpPoints[c] = subCells[c];
9718   }
9719   for(v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
9720     tmpPoints[v] = subVerticesActive[v-numSubCells];
9721   }
9722   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
9723 
9724   ierr = PetscFree(subCells);CHKERRQ(ierr);
9725   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
9726   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
9727   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
9728   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9729   PetscFunctionReturn(0);
9730 }
9731 
9732 #undef __FUNCT__
9733 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9734 /* We can easily have a form that takes an IS instead */
9735 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9736 {
9737   PetscSection   section, globalSection;
9738   PetscInt      *numbers, p;
9739   PetscErrorCode ierr;
9740 
9741   PetscFunctionBegin;
9742   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
9743   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9744   for(p = pStart; p < pEnd; ++p) {
9745     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9746   }
9747   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9748   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9749   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9750   for(p = pStart; p < pEnd; ++p) {
9751     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9752   }
9753   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9754   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9755   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9756   PetscFunctionReturn(0);
9757 }
9758 
9759 #undef __FUNCT__
9760 #define __FUNCT__ "DMPlexGetCellNumbering"
9761 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9762 {
9763   DM_Plex    *mesh = (DM_Plex *) dm->data;
9764   PetscInt       cellHeight, cStart, cEnd, cMax;
9765   PetscErrorCode ierr;
9766 
9767   PetscFunctionBegin;
9768   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9769   if (!mesh->globalCellNumbers) {
9770     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9771     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9772     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
9773     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9774     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9775   }
9776   *globalCellNumbers = mesh->globalCellNumbers;
9777   PetscFunctionReturn(0);
9778 }
9779 
9780 #undef __FUNCT__
9781 #define __FUNCT__ "DMPlexGetVertexNumbering"
9782 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9783 {
9784   DM_Plex    *mesh = (DM_Plex *) dm->data;
9785   PetscInt       vStart, vEnd, vMax;
9786   PetscErrorCode ierr;
9787 
9788   PetscFunctionBegin;
9789   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9790   if (!mesh->globalVertexNumbers) {
9791     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9792     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9793     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9794     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9795   }
9796   *globalVertexNumbers = mesh->globalVertexNumbers;
9797   PetscFunctionReturn(0);
9798 }
9799 
9800 #undef __FUNCT__
9801 #define __FUNCT__ "DMPlexGetSubpointMap"
9802 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
9803 {
9804   DM_Plex *mesh = (DM_Plex *) dm->data;
9805 
9806   PetscFunctionBegin;
9807   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9808   PetscValidPointer(subpointMap, 2);
9809   *subpointMap = mesh->subpointMap;
9810   PetscFunctionReturn(0);
9811 }
9812 
9813 #undef __FUNCT__
9814 #define __FUNCT__ "DMPlexSetSubpointMap"
9815 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
9816 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
9817 {
9818   DM_Plex *mesh = (DM_Plex *) dm->data;
9819 
9820   PetscFunctionBegin;
9821   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9822   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
9823   mesh->subpointMap = subpointMap;
9824   PetscFunctionReturn(0);
9825 }
9826 
9827 #undef __FUNCT__
9828 #define __FUNCT__ "DMPlexGetScale"
9829 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9830 {
9831   DM_Plex *mesh = (DM_Plex *) dm->data;
9832 
9833   PetscFunctionBegin;
9834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9835   PetscValidPointer(scale, 3);
9836   *scale = mesh->scale[unit];
9837   PetscFunctionReturn(0);
9838 }
9839 
9840 #undef __FUNCT__
9841 #define __FUNCT__ "DMPlexSetScale"
9842 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9843 {
9844   DM_Plex *mesh = (DM_Plex *) dm->data;
9845 
9846   PetscFunctionBegin;
9847   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9848   mesh->scale[unit] = scale;
9849   PetscFunctionReturn(0);
9850 }
9851 
9852 
9853 /*******************************************************************************
9854 This should be in a separate Discretization object, but I am not sure how to lay
9855 it out yet, so I am stuffing things here while I experiment.
9856 *******************************************************************************/
9857 #undef __FUNCT__
9858 #define __FUNCT__ "DMPlexSetFEMIntegration"
9859 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9860                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9861                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9862                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9863                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9864                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9865                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9866                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9867                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9868                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9869                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9870                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9871                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9872                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9873                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9874                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9875                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9876 {
9877   DM_Plex *mesh = (DM_Plex *) dm->data;
9878 
9879   PetscFunctionBegin;
9880   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9881   mesh->integrateResidualFEM       = integrateResidualFEM;
9882   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9883   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9884   PetscFunctionReturn(0);
9885 }
9886 
9887 #undef __FUNCT__
9888 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9889 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9890 {
9891   Vec            coordinates;
9892   PetscSection   section, cSection;
9893   PetscInt       dim, vStart, vEnd, v, c, d;
9894   PetscScalar   *values, *cArray;
9895   PetscReal     *coords;
9896   PetscErrorCode ierr;
9897 
9898   PetscFunctionBegin;
9899   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9900   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9901   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9902   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9903   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9904   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9905   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9906   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9907   for (v = vStart; v < vEnd; ++v) {
9908     PetscInt dof, off;
9909 
9910     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9911     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9912     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9913     for(d = 0; d < dof; ++d) {
9914       coords[d] = PetscRealPart(cArray[off+d]);
9915     }
9916     for(c = 0; c < numComp; ++c) {
9917       values[c] = (*funcs[c])(coords);
9918     }
9919     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9920   }
9921   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9922   /* Temporary, must be replaced by a projection on the finite element basis */
9923   {
9924     PetscInt eStart = 0, eEnd = 0, e, depth;
9925 
9926     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9927     --depth;
9928     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9929     for (e = eStart; e < eEnd; ++e) {
9930       const PetscInt *cone = PETSC_NULL;
9931       PetscInt        coneSize, d;
9932       PetscScalar    *coordsA, *coordsB;
9933 
9934       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9935       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9936       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9937       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9938       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9939       for (d = 0; d < dim; ++d) {
9940         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9941       }
9942       for (c = 0; c < numComp; ++c) {
9943         values[c] = (*funcs[c])(coords);
9944       }
9945       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9946     }
9947   }
9948 
9949   ierr = PetscFree(coords);CHKERRQ(ierr);
9950   ierr = PetscFree(values);CHKERRQ(ierr);
9951 #if 0
9952   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9953   PetscReal      detJ;
9954 
9955   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9956   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9957   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV((int) pow(this->_mesh->getSieve()->getMaxConeSize(), dim+1)+1, true);
9958 
9959   for (PetscInt c = cStart; c < cEnd; ++c) {
9960     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9961     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9962     const int                          oSize   = pV.getSize();
9963     int                                v       = 0;
9964 
9965     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
9966     for (PetscInt cl = 0; cl < oSize; ++cl) {
9967       const PetscInt fDim;
9968 
9969       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9970       if (pointDim) {
9971         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9972           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9973         }
9974       }
9975     }
9976     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
9977     pV.clear();
9978   }
9979   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9980   ierr = PetscFree(values);CHKERRQ(ierr);
9981 #endif
9982   PetscFunctionReturn(0);
9983 }
9984 
9985 #undef __FUNCT__
9986 #define __FUNCT__ "DMPlexProjectFunction"
9987 /*@C
9988   DMPlexProjectFunction - This projects the given function into the function space provided.
9989 
9990   Input Parameters:
9991 + dm      - The DM
9992 . numComp - The number of components (functions)
9993 . funcs   - The coordinate functions to evaluate
9994 - mode    - The insertion mode for values
9995 
9996   Output Parameter:
9997 . X - vector
9998 
9999   Level: developer
10000 
10001   Note:
10002   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10003   We will eventually fix it.
10004 
10005 ,seealso: DMPlexComputeL2Diff()
10006 */
10007 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10008 {
10009   Vec            localX;
10010   PetscErrorCode ierr;
10011 
10012   PetscFunctionBegin;
10013   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10014   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10015   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10016   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10017   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10018   PetscFunctionReturn(0);
10019 }
10020 
10021 #undef __FUNCT__
10022 #define __FUNCT__ "DMPlexComputeL2Diff"
10023 /*@C
10024   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10025 
10026   Input Parameters:
10027 + dm    - The DM
10028 . quad  - The PetscQuadrature object for each field
10029 . funcs - The functions to evaluate for each field component
10030 - X     - The coefficient vector u_h
10031 
10032   Output Parameter:
10033 . diff - The diff ||u - u_h||_2
10034 
10035   Level: developer
10036 
10037 .seealso: DMPlexProjectFunction()
10038 */
10039 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff) {
10040   const PetscInt   debug = 0;
10041   PetscSection     section;
10042   Vec              localX;
10043   PetscReal       *coords, *v0, *J, *invJ, detJ;
10044   PetscReal        localDiff = 0.0;
10045   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10046   PetscErrorCode   ierr;
10047 
10048   PetscFunctionBegin;
10049   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10050   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10051   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10052   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10053   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10054   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10055   for (field = 0; field < numFields; ++field) {
10056     numComponents += quad[field].numComponents;
10057   }
10058   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10059   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10060   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10061   for (c = cStart; c < cEnd; ++c) {
10062     const PetscScalar *x;
10063     PetscReal          elemDiff = 0.0;
10064 
10065     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10066     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10067     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10068 
10069     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10070       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10071       const PetscReal *quadPoints    = quad[field].quadPoints;
10072       const PetscReal *quadWeights   = quad[field].quadWeights;
10073       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10074       const PetscInt   numBasisComps = quad[field].numComponents;
10075       const PetscReal *basis         = quad[field].basis;
10076       PetscInt         q, d, e, fc, f;
10077 
10078       if (debug) {
10079         char title[1024];
10080         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10081         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10082       }
10083       for (q = 0; q < numQuadPoints; ++q) {
10084         for (d = 0; d < dim; d++) {
10085           coords[d] = v0[d];
10086           for (e = 0; e < dim; e++) {
10087             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10088           }
10089         }
10090         for (fc = 0; fc < numBasisComps; ++fc) {
10091           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10092           PetscReal       interpolant = 0.0;
10093           for (f = 0; f < numBasisFuncs; ++f) {
10094             const PetscInt fidx = f*numBasisComps+fc;
10095             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10096           }
10097           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10098           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10099         }
10100       }
10101       comp        += numBasisComps;
10102       fieldOffset += numBasisFuncs*numBasisComps;
10103     }
10104     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10105     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10106     localDiff += elemDiff;
10107   }
10108   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10109   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10110   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10111   *diff = PetscSqrtReal(*diff);
10112   PetscFunctionReturn(0);
10113 }
10114 
10115 #undef __FUNCT__
10116 #define __FUNCT__ "DMPlexComputeResidualFEM"
10117 /*@
10118   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10119 
10120   Input Parameters:
10121 + dm - The mesh
10122 . X  - Local input vector
10123 - user - The user context
10124 
10125   Output Parameter:
10126 . F  - Local output vector
10127 
10128   Note:
10129   The second member of the user context must be an FEMContext.
10130 
10131   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10132   like a GPU, or vectorize on a multicore machine.
10133 
10134 .seealso: DMPlexComputeJacobianActionFEM()
10135 */
10136 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10137 {
10138   DM_Plex      *mesh = (DM_Plex *) dm->data;
10139   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10140   PetscQuadrature *quad = fem->quad;
10141   PetscSection     section;
10142   PetscReal       *v0, *J, *invJ, *detJ;
10143   PetscScalar     *elemVec, *u;
10144   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10145   PetscInt         cellDof = 0, numComponents = 0;
10146   PetscErrorCode   ierr;
10147 
10148   PetscFunctionBegin;
10149   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10150   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10151   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10152   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10153   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10154   numCells = cEnd - cStart;
10155   for (field = 0; field < numFields; ++field) {
10156     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10157     numComponents += quad[field].numComponents;
10158   }
10159   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10160   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10161   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);
10162   for (c = cStart; c < cEnd; ++c) {
10163     const PetscScalar *x;
10164     PetscInt           i;
10165 
10166     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10167     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10168     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10169 
10170     for (i = 0; i < cellDof; ++i) {
10171       u[c*cellDof+i] = x[i];
10172     }
10173     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10174   }
10175   for (field = 0; field < numFields; ++field) {
10176     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10177     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10178     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10179     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10180     /* Conforming batches */
10181     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10182     PetscInt numBlocks  = 1;
10183     PetscInt batchSize  = numBlocks * blockSize;
10184     PetscInt numBatches = numBatchesTmp;
10185     PetscInt numChunks  = numCells / (numBatches*batchSize);
10186     /* Remainder */
10187     PetscInt numRemainder = numCells % (numBatches * batchSize);
10188     PetscInt offset       = numCells - numRemainder;
10189 
10190     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10191     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10192                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10193   }
10194   for (c = cStart; c < cEnd; ++c) {
10195     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10196     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10197   }
10198   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10199   if (mesh->printFEM) {
10200     PetscMPIInt rank, numProcs;
10201     PetscInt    p;
10202 
10203     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10204     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10205     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10206     for (p = 0; p < numProcs; ++p) {
10207       if (p == rank) {
10208         Vec f;
10209 
10210         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10211         ierr = VecCopy(F, f);CHKERRQ(ierr);
10212         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10213         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10214         ierr = VecDestroy(&f);CHKERRQ(ierr);
10215         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10216       }
10217       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10218     }
10219   }
10220   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10221   PetscFunctionReturn(0);
10222 }
10223 
10224 #undef __FUNCT__
10225 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10226 /*@C
10227   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10228 
10229   Input Parameters:
10230 + dm - The mesh
10231 . J  - The Jacobian shell matrix
10232 . X  - Local input vector
10233 - user - The user context
10234 
10235   Output Parameter:
10236 . F  - Local output vector
10237 
10238   Note:
10239   The second member of the user context must be an FEMContext.
10240 
10241   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10242   like a GPU, or vectorize on a multicore machine.
10243 
10244 .seealso: DMPlexComputeResidualFEM()
10245 */
10246 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10247 {
10248   DM_Plex      *mesh = (DM_Plex *) dm->data;
10249   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10250   PetscQuadrature *quad = fem->quad;
10251   PetscSection     section;
10252   JacActionCtx    *jctx;
10253   PetscReal       *v0, *J, *invJ, *detJ;
10254   PetscScalar     *elemVec, *u, *a;
10255   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10256   PetscInt         cellDof = 0;
10257   PetscErrorCode   ierr;
10258 
10259   PetscFunctionBegin;
10260   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10261   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10262   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10263   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10264   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10265   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10266   numCells = cEnd - cStart;
10267   for (field = 0; field < numFields; ++field) {
10268     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10269   }
10270   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10271   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);
10272   for (c = cStart; c < cEnd; ++c) {
10273     const PetscScalar *x;
10274     PetscInt           i;
10275 
10276     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10277     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10278     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10279     for (i = 0; i < cellDof; ++i) {
10280       u[c*cellDof+i] = x[i];
10281     }
10282     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10283     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10284     for (i = 0; i < cellDof; ++i) {
10285       a[c*cellDof+i] = x[i];
10286     }
10287     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10288   }
10289   for (field = 0; field < numFields; ++field) {
10290     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10291     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10292     /* Conforming batches */
10293     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10294     PetscInt numBlocks  = 1;
10295     PetscInt batchSize  = numBlocks * blockSize;
10296     PetscInt numBatches = numBatchesTmp;
10297     PetscInt numChunks  = numCells / (numBatches*batchSize);
10298     /* Remainder */
10299     PetscInt numRemainder = numCells % (numBatches * batchSize);
10300     PetscInt offset       = numCells - numRemainder;
10301 
10302     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);
10303     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],
10304                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10305   }
10306   for (c = cStart; c < cEnd; ++c) {
10307     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10308     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10309   }
10310   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10311   if (mesh->printFEM) {
10312     PetscMPIInt rank, numProcs;
10313     PetscInt    p;
10314 
10315     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10316     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10317     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10318     for (p = 0; p < numProcs; ++p) {
10319       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10320       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10321     }
10322   }
10323   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10324   PetscFunctionReturn(0);
10325 }
10326 
10327 #undef __FUNCT__
10328 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10329 /*@
10330   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10331 
10332   Input Parameters:
10333 + dm - The mesh
10334 . X  - Local input vector
10335 - user - The user context
10336 
10337   Output Parameter:
10338 . Jac  - Jacobian matrix
10339 
10340   Note:
10341   The second member of the user context must be an FEMContext.
10342 
10343   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10344   like a GPU, or vectorize on a multicore machine.
10345 
10346 .seealso: FormFunctionLocal()
10347 */
10348 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10349 {
10350   DM_Plex      *mesh = (DM_Plex *) dm->data;
10351   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10352   PetscQuadrature *quad = fem->quad;
10353   PetscSection     section;
10354   PetscReal       *v0, *J, *invJ, *detJ;
10355   PetscScalar     *elemMat, *u;
10356   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10357   PetscInt         cellDof = 0, numComponents = 0;
10358   PetscBool        isShell;
10359   PetscErrorCode   ierr;
10360 
10361   PetscFunctionBegin;
10362   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10363   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10364   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10365   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10366   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10367   numCells = cEnd - cStart;
10368   for (field = 0; field < numFields; ++field) {
10369     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10370     numComponents += quad[field].numComponents;
10371   }
10372   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10373   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10374   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);
10375   for (c = cStart; c < cEnd; ++c) {
10376     const PetscScalar *x;
10377     PetscInt           i;
10378 
10379     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10380     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10381     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10382 
10383     for (i = 0; i < cellDof; ++i) {
10384       u[c*cellDof+i] = x[i];
10385     }
10386     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10387   }
10388   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10389   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10390     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10391     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10392     PetscInt       fieldJ;
10393 
10394     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10395       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10396       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10397       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10398       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10399       /* Conforming batches */
10400       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10401       PetscInt numBlocks  = 1;
10402       PetscInt batchSize  = numBlocks * blockSize;
10403       PetscInt numBatches = numBatchesTmp;
10404       PetscInt numChunks  = numCells / (numBatches*batchSize);
10405       /* Remainder */
10406       PetscInt numRemainder = numCells % (numBatches * batchSize);
10407       PetscInt offset       = numCells - numRemainder;
10408 
10409       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10410       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10411                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10412     }
10413   }
10414   for (c = cStart; c < cEnd; ++c) {
10415     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10416     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10417   }
10418   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10419 
10420   /* Assemble matrix, using the 2-step process:
10421        MatAssemblyBegin(), MatAssemblyEnd(). */
10422   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10423   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10424 
10425   if (mesh->printFEM) {
10426     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10427     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10428     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10429   }
10430   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10431   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10432   if (isShell) {
10433     JacActionCtx *jctx;
10434 
10435     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10436     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10437   }
10438   *str = SAME_NONZERO_PATTERN;
10439   PetscFunctionReturn(0);
10440 }
10441 
10442 
10443 #undef __FUNCT__
10444 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10445 /*@C
10446   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10447   the local section and an SF describing the section point overlap.
10448 
10449   Input Parameters:
10450   + s - The PetscSection for the local field layout
10451   . sf - The SF describing parallel layout of the section points
10452   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10453   . label - The label specifying the points
10454   - labelValue - The label stratum specifying the points
10455 
10456   Output Parameter:
10457   . gsection - The PetscSection for the global field layout
10458 
10459   Note: This gives negative sizes and offsets to points not owned by this process
10460 
10461   Level: developer
10462 
10463 .seealso: PetscSectionCreate()
10464 @*/
10465 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10466 {
10467   PetscInt      *neg;
10468   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10469   PetscErrorCode ierr;
10470 
10471   PetscFunctionBegin;
10472   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10473   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10474   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10475   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10476   /* Mark ghost points with negative dof */
10477   for (p = pStart; p < pEnd; ++p) {
10478     PetscInt value;
10479 
10480     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10481     if (value != labelValue) continue;
10482     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10483     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10484     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10485     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10486     neg[p-pStart] = -(dof+1);
10487   }
10488   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10489   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10490   if (nroots >= 0) {
10491     if (nroots > pEnd - pStart) {
10492       PetscInt *tmpDof;
10493       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10494       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10495       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10496       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10497       for (p = pStart; p < pEnd; ++p) {
10498         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
10499       }
10500       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10501     } else {
10502       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10503       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10504     }
10505   }
10506   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10507   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10508     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10509     (*gsection)->atlasOff[p] = off;
10510     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10511   }
10512   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10513   globalOff -= off;
10514   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10515     (*gsection)->atlasOff[p] += globalOff;
10516     neg[p] = -((*gsection)->atlasOff[p]+1);
10517   }
10518   /* Put in negative offsets for ghost points */
10519   if (nroots >= 0) {
10520     if (nroots > pEnd - pStart) {
10521       PetscInt *tmpOff;
10522       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10523       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10524       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10525       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10526       for (p = pStart; p < pEnd; ++p) {
10527         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
10528       }
10529       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10530     } else {
10531       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10532       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10533     }
10534   }
10535   ierr = PetscFree(neg);CHKERRQ(ierr);
10536   PetscFunctionReturn(0);
10537 }
10538