xref: /petsc/src/dm/impls/plex/plex.c (revision 6ad14cee31e22862e4fd7850d600bd109a2e55c6)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/vecimpl.h>
4 #include <petsc-private/isimpl.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
8 
9 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "VecView_Plex_Local"
14 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
15 {
16   DM             dm;
17   PetscBool      isvtk;
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
22   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
23   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
24   if (isvtk) {
25     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
26     PetscSection            section;
27     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
28 
29     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
30     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
31     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
32     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, NULL);CHKERRQ(ierr);
33     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, NULL);CHKERRQ(ierr);
34     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
35     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
36     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
37     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
38     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
39     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
40       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
41     } else if (cdof && vdof) {
42       SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
43     } else if (cdof) {
44       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
45        * vector or just happens to have the same number of dofs as the dimension. */
46       if (cdof == dim) {
47         ft = PETSC_VTK_CELL_VECTOR_FIELD;
48       } else {
49         ft = PETSC_VTK_CELL_FIELD;
50       }
51     } else if (vdof) {
52       if (vdof == dim) {
53         ft = PETSC_VTK_POINT_VECTOR_FIELD;
54       } else {
55         ft = PETSC_VTK_POINT_FIELD;
56       }
57     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
58 
59     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
60     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
61     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
62   } else {
63     PetscBool isseq;
64 
65     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
66     if (isseq) {
67       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
68     } else {
69       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
70     }
71   }
72   PetscFunctionReturn(0);
73 }
74 
75 #undef __FUNCT__
76 #define __FUNCT__ "VecView_Plex"
77 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
78 {
79   DM             dm;
80   PetscBool      isvtk;
81   PetscErrorCode ierr;
82 
83   PetscFunctionBegin;
84   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
85   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
86   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
87   if (isvtk) {
88     Vec         locv;
89     const char *name;
90 
91     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
92     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
93     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
94     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
95     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
96     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
97     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
98   } else {
99     PetscBool isseq;
100 
101     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
102     if (isseq) {
103       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
104     } else {
105       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
106     }
107   }
108   PetscFunctionReturn(0);
109 }
110 
111 #undef __FUNCT__
112 #define __FUNCT__ "DMPlexView_Ascii"
113 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
114 {
115   DM_Plex          *mesh = (DM_Plex*) dm->data;
116   DM                cdm;
117   DMLabel           markers;
118   PetscSection      coordSection;
119   Vec               coordinates;
120   PetscViewerFormat format;
121   PetscErrorCode    ierr;
122 
123   PetscFunctionBegin;
124   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
125   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
126   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
127   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
128   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
129     const char *name;
130     PetscInt    maxConeSize, maxSupportSize;
131     PetscInt    pStart, pEnd, p;
132     PetscMPIInt rank, size;
133 
134     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
135     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
136     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
137     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
138     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
142     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
143     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
144     for (p = pStart; p < pEnd; ++p) {
145       PetscInt dof, off, s;
146 
147       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
148       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
149       for (s = off; s < off+dof; ++s) {
150         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
151       }
152     }
153     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
154     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
155     for (p = pStart; p < pEnd; ++p) {
156       PetscInt dof, off, c;
157 
158       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
159       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
160       for (c = off; c < off+dof; ++c) {
161         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
162       }
163     }
164     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
165     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
166     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
167     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
168     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
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(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &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(PetscObjectComm((PetscObject)dm), 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 = 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;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscMPIInt size;
282 
283     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
284     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
285     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
286     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
287     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
288     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
289     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
290     if (depth == 1) {
291       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
292       pEnd = pEnd - pStart;
293       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
294       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
295       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
296       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
297       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
298       pEnd = pEnd - pStart;
299       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
300       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
301       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
302       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
303     } else {
304       for (d = 0; d <= dim; d++) {
305         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
306         pEnd = pEnd - pStart;
307         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
308         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
309         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
310         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
311       }
312     }
313     ierr = PetscFree(sizes);CHKERRQ(ierr);
314   }
315   PetscFunctionReturn(0);
316 }
317 
318 #undef __FUNCT__
319 #define __FUNCT__ "DMView_Plex"
320 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
321 {
322   PetscBool      iascii, isbinary;
323   PetscErrorCode ierr;
324 
325   PetscFunctionBegin;
326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
327   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
329   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
330   if (iascii) {
331     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
332 #if 0
333   } else if (isbinary) {
334     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
335 #endif
336   }
337   PetscFunctionReturn(0);
338 }
339 
340 #undef __FUNCT__
341 #define __FUNCT__ "DMDestroy_Plex"
342 PetscErrorCode DMDestroy_Plex(DM dm)
343 {
344   DM_Plex       *mesh = (DM_Plex*) dm->data;
345   DMLabel        next  = mesh->labels;
346   PetscErrorCode ierr;
347 
348   PetscFunctionBegin;
349   if (--mesh->refct > 0) PetscFunctionReturn(0);
350   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
353   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
355   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
356   while (next) {
357     DMLabel tmp = next->next;
358 
359     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
360     next = tmp;
361   }
362   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
364   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
365   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
366   ierr = PetscFree(mesh);CHKERRQ(ierr);
367   PetscFunctionReturn(0);
368 }
369 
370 #undef __FUNCT__
371 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
372 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
373 {
374   const PetscInt *support = NULL;
375   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
376   PetscErrorCode  ierr;
377 
378   PetscFunctionBegin;
379   if (useClosure) {
380     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
381     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
382     for (s = 0; s < supportSize; ++s) {
383       const PetscInt *cone = NULL;
384       PetscInt        coneSize, c, q;
385 
386       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
387       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
388       for (c = 0; c < coneSize; ++c) {
389         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
390           if (cone[c] == adj[q]) break;
391         }
392         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
393       }
394     }
395   } else {
396     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
397     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
398     for (s = 0; s < supportSize; ++s) {
399       const PetscInt *cone = NULL;
400       PetscInt        coneSize, c, q;
401 
402       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
403       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
404       for (c = 0; c < coneSize; ++c) {
405         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
406           if (cone[c] == adj[q]) break;
407         }
408         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
409       }
410     }
411   }
412   *adjSize = numAdj;
413   PetscFunctionReturn(0);
414 }
415 
416 #undef __FUNCT__
417 #define __FUNCT__ "DMPlexGetAdjacency_Private"
418 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
419 {
420   const PetscInt *star  = tmpClosure;
421   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
422   PetscErrorCode  ierr;
423 
424   PetscFunctionBegin;
425   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
426   for (s = 2; s < starSize*2; s += 2) {
427     const PetscInt *closure = NULL;
428     PetscInt        closureSize, c, q;
429 
430     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
431     for (c = 0; c < closureSize*2; c += 2) {
432       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
433         if (closure[c] == adj[q]) break;
434       }
435       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
436     }
437     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
438   }
439   *adjSize = numAdj;
440   PetscFunctionReturn(0);
441 }
442 
443 #undef __FUNCT__
444 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
445 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
446 {
447   DM_Plex *mesh = (DM_Plex*) dm->data;
448 
449   PetscFunctionBegin;
450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
451   mesh->preallocCenterDim = preallocCenterDim;
452   PetscFunctionReturn(0);
453 }
454 
455 #undef __FUNCT__
456 #define __FUNCT__ "DMPlexPreallocateOperator"
457 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
458 {
459   DM_Plex           *mesh = (DM_Plex*) dm->data;
460   MPI_Comm           comm;
461   PetscSF            sf, sfDof, sfAdj;
462   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
463   PetscInt           nleaves, l, p;
464   const PetscInt    *leaves;
465   const PetscSFNode *remotes;
466   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
467   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
468   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
469   PetscLayout        rLayout;
470   PetscInt           locRows, rStart, rEnd, r;
471   PetscMPIInt        size;
472   PetscBool          useClosure, debug = PETSC_FALSE;
473   PetscErrorCode     ierr;
474 
475   PetscFunctionBegin;
476   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
477   ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr);
478   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
479   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
480   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
481   /* Create dof SF based on point SF */
482   if (debug) {
483     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
487     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
488     ierr = PetscSFView(sf, NULL);CHKERRQ(ierr);
489   }
490   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
491   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
492   if (debug) {
493     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
494     ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr);
495   }
496   /* Create section for dof adjacency (dof ==> # adj dof) */
497   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
498   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
499   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
500   if (mesh->preallocCenterDim == dim) {
501     useClosure = PETSC_FALSE;
502   } else if (mesh->preallocCenterDim == 0) {
503     useClosure = PETSC_TRUE;
504   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
505 
506   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
507   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
510   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
511   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
512   /*   Fill in the ghost dofs on the interface */
513   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
514   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
515   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
516 
517   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
518   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
519 
520   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
521 
522   /*
523    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
524     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
525        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
526     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
527        Create sfAdj connecting rootSectionAdj and leafSectionAdj
528     3. Visit unowned points on interface, write adjacencies to adj
529        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
530     4. Visit owned points on interface, write adjacencies to rootAdj
531        Remove redundancy in rootAdj
532    ** The last two traversals use transitive closure
533     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
534        Allocate memory addressed by sectionAdj (cols)
535     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
536    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
537   */
538 
539   for (l = 0; l < nleaves; ++l) {
540     PetscInt dof, off, d, q;
541     PetscInt p = leaves[l], numAdj = maxAdjSize;
542 
543     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
544     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
545     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
546     for (q = 0; q < numAdj; ++q) {
547       const PetscInt padj = tmpAdj[q];
548       PetscInt ndof, ncdof;
549 
550       if ((padj < pStart) || (padj >= pEnd)) continue;
551       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
552       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
553       for (d = off; d < off+dof; ++d) {
554         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
555       }
556     }
557   }
558   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
559   if (debug) {
560     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
561     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
562   }
563   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
564   if (size > 1) {
565     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
566     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
567   }
568   if (debug) {
569     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
570     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
571   }
572   /* Add in local adjacency sizes for owned dofs on interface (roots) */
573   for (p = pStart; p < pEnd; ++p) {
574     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
575 
576     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
577     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
578     if (!dof) continue;
579     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
580     if (adof <= 0) continue;
581     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
582     for (q = 0; q < numAdj; ++q) {
583       const PetscInt padj = tmpAdj[q];
584       PetscInt ndof, ncdof;
585 
586       if ((padj < pStart) || (padj >= pEnd)) continue;
587       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
588       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
589       for (d = off; d < off+dof; ++d) {
590         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
591       }
592     }
593   }
594   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
595   if (debug) {
596     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
597     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
598   }
599   /* Create adj SF based on dof SF */
600   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
601   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
602   if (debug) {
603     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
604     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
605   }
606   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
607   /* Create leaf adjacency */
608   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
609   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
610   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
611   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
612   for (l = 0; l < nleaves; ++l) {
613     PetscInt dof, off, d, q;
614     PetscInt p = leaves[l], numAdj = maxAdjSize;
615 
616     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
617     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
618     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
619     for (d = off; d < off+dof; ++d) {
620       PetscInt aoff, i = 0;
621 
622       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
623       for (q = 0; q < numAdj; ++q) {
624         const PetscInt padj = tmpAdj[q];
625         PetscInt ndof, ncdof, ngoff, nd;
626 
627         if ((padj < pStart) || (padj >= pEnd)) continue;
628         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
629         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
630         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
631         for (nd = 0; nd < ndof-ncdof; ++nd) {
632           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
633           ++i;
634         }
635       }
636     }
637   }
638   /* Debugging */
639   if (debug) {
640     IS tmp;
641     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
642     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
643     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
644   }
645   /* Gather adjacenct indices to root */
646   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
647   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
648   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
649   if (size > 1) {
650     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
651     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
652   }
653   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
654   ierr = PetscFree(adj);CHKERRQ(ierr);
655   /* Debugging */
656   if (debug) {
657     IS tmp;
658     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
659     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
660     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
661   }
662   /* Add in local adjacency indices for owned dofs on interface (roots) */
663   for (p = pStart; p < pEnd; ++p) {
664     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
665 
666     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
667     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
668     if (!dof) continue;
669     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
670     if (adof <= 0) continue;
671     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
672     for (d = off; d < off+dof; ++d) {
673       PetscInt adof, aoff, i;
674 
675       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
676       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
677       i    = adof-1;
678       for (q = 0; q < numAdj; ++q) {
679         const PetscInt padj = tmpAdj[q];
680         PetscInt ndof, ncdof, ngoff, nd;
681 
682         if ((padj < pStart) || (padj >= pEnd)) continue;
683         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
684         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
685         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
686         for (nd = 0; nd < ndof-ncdof; ++nd) {
687           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
688           --i;
689         }
690       }
691     }
692   }
693   /* Debugging */
694   if (debug) {
695     IS tmp;
696     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
697     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
698     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
699   }
700   /* Compress indices */
701   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
702   for (p = pStart; p < pEnd; ++p) {
703     PetscInt dof, cdof, off, d;
704     PetscInt adof, aoff;
705 
706     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
707     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
708     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
709     if (!dof) continue;
710     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
711     if (adof <= 0) continue;
712     for (d = off; d < off+dof-cdof; ++d) {
713       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
714       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
715       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
716       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
717     }
718   }
719   /* Debugging */
720   if (debug) {
721     IS tmp;
722     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
723     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
724     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
725     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
726     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
727   }
728   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
729   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
730   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
731   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
732   for (p = pStart; p < pEnd; ++p) {
733     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
734     PetscBool found  = PETSC_TRUE;
735 
736     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
737     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
738     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
739     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
740     for (d = 0; d < dof-cdof; ++d) {
741       PetscInt ldof, rdof;
742 
743       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
744       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
745       if (ldof > 0) {
746         /* We do not own this point */
747       } else if (rdof > 0) {
748         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
749       } else {
750         found = PETSC_FALSE;
751       }
752     }
753     if (found) continue;
754     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
755     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
756     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
757     for (q = 0; q < numAdj; ++q) {
758       const PetscInt padj = tmpAdj[q];
759       PetscInt ndof, ncdof, noff;
760 
761       if ((padj < pStart) || (padj >= pEnd)) continue;
762       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
763       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
764       ierr = PetscSectionGetOffset(section, padj, &noff);CHKERRQ(ierr);
765       for (d = goff; d < goff+dof-cdof; ++d) {
766         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
767       }
768     }
769   }
770   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
771   if (debug) {
772     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
773     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
774   }
775   /* Get adjacent indices */
776   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
777   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
778   for (p = pStart; p < pEnd; ++p) {
779     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
780     PetscBool found  = PETSC_TRUE;
781 
782     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
783     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
784     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
785     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
786     for (d = 0; d < dof-cdof; ++d) {
787       PetscInt ldof, rdof;
788 
789       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
790       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
791       if (ldof > 0) {
792         /* We do not own this point */
793       } else if (rdof > 0) {
794         PetscInt aoff, roff;
795 
796         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
797         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
798         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
799       } else {
800         found = PETSC_FALSE;
801       }
802     }
803     if (found) continue;
804     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
805     for (d = goff; d < goff+dof-cdof; ++d) {
806       PetscInt adof, aoff, i = 0;
807 
808       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
809       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
810       for (q = 0; q < numAdj; ++q) {
811         const PetscInt  padj = tmpAdj[q];
812         PetscInt        ndof, ncdof, ngoff, nd;
813         const PetscInt *ncind;
814 
815         /* Adjacent points may not be in the section chart */
816         if ((padj < pStart) || (padj >= pEnd)) continue;
817         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
818         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
819         ierr = PetscSectionGetConstraintIndices(section, padj, &ncind);CHKERRQ(ierr);
820         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
821         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
822           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
823         }
824       }
825       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);
826     }
827   }
828   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
829   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
830   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
831   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
832   /* Debugging */
833   if (debug) {
834     IS tmp;
835     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
836     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
837     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
838   }
839   /* Create allocation vectors from adjacency graph */
840   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
841   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr);
842   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
843   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
844   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
845   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
846   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
847   /* Only loop over blocks of rows */
848   if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
849   for (r = rStart/bs; r < rEnd/bs; ++r) {
850     const PetscInt row = r*bs;
851     PetscInt       numCols, cStart, c;
852 
853     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
854     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
855     for (c = cStart; c < cStart+numCols; ++c) {
856       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
857         ++dnz[r-rStart];
858         if (cols[c] >= row) ++dnzu[r-rStart];
859       } else {
860         ++onz[r-rStart];
861         if (cols[c] >= row) ++onzu[r-rStart];
862       }
863     }
864   }
865   if (bs > 1) {
866     for (r = 0; r < locRows/bs; ++r) {
867       dnz[r]  /= bs;
868       onz[r]  /= bs;
869       dnzu[r] /= bs;
870       onzu[r] /= bs;
871     }
872   }
873   /* Set matrix pattern */
874   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
875   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
876   /* Fill matrix with zeros */
877   if (fillMatrix) {
878     PetscScalar *values;
879     PetscInt     maxRowLen = 0;
880 
881     for (r = rStart; r < rEnd; ++r) {
882       PetscInt len;
883 
884       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
885       maxRowLen = PetscMax(maxRowLen, len);
886     }
887     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
888     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
889     for (r = rStart; r < rEnd; ++r) {
890       PetscInt numCols, cStart;
891 
892       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
893       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
894       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
895     }
896     ierr = PetscFree(values);CHKERRQ(ierr);
897     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
898     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
899   }
900   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
901   ierr = PetscFree(cols);CHKERRQ(ierr);
902   PetscFunctionReturn(0);
903 }
904 
905 #if 0
906 #undef __FUNCT__
907 #define __FUNCT__ "DMPlexPreallocateOperator_2"
908 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
909 {
910   PetscInt       *tmpClosure,*tmpAdj,*visits;
911   PetscInt        c,cStart,cEnd,pStart,pEnd;
912   PetscErrorCode  ierr;
913 
914   PetscFunctionBegin;
915   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
916   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
917   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
918 
919   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
920 
921   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
922   npoints = pEnd - pStart;
923 
924   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
925   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
926   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
927   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
928   for (c=cStart; c<cEnd; c++) {
929     PetscInt *support = tmpClosure;
930     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
931     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
932   }
933   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
934   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
935   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
936   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
937 
938   ierr = PetscSFGetRanks();CHKERRQ(ierr);
939 
940 
941   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
942   for (c=cStart; c<cEnd; c++) {
943     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
944     /*
945      Depth-first walk of transitive closure.
946      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.
947      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
948      */
949   }
950 
951   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
952   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
953   PetscFunctionReturn(0);
954 }
955 #endif
956 
957 #undef __FUNCT__
958 #define __FUNCT__ "DMCreateMatrix_Plex"
959 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
960 {
961   PetscSection   section, sectionGlobal;
962   PetscInt       bs = -1;
963   PetscInt       localSize;
964   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
965   PetscErrorCode ierr;
966 
967   PetscFunctionBegin;
968 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
969   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
970 #endif
971   if (!mtype) mtype = MATAIJ;
972   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
973   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
974   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
975   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
976   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
977   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
978   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
979   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
980   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
981   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
982   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
983   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
984   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
985   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
986   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
987   /* Check for symmetric storage */
988   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
989   if (isSymmetric) {
990     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
991   }
992   if (!isShell) {
993     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
994     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
995 
996     if (bs < 0) {
997       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
998         PetscInt pStart, pEnd, p, dof, cdof;
999 
1000         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1001         for (p = pStart; p < pEnd; ++p) {
1002           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
1003           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
1004           if (dof-cdof) {
1005             if (bs < 0) {
1006               bs = dof-cdof;
1007             } else if (bs != dof-cdof) {
1008               /* Layout does not admit a pointwise block size */
1009               bs = 1;
1010               break;
1011             }
1012           }
1013         }
1014         /* Must have same blocksize on all procs (some might have no points) */
1015         bsLocal = bs;
1016         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1017         bsLocal = bs < 0 ? bsMax : bs;
1018         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1019         if (bsMin != bsMax) {
1020           bs = 1;
1021         } else {
1022           bs = bsMax;
1023         }
1024       } else {
1025         bs = 1;
1026       }
1027     }
1028     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1029     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1030     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1031     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1032     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1033     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1034     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1035   }
1036   PetscFunctionReturn(0);
1037 }
1038 
1039 #undef __FUNCT__
1040 #define __FUNCT__ "DMPlexGetDimension"
1041 /*@
1042   DMPlexGetDimension - Return the topological mesh dimension
1043 
1044   Not collective
1045 
1046   Input Parameter:
1047 . mesh - The DMPlex
1048 
1049   Output Parameter:
1050 . dim - The topological mesh dimension
1051 
1052   Level: beginner
1053 
1054 .seealso: DMPlexCreate()
1055 @*/
1056 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1057 {
1058   DM_Plex *mesh = (DM_Plex*) dm->data;
1059 
1060   PetscFunctionBegin;
1061   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1062   PetscValidPointer(dim, 2);
1063   *dim = mesh->dim;
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 #undef __FUNCT__
1068 #define __FUNCT__ "DMPlexSetDimension"
1069 /*@
1070   DMPlexSetDimension - Set the topological mesh dimension
1071 
1072   Collective on mesh
1073 
1074   Input Parameters:
1075 + mesh - The DMPlex
1076 - dim - The topological mesh dimension
1077 
1078   Level: beginner
1079 
1080 .seealso: DMPlexCreate()
1081 @*/
1082 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1083 {
1084   DM_Plex *mesh = (DM_Plex*) dm->data;
1085 
1086   PetscFunctionBegin;
1087   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1088   PetscValidLogicalCollectiveInt(dm, dim, 2);
1089   mesh->dim               = dim;
1090   mesh->preallocCenterDim = dim;
1091   PetscFunctionReturn(0);
1092 }
1093 
1094 #undef __FUNCT__
1095 #define __FUNCT__ "DMPlexGetChart"
1096 /*@
1097   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1098 
1099   Not collective
1100 
1101   Input Parameter:
1102 . mesh - The DMPlex
1103 
1104   Output Parameters:
1105 + pStart - The first mesh point
1106 - pEnd   - The upper bound for mesh points
1107 
1108   Level: beginner
1109 
1110 .seealso: DMPlexCreate(), DMPlexSetChart()
1111 @*/
1112 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1113 {
1114   DM_Plex       *mesh = (DM_Plex*) dm->data;
1115   PetscErrorCode ierr;
1116 
1117   PetscFunctionBegin;
1118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1119   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1120   PetscFunctionReturn(0);
1121 }
1122 
1123 #undef __FUNCT__
1124 #define __FUNCT__ "DMPlexSetChart"
1125 /*@
1126   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1127 
1128   Not collective
1129 
1130   Input Parameters:
1131 + mesh - The DMPlex
1132 . pStart - The first mesh point
1133 - pEnd   - The upper bound for mesh points
1134 
1135   Output Parameters:
1136 
1137   Level: beginner
1138 
1139 .seealso: DMPlexCreate(), DMPlexGetChart()
1140 @*/
1141 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1142 {
1143   DM_Plex       *mesh = (DM_Plex*) dm->data;
1144   PetscErrorCode ierr;
1145 
1146   PetscFunctionBegin;
1147   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1148   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1149   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1150   PetscFunctionReturn(0);
1151 }
1152 
1153 #undef __FUNCT__
1154 #define __FUNCT__ "DMPlexGetConeSize"
1155 /*@
1156   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1157 
1158   Not collective
1159 
1160   Input Parameters:
1161 + mesh - The DMPlex
1162 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1163 
1164   Output Parameter:
1165 . size - The cone size for point p
1166 
1167   Level: beginner
1168 
1169 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1170 @*/
1171 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1172 {
1173   DM_Plex       *mesh = (DM_Plex*) dm->data;
1174   PetscErrorCode ierr;
1175 
1176   PetscFunctionBegin;
1177   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1178   PetscValidPointer(size, 3);
1179   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1180   PetscFunctionReturn(0);
1181 }
1182 
1183 #undef __FUNCT__
1184 #define __FUNCT__ "DMPlexSetConeSize"
1185 /*@
1186   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1187 
1188   Not collective
1189 
1190   Input Parameters:
1191 + mesh - The DMPlex
1192 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1193 - size - The cone size for point p
1194 
1195   Output Parameter:
1196 
1197   Note:
1198   This should be called after DMPlexSetChart().
1199 
1200   Level: beginner
1201 
1202 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1203 @*/
1204 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1205 {
1206   DM_Plex       *mesh = (DM_Plex*) dm->data;
1207   PetscErrorCode ierr;
1208 
1209   PetscFunctionBegin;
1210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1211   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1212 
1213   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1214   PetscFunctionReturn(0);
1215 }
1216 
1217 #undef __FUNCT__
1218 #define __FUNCT__ "DMPlexGetCone"
1219 /*@C
1220   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1221 
1222   Not collective
1223 
1224   Input Parameters:
1225 + mesh - The DMPlex
1226 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1227 
1228   Output Parameter:
1229 . cone - An array of points which are on the in-edges for point p
1230 
1231   Level: beginner
1232 
1233   Note:
1234   This routine is not available in Fortran.
1235 
1236 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1237 @*/
1238 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1239 {
1240   DM_Plex       *mesh = (DM_Plex*) dm->data;
1241   PetscInt       off;
1242   PetscErrorCode ierr;
1243 
1244   PetscFunctionBegin;
1245   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1246   PetscValidPointer(cone, 3);
1247   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1248   *cone = &mesh->cones[off];
1249   PetscFunctionReturn(0);
1250 }
1251 
1252 #undef __FUNCT__
1253 #define __FUNCT__ "DMPlexSetCone"
1254 /*@
1255   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1256 
1257   Not collective
1258 
1259   Input Parameters:
1260 + mesh - The DMPlex
1261 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1262 - cone - An array of points which are on the in-edges for point p
1263 
1264   Output Parameter:
1265 
1266   Note:
1267   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1268 
1269   Level: beginner
1270 
1271 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1272 @*/
1273 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1274 {
1275   DM_Plex       *mesh = (DM_Plex*) dm->data;
1276   PetscInt       pStart, pEnd;
1277   PetscInt       dof, off, c;
1278   PetscErrorCode ierr;
1279 
1280   PetscFunctionBegin;
1281   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1282   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1283   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1284   if (dof) PetscValidPointer(cone, 3);
1285   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1286   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1287   for (c = 0; c < dof; ++c) {
1288     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1289     mesh->cones[off+c] = cone[c];
1290   }
1291   PetscFunctionReturn(0);
1292 }
1293 
1294 #undef __FUNCT__
1295 #define __FUNCT__ "DMPlexGetConeOrientation"
1296 /*@C
1297   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1298 
1299   Not collective
1300 
1301   Input Parameters:
1302 + mesh - The DMPlex
1303 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1304 
1305   Output Parameter:
1306 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1307                     integer giving the prescription for cone traversal. If it is negative, the cone is
1308                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1309                     the index of the cone point on which to start.
1310 
1311   Level: beginner
1312 
1313   Note:
1314   This routine is not available in Fortran.
1315 
1316 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1317 @*/
1318 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1319 {
1320   DM_Plex       *mesh = (DM_Plex*) dm->data;
1321   PetscInt       off;
1322   PetscErrorCode ierr;
1323 
1324   PetscFunctionBegin;
1325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1326 #if defined(PETSC_USE_DEBUG)
1327   {
1328     PetscInt dof;
1329     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1330     if (dof) PetscValidPointer(coneOrientation, 3);
1331   }
1332 #endif
1333   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1334 
1335   *coneOrientation = &mesh->coneOrientations[off];
1336   PetscFunctionReturn(0);
1337 }
1338 
1339 #undef __FUNCT__
1340 #define __FUNCT__ "DMPlexSetConeOrientation"
1341 /*@
1342   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1343 
1344   Not collective
1345 
1346   Input Parameters:
1347 + mesh - The DMPlex
1348 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1349 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1350                     integer giving the prescription for cone traversal. If it is negative, the cone is
1351                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1352                     the index of the cone point on which to start.
1353 
1354   Output Parameter:
1355 
1356   Note:
1357   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1358 
1359   Level: beginner
1360 
1361 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1362 @*/
1363 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1364 {
1365   DM_Plex       *mesh = (DM_Plex*) dm->data;
1366   PetscInt       pStart, pEnd;
1367   PetscInt       dof, off, c;
1368   PetscErrorCode ierr;
1369 
1370   PetscFunctionBegin;
1371   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1372   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1373   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1374   if (dof) PetscValidPointer(coneOrientation, 3);
1375   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1376   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1377   for (c = 0; c < dof; ++c) {
1378     PetscInt cdof, o = coneOrientation[c];
1379 
1380     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1381     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1382     mesh->coneOrientations[off+c] = o;
1383   }
1384   PetscFunctionReturn(0);
1385 }
1386 
1387 #undef __FUNCT__
1388 #define __FUNCT__ "DMPlexInsertCone"
1389 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1390 {
1391   DM_Plex       *mesh = (DM_Plex*) dm->data;
1392   PetscInt       pStart, pEnd;
1393   PetscInt       dof, off;
1394   PetscErrorCode ierr;
1395 
1396   PetscFunctionBegin;
1397   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1398   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1399   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1400   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1401   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1402   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1403   if (conePos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1404   mesh->cones[off+conePos] = conePoint;
1405   PetscFunctionReturn(0);
1406 }
1407 
1408 #undef __FUNCT__
1409 #define __FUNCT__ "DMPlexGetSupportSize"
1410 /*@
1411   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1412 
1413   Not collective
1414 
1415   Input Parameters:
1416 + mesh - The DMPlex
1417 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1418 
1419   Output Parameter:
1420 . size - The support size for point p
1421 
1422   Level: beginner
1423 
1424 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1425 @*/
1426 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1427 {
1428   DM_Plex       *mesh = (DM_Plex*) dm->data;
1429   PetscErrorCode ierr;
1430 
1431   PetscFunctionBegin;
1432   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1433   PetscValidPointer(size, 3);
1434   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1435   PetscFunctionReturn(0);
1436 }
1437 
1438 #undef __FUNCT__
1439 #define __FUNCT__ "DMPlexSetSupportSize"
1440 /*@
1441   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1442 
1443   Not collective
1444 
1445   Input Parameters:
1446 + mesh - The DMPlex
1447 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1448 - size - The support size for point p
1449 
1450   Output Parameter:
1451 
1452   Note:
1453   This should be called after DMPlexSetChart().
1454 
1455   Level: beginner
1456 
1457 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1458 @*/
1459 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1460 {
1461   DM_Plex       *mesh = (DM_Plex*) dm->data;
1462   PetscErrorCode ierr;
1463 
1464   PetscFunctionBegin;
1465   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1466   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1467 
1468   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1469   PetscFunctionReturn(0);
1470 }
1471 
1472 #undef __FUNCT__
1473 #define __FUNCT__ "DMPlexGetSupport"
1474 /*@C
1475   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1476 
1477   Not collective
1478 
1479   Input Parameters:
1480 + mesh - The DMPlex
1481 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1482 
1483   Output Parameter:
1484 . support - An array of points which are on the out-edges for point p
1485 
1486   Level: beginner
1487 
1488 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1489 @*/
1490 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1491 {
1492   DM_Plex       *mesh = (DM_Plex*) dm->data;
1493   PetscInt       off;
1494   PetscErrorCode ierr;
1495 
1496   PetscFunctionBegin;
1497   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1498   PetscValidPointer(support, 3);
1499   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1500   *support = &mesh->supports[off];
1501   PetscFunctionReturn(0);
1502 }
1503 
1504 #undef __FUNCT__
1505 #define __FUNCT__ "DMPlexSetSupport"
1506 /*@
1507   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1508 
1509   Not collective
1510 
1511   Input Parameters:
1512 + mesh - The DMPlex
1513 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1514 - support - An array of points which are on the in-edges for point p
1515 
1516   Output Parameter:
1517 
1518   Note:
1519   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1520 
1521   Level: beginner
1522 
1523 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1524 @*/
1525 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1526 {
1527   DM_Plex       *mesh = (DM_Plex*) dm->data;
1528   PetscInt       pStart, pEnd;
1529   PetscInt       dof, off, c;
1530   PetscErrorCode ierr;
1531 
1532   PetscFunctionBegin;
1533   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1534   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1535   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1536   if (dof) PetscValidPointer(support, 3);
1537   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1538   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1539   for (c = 0; c < dof; ++c) {
1540     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1541     mesh->supports[off+c] = support[c];
1542   }
1543   PetscFunctionReturn(0);
1544 }
1545 
1546 #undef __FUNCT__
1547 #define __FUNCT__ "DMPlexInsertSupport"
1548 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1549 {
1550   DM_Plex       *mesh = (DM_Plex*) dm->data;
1551   PetscInt       pStart, pEnd;
1552   PetscInt       dof, off;
1553   PetscErrorCode ierr;
1554 
1555   PetscFunctionBegin;
1556   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1557   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1558   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1559   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1560   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1561   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1562   if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1563   mesh->supports[off+supportPos] = supportPoint;
1564   PetscFunctionReturn(0);
1565 }
1566 
1567 #undef __FUNCT__
1568 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1569 /*@C
1570   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1571 
1572   Not collective
1573 
1574   Input Parameters:
1575 + mesh - The DMPlex
1576 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1577 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1578 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1579 
1580   Output Parameters:
1581 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1582 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1583 
1584   Note:
1585   If using internal storage (points is NULL on input), each call overwrites the last output.
1586 
1587   Level: beginner
1588 
1589 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1590 @*/
1591 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1592 {
1593   DM_Plex        *mesh = (DM_Plex*) dm->data;
1594   PetscInt       *closure, *fifo;
1595   const PetscInt *tmp = NULL, *tmpO = NULL;
1596   PetscInt        tmpSize, t;
1597   PetscInt        depth       = 0, maxSize;
1598   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1599   PetscErrorCode  ierr;
1600 
1601   PetscFunctionBegin;
1602   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1603   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1604   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1605   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1606   if (*points) {
1607     closure = *points;
1608   } else {
1609     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1610   }
1611   closure[0] = p; closure[1] = 0;
1612   /* This is only 1-level */
1613   if (useCone) {
1614     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1615     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1616     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1617   } else {
1618     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1619     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1620   }
1621   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1622     const PetscInt cp = tmp[t];
1623     const PetscInt co = tmpO ? tmpO[t] : 0;
1624 
1625     closure[closureSize]   = cp;
1626     closure[closureSize+1] = co;
1627     fifo[fifoSize]         = cp;
1628     fifo[fifoSize+1]       = co;
1629   }
1630   while (fifoSize - fifoStart) {
1631     const PetscInt q   = fifo[fifoStart];
1632     const PetscInt o   = fifo[fifoStart+1];
1633     const PetscInt rev = o >= 0 ? 0 : 1;
1634     const PetscInt off = rev ? -(o+1) : o;
1635 
1636     if (useCone) {
1637       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1638       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1639       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1640     } else {
1641       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1642       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1643       tmpO = NULL;
1644     }
1645     for (t = 0; t < tmpSize; ++t) {
1646       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1647       const PetscInt cp = tmp[i];
1648       /* Must propogate orientation */
1649       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1650       PetscInt       c;
1651 
1652       /* Check for duplicate */
1653       for (c = 0; c < closureSize; c += 2) {
1654         if (closure[c] == cp) break;
1655       }
1656       if (c == closureSize) {
1657         closure[closureSize]   = cp;
1658         closure[closureSize+1] = co;
1659         fifo[fifoSize]         = cp;
1660         fifo[fifoSize+1]       = co;
1661         closureSize           += 2;
1662         fifoSize              += 2;
1663       }
1664     }
1665     fifoStart += 2;
1666   }
1667   if (numPoints) *numPoints = closureSize/2;
1668   if (points)    *points    = closure;
1669   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1670   PetscFunctionReturn(0);
1671 }
1672 
1673 #undef __FUNCT__
1674 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1675 /*@C
1676   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1677 
1678   Not collective
1679 
1680   Input Parameters:
1681 + mesh - The DMPlex
1682 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1683 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1684 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1685 
1686   Output Parameters:
1687 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1688 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1689 
1690   Note:
1691   If not using internal storage (points is not NULL on input), this call is unnecessary
1692 
1693   Level: beginner
1694 
1695 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1696 @*/
1697 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1698 {
1699   PetscErrorCode ierr;
1700 
1701   PetscFunctionBegin;
1702   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1703   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1704   PetscFunctionReturn(0);
1705 }
1706 
1707 #undef __FUNCT__
1708 #define __FUNCT__ "DMPlexGetMaxSizes"
1709 /*@
1710   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1711 
1712   Not collective
1713 
1714   Input Parameter:
1715 . mesh - The DMPlex
1716 
1717   Output Parameters:
1718 + maxConeSize - The maximum number of in-edges
1719 - maxSupportSize - The maximum number of out-edges
1720 
1721   Level: beginner
1722 
1723 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1724 @*/
1725 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1726 {
1727   DM_Plex *mesh = (DM_Plex*) dm->data;
1728 
1729   PetscFunctionBegin;
1730   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1731   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1732   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1733   PetscFunctionReturn(0);
1734 }
1735 
1736 #undef __FUNCT__
1737 #define __FUNCT__ "DMSetUp_Plex"
1738 PetscErrorCode DMSetUp_Plex(DM dm)
1739 {
1740   DM_Plex       *mesh = (DM_Plex*) dm->data;
1741   PetscInt       size;
1742   PetscErrorCode ierr;
1743 
1744   PetscFunctionBegin;
1745   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1746   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1747   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1748   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1749   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1750   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1751   if (mesh->maxSupportSize) {
1752     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1753     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1754     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1755   }
1756   PetscFunctionReturn(0);
1757 }
1758 
1759 #undef __FUNCT__
1760 #define __FUNCT__ "DMCreateSubDM_Plex"
1761 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1762 {
1763   PetscSection   section, sectionGlobal;
1764   PetscInt      *subIndices;
1765   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1766   PetscErrorCode ierr;
1767 
1768   PetscFunctionBegin;
1769   if (!numFields) PetscFunctionReturn(0);
1770   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1771   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1772   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1773   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1774   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1775   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1776   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1777   for (p = pStart; p < pEnd; ++p) {
1778     PetscInt gdof;
1779 
1780     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1781     if (gdof > 0) {
1782       for (f = 0; f < numFields; ++f) {
1783         PetscInt fdof, fcdof;
1784 
1785         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1786         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1787         subSize += fdof-fcdof;
1788       }
1789     }
1790   }
1791   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1792   for (p = pStart; p < pEnd; ++p) {
1793     PetscInt gdof, goff;
1794 
1795     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1796     if (gdof > 0) {
1797       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1798       for (f = 0; f < numFields; ++f) {
1799         PetscInt fdof, fcdof, fc, f2, poff = 0;
1800 
1801         /* Can get rid of this loop by storing field information in the global section */
1802         for (f2 = 0; f2 < fields[f]; ++f2) {
1803           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1804           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1805           poff += fdof-fcdof;
1806         }
1807         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1808         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1809         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1810           subIndices[subOff] = goff+poff+fc;
1811         }
1812       }
1813     }
1814   }
1815   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1816   if (subdm) {
1817     PetscSection subsection;
1818     PetscBool    haveNull = PETSC_FALSE;
1819     PetscInt     f, nf = 0;
1820 
1821     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1822     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1823     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1824     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1825     for (f = 0; f < numFields; ++f) {
1826       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1827       if ((*subdm)->nullspaceConstructors[f]) {
1828         haveNull = PETSC_TRUE;
1829         nf       = f;
1830       }
1831     }
1832     if (haveNull) {
1833       MatNullSpace nullSpace;
1834 
1835       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1836       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1837       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1838     }
1839     if (dm->fields) {
1840       if (nF != dm->numFields) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1841       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1842       for (f = 0; f < numFields; ++f) {
1843         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1844       }
1845       if (numFields == 1) {
1846         MatNullSpace space;
1847         Mat          pmat;
1848 
1849         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1850         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1851         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1852         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1853         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1854         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1855       }
1856     }
1857   }
1858   PetscFunctionReturn(0);
1859 }
1860 
1861 #undef __FUNCT__
1862 #define __FUNCT__ "DMPlexSymmetrize"
1863 /*@
1864   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1865 
1866   Not collective
1867 
1868   Input Parameter:
1869 . mesh - The DMPlex
1870 
1871   Output Parameter:
1872 
1873   Note:
1874   This should be called after all calls to DMPlexSetCone()
1875 
1876   Level: beginner
1877 
1878 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1879 @*/
1880 PetscErrorCode DMPlexSymmetrize(DM dm)
1881 {
1882   DM_Plex       *mesh = (DM_Plex*) dm->data;
1883   PetscInt      *offsets;
1884   PetscInt       supportSize;
1885   PetscInt       pStart, pEnd, p;
1886   PetscErrorCode ierr;
1887 
1888   PetscFunctionBegin;
1889   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1890   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1891   /* Calculate support sizes */
1892   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1893   for (p = pStart; p < pEnd; ++p) {
1894     PetscInt dof, off, c;
1895 
1896     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1897     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1898     for (c = off; c < off+dof; ++c) {
1899       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1900     }
1901   }
1902   for (p = pStart; p < pEnd; ++p) {
1903     PetscInt dof;
1904 
1905     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1906 
1907     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1908   }
1909   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1910   /* Calculate supports */
1911   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1912   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1913   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1914   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1915   for (p = pStart; p < pEnd; ++p) {
1916     PetscInt dof, off, c;
1917 
1918     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1919     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1920     for (c = off; c < off+dof; ++c) {
1921       const PetscInt q = mesh->cones[c];
1922       PetscInt       offS;
1923 
1924       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1925 
1926       mesh->supports[offS+offsets[q]] = p;
1927       ++offsets[q];
1928     }
1929   }
1930   ierr = PetscFree(offsets);CHKERRQ(ierr);
1931   PetscFunctionReturn(0);
1932 }
1933 
1934 #undef __FUNCT__
1935 #define __FUNCT__ "DMPlexSetDepth_Private"
1936 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1937 {
1938   PetscInt       d;
1939   PetscErrorCode ierr;
1940 
1941   PetscFunctionBegin;
1942   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1943   if (d < 0) {
1944     /* We are guaranteed that the point has a cone since the depth was not yet set */
1945     const PetscInt *cone = NULL;
1946     PetscInt        dCone;
1947 
1948     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1949     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1950     d    = dCone+1;
1951     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1952   }
1953   *depth = d;
1954   PetscFunctionReturn(0);
1955 }
1956 
1957 #undef __FUNCT__
1958 #define __FUNCT__ "DMPlexStratify"
1959 /*@
1960   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1961   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1962   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1963   the DAG.
1964 
1965   Not collective
1966 
1967   Input Parameter:
1968 . mesh - The DMPlex
1969 
1970   Output Parameter:
1971 
1972   Notes:
1973   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1974   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1975 
1976   This should be called after all calls to DMPlexSymmetrize()
1977 
1978   Level: beginner
1979 
1980 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1981 @*/
1982 PetscErrorCode DMPlexStratify(DM dm)
1983 {
1984   DM_Plex       *mesh = (DM_Plex*) dm->data;
1985   PetscInt       pStart, pEnd, p;
1986   PetscInt       numRoots = 0, numLeaves = 0;
1987   PetscErrorCode ierr;
1988 
1989   PetscFunctionBegin;
1990   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1991   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1992   /* Calculate depth */
1993   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1994   /* Initialize roots and count leaves */
1995   for (p = pStart; p < pEnd; ++p) {
1996     PetscInt coneSize, supportSize;
1997 
1998     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1999     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2000     if (!coneSize && supportSize) {
2001       ++numRoots;
2002       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2003     } else if (!supportSize && coneSize) {
2004       ++numLeaves;
2005     } else if (!supportSize && !coneSize) {
2006       /* Isolated points */
2007       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2008     }
2009   }
2010   if (numRoots + numLeaves == (pEnd - pStart)) {
2011     for (p = pStart; p < pEnd; ++p) {
2012       PetscInt coneSize, supportSize;
2013 
2014       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2015       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2016       if (!supportSize && coneSize) {
2017         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2018       }
2019     }
2020   } else {
2021     /* This might be slow since lookup is not fast */
2022     for (p = pStart; p < pEnd; ++p) {
2023       PetscInt depth;
2024 
2025       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2026     }
2027   }
2028   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2029   PetscFunctionReturn(0);
2030 }
2031 
2032 #undef __FUNCT__
2033 #define __FUNCT__ "DMPlexGetJoin"
2034 /*@C
2035   DMPlexGetJoin - Get an array for the join of the set of points
2036 
2037   Not Collective
2038 
2039   Input Parameters:
2040 + dm - The DMPlex object
2041 . numPoints - The number of input points for the join
2042 - points - The input points
2043 
2044   Output Parameters:
2045 + numCoveredPoints - The number of points in the join
2046 - coveredPoints - The points in the join
2047 
2048   Level: intermediate
2049 
2050   Note: Currently, this is restricted to a single level join
2051 
2052 .keywords: mesh
2053 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2054 @*/
2055 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2056 {
2057   DM_Plex       *mesh = (DM_Plex*) dm->data;
2058   PetscInt      *join[2];
2059   PetscInt       joinSize, i = 0;
2060   PetscInt       dof, off, p, c, m;
2061   PetscErrorCode ierr;
2062 
2063   PetscFunctionBegin;
2064   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2065   PetscValidPointer(points, 2);
2066   PetscValidPointer(numCoveredPoints, 3);
2067   PetscValidPointer(coveredPoints, 4);
2068   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2069   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2070   /* Copy in support of first point */
2071   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2072   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2073   for (joinSize = 0; joinSize < dof; ++joinSize) {
2074     join[i][joinSize] = mesh->supports[off+joinSize];
2075   }
2076   /* Check each successive support */
2077   for (p = 1; p < numPoints; ++p) {
2078     PetscInt newJoinSize = 0;
2079 
2080     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2081     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2082     for (c = 0; c < dof; ++c) {
2083       const PetscInt point = mesh->supports[off+c];
2084 
2085       for (m = 0; m < joinSize; ++m) {
2086         if (point == join[i][m]) {
2087           join[1-i][newJoinSize++] = point;
2088           break;
2089         }
2090       }
2091     }
2092     joinSize = newJoinSize;
2093     i        = 1-i;
2094   }
2095   *numCoveredPoints = joinSize;
2096   *coveredPoints    = join[i];
2097   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2098   PetscFunctionReturn(0);
2099 }
2100 
2101 #undef __FUNCT__
2102 #define __FUNCT__ "DMPlexRestoreJoin"
2103 /*@C
2104   DMPlexRestoreJoin - Restore an array for the join of the set of points
2105 
2106   Not Collective
2107 
2108   Input Parameters:
2109 + dm - The DMPlex object
2110 . numPoints - The number of input points for the join
2111 - points - The input points
2112 
2113   Output Parameters:
2114 + numCoveredPoints - The number of points in the join
2115 - coveredPoints - The points in the join
2116 
2117   Level: intermediate
2118 
2119 .keywords: mesh
2120 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2121 @*/
2122 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2123 {
2124   PetscErrorCode ierr;
2125 
2126   PetscFunctionBegin;
2127   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2128   PetscValidPointer(coveredPoints, 4);
2129   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2130   PetscFunctionReturn(0);
2131 }
2132 
2133 #undef __FUNCT__
2134 #define __FUNCT__ "DMPlexGetFullJoin"
2135 /*@C
2136   DMPlexGetFullJoin - Get an array for the join of the set of points
2137 
2138   Not Collective
2139 
2140   Input Parameters:
2141 + dm - The DMPlex object
2142 . numPoints - The number of input points for the join
2143 - points - The input points
2144 
2145   Output Parameters:
2146 + numCoveredPoints - The number of points in the join
2147 - coveredPoints - The points in the join
2148 
2149   Level: intermediate
2150 
2151 .keywords: mesh
2152 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2153 @*/
2154 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2155 {
2156   DM_Plex       *mesh = (DM_Plex*) dm->data;
2157   PetscInt      *offsets, **closures;
2158   PetscInt      *join[2];
2159   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2160   PetscInt       p, d, c, m;
2161   PetscErrorCode ierr;
2162 
2163   PetscFunctionBegin;
2164   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2165   PetscValidPointer(points, 2);
2166   PetscValidPointer(numCoveredPoints, 3);
2167   PetscValidPointer(coveredPoints, 4);
2168 
2169   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2170   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2171   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2172   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2173   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2174   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2175   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2176 
2177   for (p = 0; p < numPoints; ++p) {
2178     PetscInt closureSize;
2179 
2180     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2181 
2182     offsets[p*(depth+2)+0] = 0;
2183     for (d = 0; d < depth+1; ++d) {
2184       PetscInt pStart, pEnd, i;
2185 
2186       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2187       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2188         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2189           offsets[p*(depth+2)+d+1] = i;
2190           break;
2191         }
2192       }
2193       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2194     }
2195     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2196   }
2197   for (d = 0; d < depth+1; ++d) {
2198     PetscInt dof;
2199 
2200     /* Copy in support of first point */
2201     dof = offsets[d+1] - offsets[d];
2202     for (joinSize = 0; joinSize < dof; ++joinSize) {
2203       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2204     }
2205     /* Check each successive cone */
2206     for (p = 1; p < numPoints && joinSize; ++p) {
2207       PetscInt newJoinSize = 0;
2208 
2209       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2210       for (c = 0; c < dof; ++c) {
2211         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2212 
2213         for (m = 0; m < joinSize; ++m) {
2214           if (point == join[i][m]) {
2215             join[1-i][newJoinSize++] = point;
2216             break;
2217           }
2218         }
2219       }
2220       joinSize = newJoinSize;
2221       i        = 1-i;
2222     }
2223     if (joinSize) break;
2224   }
2225   *numCoveredPoints = joinSize;
2226   *coveredPoints    = join[i];
2227   for (p = 0; p < numPoints; ++p) {
2228     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2229   }
2230   ierr = PetscFree(closures);CHKERRQ(ierr);
2231   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2232   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2233   PetscFunctionReturn(0);
2234 }
2235 
2236 #undef __FUNCT__
2237 #define __FUNCT__ "DMPlexGetMeet"
2238 /*@C
2239   DMPlexGetMeet - Get an array for the meet of the set of points
2240 
2241   Not Collective
2242 
2243   Input Parameters:
2244 + dm - The DMPlex object
2245 . numPoints - The number of input points for the meet
2246 - points - The input points
2247 
2248   Output Parameters:
2249 + numCoveredPoints - The number of points in the meet
2250 - coveredPoints - The points in the meet
2251 
2252   Level: intermediate
2253 
2254   Note: Currently, this is restricted to a single level meet
2255 
2256 .keywords: mesh
2257 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2258 @*/
2259 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2260 {
2261   DM_Plex       *mesh = (DM_Plex*) dm->data;
2262   PetscInt      *meet[2];
2263   PetscInt       meetSize, i = 0;
2264   PetscInt       dof, off, p, c, m;
2265   PetscErrorCode ierr;
2266 
2267   PetscFunctionBegin;
2268   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2269   PetscValidPointer(points, 2);
2270   PetscValidPointer(numCoveringPoints, 3);
2271   PetscValidPointer(coveringPoints, 4);
2272   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2273   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2274   /* Copy in cone of first point */
2275   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2276   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2277   for (meetSize = 0; meetSize < dof; ++meetSize) {
2278     meet[i][meetSize] = mesh->cones[off+meetSize];
2279   }
2280   /* Check each successive cone */
2281   for (p = 1; p < numPoints; ++p) {
2282     PetscInt newMeetSize = 0;
2283 
2284     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2285     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2286     for (c = 0; c < dof; ++c) {
2287       const PetscInt point = mesh->cones[off+c];
2288 
2289       for (m = 0; m < meetSize; ++m) {
2290         if (point == meet[i][m]) {
2291           meet[1-i][newMeetSize++] = point;
2292           break;
2293         }
2294       }
2295     }
2296     meetSize = newMeetSize;
2297     i        = 1-i;
2298   }
2299   *numCoveringPoints = meetSize;
2300   *coveringPoints    = meet[i];
2301   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2302   PetscFunctionReturn(0);
2303 }
2304 
2305 #undef __FUNCT__
2306 #define __FUNCT__ "DMPlexRestoreMeet"
2307 /*@C
2308   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2309 
2310   Not Collective
2311 
2312   Input Parameters:
2313 + dm - The DMPlex object
2314 . numPoints - The number of input points for the meet
2315 - points - The input points
2316 
2317   Output Parameters:
2318 + numCoveredPoints - The number of points in the meet
2319 - coveredPoints - The points in the meet
2320 
2321   Level: intermediate
2322 
2323 .keywords: mesh
2324 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2325 @*/
2326 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2327 {
2328   PetscErrorCode ierr;
2329 
2330   PetscFunctionBegin;
2331   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2332   PetscValidPointer(coveredPoints, 4);
2333   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2334   PetscFunctionReturn(0);
2335 }
2336 
2337 #undef __FUNCT__
2338 #define __FUNCT__ "DMPlexGetFullMeet"
2339 /*@C
2340   DMPlexGetFullMeet - Get an array for the meet of the set of points
2341 
2342   Not Collective
2343 
2344   Input Parameters:
2345 + dm - The DMPlex object
2346 . numPoints - The number of input points for the meet
2347 - points - The input points
2348 
2349   Output Parameters:
2350 + numCoveredPoints - The number of points in the meet
2351 - coveredPoints - The points in the meet
2352 
2353   Level: intermediate
2354 
2355 .keywords: mesh
2356 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2357 @*/
2358 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2359 {
2360   DM_Plex       *mesh = (DM_Plex*) dm->data;
2361   PetscInt      *offsets, **closures;
2362   PetscInt      *meet[2];
2363   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2364   PetscInt       p, h, c, m;
2365   PetscErrorCode ierr;
2366 
2367   PetscFunctionBegin;
2368   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2369   PetscValidPointer(points, 2);
2370   PetscValidPointer(numCoveredPoints, 3);
2371   PetscValidPointer(coveredPoints, 4);
2372 
2373   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2374   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2375   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2376   maxSize = PetscPowInt(mesh->maxConeSize,height);
2377   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2378   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2379 
2380   for (p = 0; p < numPoints; ++p) {
2381     PetscInt closureSize;
2382 
2383     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2384 
2385     offsets[p*(height+2)+0] = 0;
2386     for (h = 0; h < height+1; ++h) {
2387       PetscInt pStart, pEnd, i;
2388 
2389       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2390       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2391         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2392           offsets[p*(height+2)+h+1] = i;
2393           break;
2394         }
2395       }
2396       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2397     }
2398     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2399   }
2400   for (h = 0; h < height+1; ++h) {
2401     PetscInt dof;
2402 
2403     /* Copy in cone of first point */
2404     dof = offsets[h+1] - offsets[h];
2405     for (meetSize = 0; meetSize < dof; ++meetSize) {
2406       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2407     }
2408     /* Check each successive cone */
2409     for (p = 1; p < numPoints && meetSize; ++p) {
2410       PetscInt newMeetSize = 0;
2411 
2412       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2413       for (c = 0; c < dof; ++c) {
2414         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2415 
2416         for (m = 0; m < meetSize; ++m) {
2417           if (point == meet[i][m]) {
2418             meet[1-i][newMeetSize++] = point;
2419             break;
2420           }
2421         }
2422       }
2423       meetSize = newMeetSize;
2424       i        = 1-i;
2425     }
2426     if (meetSize) break;
2427   }
2428   *numCoveredPoints = meetSize;
2429   *coveredPoints    = meet[i];
2430   for (p = 0; p < numPoints; ++p) {
2431     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2432   }
2433   ierr = PetscFree(closures);CHKERRQ(ierr);
2434   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2435   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2436   PetscFunctionReturn(0);
2437 }
2438 
2439 #undef __FUNCT__
2440 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2441 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2442 {
2443   MPI_Comm       comm;
2444   PetscInt       cellDim;
2445   PetscErrorCode ierr;
2446 
2447   PetscFunctionBegin;
2448   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2449   PetscValidPointer(numFaceVertices,3);
2450   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2451   switch (cellDim) {
2452   case 0:
2453     *numFaceVertices = 0;
2454     break;
2455   case 1:
2456     *numFaceVertices = 1;
2457     break;
2458   case 2:
2459     switch (numCorners) {
2460     case 3: /* triangle */
2461       *numFaceVertices = 2; /* Edge has 2 vertices */
2462       break;
2463     case 4: /* quadrilateral */
2464       *numFaceVertices = 2; /* Edge has 2 vertices */
2465       break;
2466     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2467       *numFaceVertices = 3; /* Edge has 3 vertices */
2468       break;
2469     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2470       *numFaceVertices = 3; /* Edge has 3 vertices */
2471       break;
2472     default:
2473       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2474     }
2475     break;
2476   case 3:
2477     switch (numCorners) {
2478     case 4: /* tetradehdron */
2479       *numFaceVertices = 3; /* Face has 3 vertices */
2480       break;
2481     case 6: /* tet cohesive cells */
2482       *numFaceVertices = 4; /* Face has 4 vertices */
2483       break;
2484     case 8: /* hexahedron */
2485       *numFaceVertices = 4; /* Face has 4 vertices */
2486       break;
2487     case 9: /* tet cohesive Lagrange cells */
2488       *numFaceVertices = 6; /* Face has 6 vertices */
2489       break;
2490     case 10: /* quadratic tetrahedron */
2491       *numFaceVertices = 6; /* Face has 6 vertices */
2492       break;
2493     case 12: /* hex cohesive Lagrange cells */
2494       *numFaceVertices = 6; /* Face has 6 vertices */
2495       break;
2496     case 18: /* quadratic tet cohesive Lagrange cells */
2497       *numFaceVertices = 6; /* Face has 6 vertices */
2498       break;
2499     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2500       *numFaceVertices = 9; /* Face has 9 vertices */
2501       break;
2502     default:
2503       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2504     }
2505     break;
2506   default:
2507     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2508   }
2509   PetscFunctionReturn(0);
2510 }
2511 
2512 #undef __FUNCT__
2513 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2514 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2515 {
2516   const PetscInt maxFaceCases = 30;
2517   PetscInt       numFaceCases = 0;
2518   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2519   PetscInt      *off, *adj;
2520   PetscInt      *neighborCells, *tmpClosure;
2521   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2522   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2523   PetscErrorCode ierr;
2524 
2525   PetscFunctionBegin;
2526   /* For parallel partitioning, I think you have to communicate supports */
2527   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2528   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2529   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2530   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2531   if (cEnd - cStart == 0) {
2532     if (numVertices) *numVertices = 0;
2533     if (offsets)   *offsets   = NULL;
2534     if (adjacency) *adjacency = NULL;
2535     PetscFunctionReturn(0);
2536   }
2537   numCells = cEnd - cStart;
2538   /* Setup face recognition */
2539   if (depth == 1) {
2540     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 */
2541 
2542     for (c = cStart; c < cEnd; ++c) {
2543       PetscInt corners;
2544 
2545       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2546       if (!cornersSeen[corners]) {
2547         PetscInt nFV;
2548 
2549         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2550         cornersSeen[corners] = 1;
2551 
2552         ierr = DMPlexGetNumFaceVertices_Internal(dm, corners, &nFV);CHKERRQ(ierr);
2553 
2554         numFaceVertices[numFaceCases++] = nFV;
2555       }
2556     }
2557   }
2558   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2559   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2560   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2561   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2562   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2563   /* Count neighboring cells */
2564   for (cell = cStart; cell < cEnd; ++cell) {
2565     PetscInt numNeighbors = maxNeighbors, n;
2566 
2567     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2568     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2569     for (n = 0; n < numNeighbors; ++n) {
2570       PetscInt        cellPair[2];
2571       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2572       PetscInt        meetSize = 0;
2573       const PetscInt *meet    = NULL;
2574 
2575       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2576       if (cellPair[0] == cellPair[1]) continue;
2577       if (!found) {
2578         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2579         if (meetSize) {
2580           PetscInt f;
2581 
2582           for (f = 0; f < numFaceCases; ++f) {
2583             if (numFaceVertices[f] == meetSize) {
2584               found = PETSC_TRUE;
2585               break;
2586             }
2587           }
2588         }
2589         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2590       }
2591       if (found) ++off[cell-cStart+1];
2592     }
2593   }
2594   /* Prefix sum */
2595   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2596 
2597   if (adjacency) {
2598     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2599     /* Get neighboring cells */
2600     for (cell = cStart; cell < cEnd; ++cell) {
2601       PetscInt numNeighbors = maxNeighbors, n;
2602       PetscInt cellOffset   = 0;
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];
2608         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2609         PetscInt        meetSize = 0;
2610         const PetscInt *meet    = NULL;
2611 
2612         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2613         if (cellPair[0] == cellPair[1]) continue;
2614         if (!found) {
2615           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2616           if (meetSize) {
2617             PetscInt f;
2618 
2619             for (f = 0; f < numFaceCases; ++f) {
2620               if (numFaceVertices[f] == meetSize) {
2621                 found = PETSC_TRUE;
2622                 break;
2623               }
2624             }
2625           }
2626           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2627         }
2628         if (found) {
2629           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2630           ++cellOffset;
2631         }
2632       }
2633     }
2634   }
2635   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2636   if (numVertices) *numVertices = numCells;
2637   if (offsets)   *offsets   = off;
2638   if (adjacency) *adjacency = adj;
2639   PetscFunctionReturn(0);
2640 }
2641 
2642 #if defined(PETSC_HAVE_CHACO)
2643 #if defined(PETSC_HAVE_UNISTD_H)
2644 #include <unistd.h>
2645 #endif
2646 /* Chaco does not have an include file */
2647 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2648                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2649                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2650                        int mesh_dims[3], double *goal, int global_method, int local_method,
2651                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2652 
2653 extern int FREE_GRAPH;
2654 
2655 #undef __FUNCT__
2656 #define __FUNCT__ "DMPlexPartition_Chaco"
2657 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2658 {
2659   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2660   MPI_Comm       comm;
2661   int            nvtxs          = numVertices; /* number of vertices in full graph */
2662   int           *vwgts          = NULL;   /* weights for all vertices */
2663   float         *ewgts          = NULL;   /* weights for all edges */
2664   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2665   char          *outassignname  = NULL;   /*  name of assignment output file */
2666   char          *outfilename    = NULL;   /* output file name */
2667   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2668   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2669   int            mesh_dims[3];            /* dimensions of mesh of processors */
2670   double        *goal          = NULL;    /* desired set sizes for each set */
2671   int            global_method = 1;       /* global partitioning algorithm */
2672   int            local_method  = 1;       /* local partitioning algorithm */
2673   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2674   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2675   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2676   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2677   long           seed          = 123636512; /* for random graph mutations */
2678   short int     *assignment;              /* Output partition */
2679   int            fd_stdout, fd_pipe[2];
2680   PetscInt      *points;
2681   PetscMPIInt    commSize;
2682   int            i, v, p;
2683   PetscErrorCode ierr;
2684 
2685   PetscFunctionBegin;
2686   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2687   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2688   if (!numVertices) {
2689     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2690     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2691     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2692     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2693     PetscFunctionReturn(0);
2694   }
2695   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2696   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2697 
2698   if (global_method == INERTIAL_METHOD) {
2699     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2700     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2701   }
2702   mesh_dims[0] = commSize;
2703   mesh_dims[1] = 1;
2704   mesh_dims[2] = 1;
2705   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2706   /* Chaco outputs to stdout. We redirect this to a buffer. */
2707   /* TODO: check error codes for UNIX calls */
2708 #if defined(PETSC_HAVE_UNISTD_H)
2709   {
2710     int piperet;
2711     piperet = pipe(fd_pipe);
2712     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2713     fd_stdout = dup(1);
2714     close(1);
2715     dup2(fd_pipe[1], 1);
2716   }
2717 #endif
2718   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2719                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2720                    vmax, ndims, eigtol, seed);
2721 #if defined(PETSC_HAVE_UNISTD_H)
2722   {
2723     char msgLog[10000];
2724     int  count;
2725 
2726     fflush(stdout);
2727     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2728     if (count < 0) count = 0;
2729     msgLog[count] = 0;
2730     close(1);
2731     dup2(fd_stdout, 1);
2732     close(fd_stdout);
2733     close(fd_pipe[0]);
2734     close(fd_pipe[1]);
2735     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2736   }
2737 #endif
2738   /* Convert to PetscSection+IS */
2739   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2740   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2741   for (v = 0; v < nvtxs; ++v) {
2742     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2743   }
2744   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2745   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2746   for (p = 0, i = 0; p < commSize; ++p) {
2747     for (v = 0; v < nvtxs; ++v) {
2748       if (assignment[v] == p) points[i++] = v;
2749     }
2750   }
2751   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2752   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2753   if (global_method == INERTIAL_METHOD) {
2754     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2755   }
2756   ierr = PetscFree(assignment);CHKERRQ(ierr);
2757   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2758   PetscFunctionReturn(0);
2759 }
2760 #endif
2761 
2762 #if defined(PETSC_HAVE_PARMETIS)
2763 #undef __FUNCT__
2764 #define __FUNCT__ "DMPlexPartition_ParMetis"
2765 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2766 {
2767   PetscFunctionBegin;
2768   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2769   PetscFunctionReturn(0);
2770 }
2771 #endif
2772 
2773 #undef __FUNCT__
2774 #define __FUNCT__ "DMPlexEnlargePartition"
2775 /* Expand the partition by BFS on the adjacency graph */
2776 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2777 {
2778   PetscHashI      h;
2779   const PetscInt *points;
2780   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2781   PetscInt        pStart, pEnd, part, q;
2782   PetscErrorCode  ierr;
2783 
2784   PetscFunctionBegin;
2785   PetscHashICreate(h);
2786   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2787   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2788   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2789   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2790   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2791   for (part = pStart; part < pEnd; ++part) {
2792     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2793 
2794     PetscHashIClear(h);
2795     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2796     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2797     /* Add all existing points to h */
2798     for (p = 0; p < numPoints; ++p) {
2799       const PetscInt point = points[off+p];
2800       PetscHashIAdd(h, point, 1);
2801     }
2802     PetscHashISize(h, nP);
2803     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2804     /* Add all points in next BFS level */
2805     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2806     for (p = 0; p < numPoints; ++p) {
2807       const PetscInt point = points[off+p];
2808       PetscInt       s     = start[point], e = start[point+1], a;
2809 
2810       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2811     }
2812     PetscHashISize(h, numNewPoints);
2813     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2814     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2815     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2816     totPoints += numNewPoints;
2817   }
2818   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2819   PetscHashIDestroy(h);
2820   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2821   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2822   for (part = pStart, q = 0; part < pEnd; ++part) {
2823     PetscInt numPoints, p;
2824 
2825     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2826     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2827     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2828   }
2829   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2830   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2831   PetscFunctionReturn(0);
2832 }
2833 
2834 #undef __FUNCT__
2835 #define __FUNCT__ "DMPlexCreatePartition"
2836 /*
2837   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2838 
2839   Collective on DM
2840 
2841   Input Parameters:
2842   + dm - The DM
2843   . height - The height for points in the partition
2844   - enlarge - Expand each partition with neighbors
2845 
2846   Output Parameters:
2847   + partSection - The PetscSection giving the division of points by partition
2848   . partition - The list of points by partition
2849   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2850   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2851 
2852   Level: developer
2853 
2854 .seealso DMPlexDistribute()
2855 */
2856 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2857 {
2858   PetscMPIInt    size;
2859   PetscErrorCode ierr;
2860 
2861   PetscFunctionBegin;
2862   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2863 
2864   *origPartSection = NULL;
2865   *origPartition   = NULL;
2866   if (size == 1) {
2867     PetscInt *points;
2868     PetscInt  cStart, cEnd, c;
2869 
2870     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2871     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2872     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2873     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2874     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2875     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2876     for (c = cStart; c < cEnd; ++c) points[c] = c;
2877     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2878     PetscFunctionReturn(0);
2879   }
2880   if (height == 0) {
2881     PetscInt  numVertices;
2882     PetscInt *start     = NULL;
2883     PetscInt *adjacency = NULL;
2884 
2885     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2886     if (1) {
2887 #if defined(PETSC_HAVE_CHACO)
2888       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2889 #endif
2890     } else {
2891 #if defined(PETSC_HAVE_PARMETIS)
2892       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2893 #endif
2894     }
2895     if (enlarge) {
2896       *origPartSection = *partSection;
2897       *origPartition   = *partition;
2898 
2899       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2900     }
2901     ierr = PetscFree(start);CHKERRQ(ierr);
2902     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2903 # if 0
2904   } else if (height == 1) {
2905     /* Build the dual graph for faces and partition the hypergraph */
2906     PetscInt numEdges;
2907 
2908     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2909     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2910     destroyCSR(numEdges, start, adjacency);
2911 #endif
2912   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2913   PetscFunctionReturn(0);
2914 }
2915 
2916 #undef __FUNCT__
2917 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2918 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2919 {
2920   /* const PetscInt  height = 0; */
2921   const PetscInt *partArray;
2922   PetscInt       *allPoints, *partPoints = NULL;
2923   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2924   PetscErrorCode  ierr;
2925 
2926   PetscFunctionBegin;
2927   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2928   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2929   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2930   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2931   for (rank = rStart; rank < rEnd; ++rank) {
2932     PetscInt partSize = 0;
2933     PetscInt numPoints, offset, p;
2934 
2935     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2936     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2937     for (p = 0; p < numPoints; ++p) {
2938       PetscInt  point   = partArray[offset+p], closureSize, c;
2939       PetscInt *closure = NULL;
2940 
2941       /* TODO Include support for height > 0 case */
2942       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2943       /* Merge into existing points */
2944       if (partSize+closureSize > maxPartSize) {
2945         PetscInt *tmpPoints;
2946 
2947         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2948         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2949         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2950         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2951 
2952         partPoints = tmpPoints;
2953       }
2954       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2955       partSize += closureSize;
2956 
2957       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2958       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2959     }
2960     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2961   }
2962   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2963   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2964   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2965 
2966   for (rank = rStart; rank < rEnd; ++rank) {
2967     PetscInt partSize = 0, newOffset;
2968     PetscInt numPoints, offset, p;
2969 
2970     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2971     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2972     for (p = 0; p < numPoints; ++p) {
2973       PetscInt  point   = partArray[offset+p], closureSize, c;
2974       PetscInt *closure = NULL;
2975 
2976       /* TODO Include support for height > 0 case */
2977       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2978       /* Merge into existing points */
2979       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2980       partSize += closureSize;
2981 
2982       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2983       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2984     }
2985     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
2986     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2987   }
2988   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2989   ierr = PetscFree(partPoints);CHKERRQ(ierr);
2990   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2991   PetscFunctionReturn(0);
2992 }
2993 
2994 #undef __FUNCT__
2995 #define __FUNCT__ "DMPlexDistributeField"
2996 /*
2997   Input Parameters:
2998 . originalSection
2999 , originalVec
3000 
3001   Output Parameters:
3002 . newSection
3003 . newVec
3004 */
3005 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3006 {
3007   PetscSF        fieldSF;
3008   PetscInt      *remoteOffsets, fieldSize;
3009   PetscScalar   *originalValues, *newValues;
3010   PetscErrorCode ierr;
3011 
3012   PetscFunctionBegin;
3013   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3014 
3015   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3016   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3017   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3018 
3019   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3020   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3021   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3022   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3023   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3024   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3025   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3026   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3027   PetscFunctionReturn(0);
3028 }
3029 
3030 #undef __FUNCT__
3031 #define __FUNCT__ "DMPlexDistribute"
3032 /*@C
3033   DMPlexDistribute - Distributes the mesh and any associated sections.
3034 
3035   Not Collective
3036 
3037   Input Parameter:
3038 + dm  - The original DMPlex object
3039 . partitioner - The partitioning package, or NULL for the default
3040 - overlap - The overlap of partitions, 0 is the default
3041 
3042   Output Parameter:
3043 . parallelMesh - The distributed DMPlex object, or NULL
3044 
3045   Note: If the mesh was not distributed, the return value is NULL
3046 
3047   Level: intermediate
3048 
3049 .keywords: mesh, elements
3050 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3051 @*/
3052 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3053 {
3054   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3055   MPI_Comm               comm;
3056   const PetscInt         height = 0;
3057   PetscInt               dim, numRemoteRanks;
3058   IS                     origCellPart,        cellPart,        part;
3059   PetscSection           origCellPartSection, cellPartSection, partSection;
3060   PetscSFNode           *remoteRanks;
3061   PetscSF                partSF, pointSF, coneSF;
3062   ISLocalToGlobalMapping renumbering;
3063   PetscSection           originalConeSection, newConeSection;
3064   PetscInt              *remoteOffsets;
3065   PetscInt              *cones, *newCones, newConesSize;
3066   PetscBool              flg;
3067   PetscMPIInt            rank, numProcs, p;
3068   PetscErrorCode         ierr;
3069 
3070   PetscFunctionBegin;
3071   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3072   PetscValidPointer(dmParallel,4);
3073 
3074   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3075   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3076   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3077   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3078 
3079   *dmParallel = NULL;
3080   if (numProcs == 1) PetscFunctionReturn(0);
3081 
3082   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3083   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3084   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3085   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3086   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3087   if (!rank) numRemoteRanks = numProcs;
3088   else       numRemoteRanks = 0;
3089   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3090   for (p = 0; p < numRemoteRanks; ++p) {
3091     remoteRanks[p].rank  = p;
3092     remoteRanks[p].index = 0;
3093   }
3094   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3095   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3096   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3097   if (flg) {
3098     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3099     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3100     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3101     if (origCellPart) {
3102       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3103       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3104       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3105     }
3106     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3107   }
3108   /* Close the partition over the mesh */
3109   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3110   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3111   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3112   /* Create new mesh */
3113   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3114   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3115   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3116   pmesh = (DM_Plex*) (*dmParallel)->data;
3117   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3118   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3119   if (flg) {
3120     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3121     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3122     ierr = ISView(part, NULL);CHKERRQ(ierr);
3123     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3124     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3125     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3126   }
3127   /* Distribute cone section */
3128   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3129   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3130   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3131   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3132   {
3133     PetscInt pStart, pEnd, p;
3134 
3135     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3136     for (p = pStart; p < pEnd; ++p) {
3137       PetscInt coneSize;
3138       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3139       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3140     }
3141   }
3142   /* Communicate and renumber cones */
3143   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3144   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3145   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3146   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3147   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3148   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3149   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3150   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3151   if (flg) {
3152     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3153     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3154     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3155     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3156     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3157   }
3158   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3159   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3160   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3161   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3162   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3163   /* Create supports and stratify sieve */
3164   {
3165     PetscInt pStart, pEnd;
3166 
3167     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3168     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3169   }
3170   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3171   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3172   /* Distribute Coordinates */
3173   {
3174     PetscSection originalCoordSection, newCoordSection;
3175     Vec          originalCoordinates, newCoordinates;
3176     const char  *name;
3177 
3178     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3179     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3180     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3181     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3182     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3183     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3184 
3185     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3186     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3187     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3188   }
3189   /* Distribute labels */
3190   {
3191     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3192     PetscInt numLabels = 0, l;
3193 
3194     /* Bcast number of labels */
3195     while (next) {
3196       ++numLabels; next = next->next;
3197     }
3198     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3199     next = mesh->labels;
3200     for (l = 0; l < numLabels; ++l) {
3201       DMLabel         newLabel;
3202       const PetscInt *partArray;
3203       char           *name;
3204       PetscInt       *stratumSizes = NULL, *points = NULL;
3205       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3206       PetscInt        nameSize, s, p;
3207       PetscBool       isdepth;
3208       size_t          len = 0;
3209 
3210       /* Bcast name (could filter for no points) */
3211       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3212       nameSize = len;
3213       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3214       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3215       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3216       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3217       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3218       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3219       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3220       newLabel->name = name;
3221       /* Bcast numStrata (could filter for no points in stratum) */
3222       if (!rank) newLabel->numStrata = next->numStrata;
3223       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3224       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3225                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3226                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3227       /* Bcast stratumValues (could filter for no points in stratum) */
3228       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3229       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3230       /* Find size on each process and Scatter */
3231       if (!rank) {
3232         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3233         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3234         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3235         for (s = 0; s < next->numStrata; ++s) {
3236           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3237             const PetscInt point = next->points[p];
3238             PetscInt       proc;
3239 
3240             for (proc = 0; proc < numProcs; ++proc) {
3241               PetscInt dof, off, pPart;
3242 
3243               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3244               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3245               for (pPart = off; pPart < off+dof; ++pPart) {
3246                 if (partArray[pPart] == point) {
3247                   ++stratumSizes[proc*next->numStrata+s];
3248                   break;
3249                 }
3250               }
3251             }
3252           }
3253         }
3254         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3255       }
3256       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3257       /* Calculate stratumOffsets */
3258       newLabel->stratumOffsets[0] = 0;
3259       for (s = 0; s < newLabel->numStrata; ++s) {
3260         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3261       }
3262       /* Pack points and Scatter */
3263       if (!rank) {
3264         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3265         displs[0] = 0;
3266         for (p = 0; p < numProcs; ++p) {
3267           sendcnts[p] = 0;
3268           for (s = 0; s < next->numStrata; ++s) {
3269             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3270           }
3271           offsets[p]  = displs[p];
3272           displs[p+1] = displs[p] + sendcnts[p];
3273         }
3274         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);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                   points[offsets[proc]++] = point;
3288                   break;
3289                 }
3290               }
3291             }
3292           }
3293         }
3294       }
3295       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3296       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3297       ierr = PetscFree(points);CHKERRQ(ierr);
3298       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3299       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3300       /* Renumber points */
3301       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3302       /* Sort points */
3303       for (s = 0; s < newLabel->numStrata; ++s) {
3304         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3305       }
3306       /* Insert into list */
3307       if (newNext) newNext->next = newLabel;
3308       else pmesh->labels = newLabel;
3309       newNext = newLabel;
3310       if (!rank) next = next->next;
3311     }
3312   }
3313   /* Cleanup Partition */
3314   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3315   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3316   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3317   ierr = ISDestroy(&part);CHKERRQ(ierr);
3318   /* Create point SF for parallel mesh */
3319   {
3320     const PetscInt *leaves;
3321     PetscSFNode    *remotePoints, *rowners, *lowners;
3322     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3323     PetscInt        pStart, pEnd;
3324 
3325     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3326     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3327     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3328     for (p=0; p<numRoots; p++) {
3329       rowners[p].rank  = -1;
3330       rowners[p].index = -1;
3331     }
3332     if (origCellPart) {
3333       /* Make sure cells in the original partition are not assigned to other procs */
3334       const PetscInt *origCells;
3335 
3336       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3337       for (p = 0; p < numProcs; ++p) {
3338         PetscInt dof, off, d;
3339 
3340         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3341         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3342         for (d = off; d < off+dof; ++d) {
3343           rowners[origCells[d]].rank = p;
3344         }
3345       }
3346       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3347     }
3348     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3349     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3350 
3351     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3352     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3353     for (p = 0; p < numLeaves; ++p) {
3354       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3355         lowners[p].rank  = rank;
3356         lowners[p].index = leaves ? leaves[p] : p;
3357       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3358         lowners[p].rank  = -2;
3359         lowners[p].index = -2;
3360       }
3361     }
3362     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3363       rowners[p].rank  = -3;
3364       rowners[p].index = -3;
3365     }
3366     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3367     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3368     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3369     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3370     for (p = 0; p < numLeaves; ++p) {
3371       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3372       if (lowners[p].rank != rank) ++numGhostPoints;
3373     }
3374     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3375     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3376     for (p = 0, gp = 0; p < numLeaves; ++p) {
3377       if (lowners[p].rank != rank) {
3378         ghostPoints[gp]        = leaves ? leaves[p] : p;
3379         remotePoints[gp].rank  = lowners[p].rank;
3380         remotePoints[gp].index = lowners[p].index;
3381         ++gp;
3382       }
3383     }
3384     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3385     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3386     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3387   }
3388   /* Cleanup */
3389   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3390   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3391   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3392   PetscFunctionReturn(0);
3393 }
3394 
3395 #undef __FUNCT__
3396 #define __FUNCT__ "DMPlexRenumber_Private"
3397 /*
3398   Reasons to renumber:
3399 
3400   1) Permute points, e.g. bandwidth reduction (Renumber)
3401 
3402     a) Must not mix strata
3403 
3404   2) Shift numbers for point insertion (Shift)
3405 
3406     a) Want operation brken into parts so that insertion can be interleaved
3407 
3408   renumbering - An IS which provides the new numbering
3409 */
3410 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3411 {
3412   PetscFunctionBegin;
3413   PetscFunctionReturn(0);
3414 }
3415 
3416 #undef __FUNCT__
3417 #define __FUNCT__ "DMPlexShiftPoint_Private"
3418 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3419 {
3420   if (depth < 0) return p;
3421   /* Cells    */ if (p < depthEnd[depth])   return p;
3422   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3423   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3424   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3425 }
3426 
3427 #undef __FUNCT__
3428 #define __FUNCT__ "DMPlexShiftSizes_Private"
3429 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3430 {
3431   PetscInt      *depthEnd;
3432   PetscInt       depth = 0, d, pStart, pEnd, p;
3433   PetscErrorCode ierr;
3434 
3435   PetscFunctionBegin;
3436   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3437   if (depth < 0) PetscFunctionReturn(0);
3438   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3439   /* Step 1: Expand chart */
3440   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3441   for (d = 0; d <= depth; ++d) {
3442     pEnd += depthShift[d];
3443     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3444   }
3445   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3446   /* Step 2: Set cone and support sizes */
3447   for (d = 0; d <= depth; ++d) {
3448     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3449     for (p = pStart; p < pEnd; ++p) {
3450       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3451       PetscInt size;
3452 
3453       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3454       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3455       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3456       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3457     }
3458   }
3459   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3460   PetscFunctionReturn(0);
3461 }
3462 
3463 #undef __FUNCT__
3464 #define __FUNCT__ "DMPlexShiftPoints_Private"
3465 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3466 {
3467   PetscInt      *depthEnd, *newpoints;
3468   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3469   PetscErrorCode ierr;
3470 
3471   PetscFunctionBegin;
3472   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3473   if (depth < 0) PetscFunctionReturn(0);
3474   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3475   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3476   for (d = 0; d <= depth; ++d) {
3477     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3478   }
3479   /* Step 5: Set cones and supports */
3480   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3481   for (p = pStart; p < pEnd; ++p) {
3482     const PetscInt *points = NULL, *orientations = NULL;
3483     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3484 
3485     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3486     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3487     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3488     for (i = 0; i < size; ++i) {
3489       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3490     }
3491     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3492     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3493     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3494     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3495     for (i = 0; i < size; ++i) {
3496       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3497     }
3498     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3499   }
3500   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3501   PetscFunctionReturn(0);
3502 }
3503 
3504 #undef __FUNCT__
3505 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3506 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3507 {
3508   PetscSection   coordSection, newCoordSection;
3509   Vec            coordinates, newCoordinates;
3510   PetscScalar   *coords, *newCoords;
3511   PetscInt      *depthEnd, coordSize;
3512   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3513   PetscErrorCode ierr;
3514 
3515   PetscFunctionBegin;
3516   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3517   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3518   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3519   for (d = 0; d <= depth; ++d) {
3520     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3521   }
3522   /* Step 8: Convert coordinates */
3523   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3524   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3525   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3526   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);CHKERRQ(ierr);
3527   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3528   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3529   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3530   for (v = vStartNew; v < vEndNew; ++v) {
3531     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3532     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3533   }
3534   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3535   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3536   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3537   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &newCoordinates);CHKERRQ(ierr);
3538   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3539   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3540   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3541   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3542   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3543   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3544   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3545   for (v = vStart; v < vEnd; ++v) {
3546     PetscInt dof, off, noff, d;
3547 
3548     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3549     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3550     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3551     for (d = 0; d < dof; ++d) {
3552       newCoords[noff+d] = coords[off+d];
3553     }
3554   }
3555   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3556   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3557   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3558   ierr = PetscSectionDestroy(&newCoordSection);CHKERRQ(ierr);
3559   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3560   PetscFunctionReturn(0);
3561 }
3562 
3563 #undef __FUNCT__
3564 #define __FUNCT__ "DMPlexShiftSF_Private"
3565 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3566 {
3567   PetscInt          *depthEnd;
3568   PetscInt           depth = 0, d;
3569   PetscSF            sfPoint, sfPointNew;
3570   const PetscSFNode *remotePoints;
3571   PetscSFNode       *gremotePoints;
3572   const PetscInt    *localPoints;
3573   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3574   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3575   PetscMPIInt        numProcs;
3576   PetscErrorCode     ierr;
3577 
3578   PetscFunctionBegin;
3579   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3580   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3581   for (d = 0; d <= depth; ++d) {
3582     totShift += depthShift[d];
3583     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3584   }
3585   /* Step 9: Convert pointSF */
3586   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
3587   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3588   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3589   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3590   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3591   if (numRoots >= 0) {
3592     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3593     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3594     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3595     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3596     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3597     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3598     for (l = 0; l < numLeaves; ++l) {
3599       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3600       gremotePoints[l].rank  = remotePoints[l].rank;
3601       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3602     }
3603     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3604     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3605   }
3606   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3607   PetscFunctionReturn(0);
3608 }
3609 
3610 #undef __FUNCT__
3611 #define __FUNCT__ "DMPlexShiftLabels_Private"
3612 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3613 {
3614   PetscSF            sfPoint;
3615   DMLabel            vtkLabel, ghostLabel;
3616   PetscInt          *depthEnd;
3617   const PetscSFNode *leafRemote;
3618   const PetscInt    *leafLocal;
3619   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3620   PetscMPIInt        rank;
3621   PetscErrorCode     ierr;
3622 
3623   PetscFunctionBegin;
3624   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3625   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3626   for (d = 0; d <= depth; ++d) {
3627     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3628   }
3629   /* Step 10: Convert labels */
3630   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3631   for (l = 0; l < numLabels; ++l) {
3632     DMLabel         label, newlabel;
3633     const char     *lname;
3634     PetscBool       isDepth;
3635     IS              valueIS;
3636     const PetscInt *values;
3637     PetscInt        numValues, val;
3638 
3639     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3640     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3641     if (isDepth) continue;
3642     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3643     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3644     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3645     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3646     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3647     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3648     for (val = 0; val < numValues; ++val) {
3649       IS              pointIS;
3650       const PetscInt *points;
3651       PetscInt        numPoints, p;
3652 
3653       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3654       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3655       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3656       for (p = 0; p < numPoints; ++p) {
3657         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3658 
3659         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3660       }
3661       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3662       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3663     }
3664     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3665     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3666   }
3667   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3668   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3669   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
3670   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3671   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3672   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3673   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3674   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3675   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3676   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3677   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3678     for (; c < leafLocal[l] && c < cEnd; ++c) {
3679       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3680     }
3681     if (leafLocal[l] >= cEnd) break;
3682     if (leafRemote[l].rank == rank) {
3683       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3684     } else {
3685       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3686     }
3687   }
3688   for (; c < cEnd; ++c) {
3689     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3690   }
3691   if (0) {
3692     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3693     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3694     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3695   }
3696   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3697   for (f = fStart; f < fEnd; ++f) {
3698     PetscInt numCells;
3699 
3700     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3701     if (numCells < 2) {
3702       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3703     } else {
3704       const PetscInt *cells = NULL;
3705       PetscInt        vA, vB;
3706 
3707       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3708       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3709       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3710       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3711     }
3712   }
3713   if (0) {
3714     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3715     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3716     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3717   }
3718   PetscFunctionReturn(0);
3719 }
3720 
3721 #undef __FUNCT__
3722 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3723 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3724 {
3725   DMLabel         label;
3726   IS              valueIS;
3727   const PetscInt *values;
3728   PetscInt       *depthShift;
3729   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3730   PetscErrorCode  ierr;
3731 
3732   PetscFunctionBegin;
3733   /* Count ghost cells */
3734   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3735   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3736   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3737   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3738 
3739   *numGhostCells = 0;
3740   for (fs = 0; fs < numFS; ++fs) {
3741     PetscInt numBdFaces;
3742 
3743     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3744 
3745     *numGhostCells += numBdFaces;
3746   }
3747   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3748   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3749   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3750   if (depth >= 0) depthShift[depth] = *numGhostCells;
3751   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3752   /* Step 3: Set cone/support sizes for new points */
3753   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3754   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3755     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3756   }
3757   for (fs = 0; fs < numFS; ++fs) {
3758     IS              faceIS;
3759     const PetscInt *faces;
3760     PetscInt        numFaces, f;
3761 
3762     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3763     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3764     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3765     for (f = 0; f < numFaces; ++f) {
3766       PetscInt size;
3767 
3768       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3769       if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3770       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3771     }
3772     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3773     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3774   }
3775   /* Step 4: Setup ghosted DM */
3776   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3777   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3778   /* Step 6: Set cones and supports for new points */
3779   ghostCell = cEnd;
3780   for (fs = 0; fs < numFS; ++fs) {
3781     IS              faceIS;
3782     const PetscInt *faces;
3783     PetscInt        numFaces, f;
3784 
3785     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3786     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3787     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3788     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3789       PetscInt newFace = faces[f] + *numGhostCells;
3790 
3791       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3792       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3793     }
3794     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3795     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3796   }
3797   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3798   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3799   /* Step 7: Stratify */
3800   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3801   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3802   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3803   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3804   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3805   PetscFunctionReturn(0);
3806 }
3807 
3808 #undef __FUNCT__
3809 #define __FUNCT__ "DMPlexConstructGhostCells"
3810 /*@C
3811   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3812 
3813   Collective on dm
3814 
3815   Input Parameters:
3816 + dm - The original DM
3817 - labelName - The label specifying the boundary faces (this could be auto-generated)
3818 
3819   Output Parameters:
3820 + numGhostCells - The number of ghost cells added to the DM
3821 - dmGhosted - The new DM
3822 
3823   Level: developer
3824 
3825 .seealso: DMCreate()
3826 */
3827 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3828 {
3829   DM             gdm;
3830   PetscInt       dim;
3831   PetscErrorCode ierr;
3832 
3833   PetscFunctionBegin;
3834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3835   PetscValidPointer(numGhostCells, 3);
3836   PetscValidPointer(dmGhosted, 4);
3837   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &gdm);CHKERRQ(ierr);
3838   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3839   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3840   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3841   switch (dim) {
3842   case 2:
3843     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3844     break;
3845   default:
3846     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3847   }
3848   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3849   *dmGhosted = gdm;
3850   PetscFunctionReturn(0);
3851 }
3852 
3853 #undef __FUNCT__
3854 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3855 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3856 {
3857   MPI_Comm        comm;
3858   IS              valueIS, *pointIS;
3859   const PetscInt *values, **splitPoints;
3860   PetscSection    coordSection;
3861   Vec             coordinates;
3862   PetscScalar    *coords;
3863   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3864   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3865   PetscErrorCode  ierr;
3866 
3867   PetscFunctionBegin;
3868   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3869   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3870   /* Count split points and add cohesive cells */
3871   if (label) {
3872     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3873     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3874     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3875   }
3876   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3877   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3878   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3879   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3880   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3881   for (d = 0; d <= depth; ++d) {
3882     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3883     numSplitPoints[d] = 0;
3884     splitPoints[d]    = NULL;
3885     pointIS[d]        = NULL;
3886   }
3887   for (sp = 0; sp < numSP; ++sp) {
3888     const PetscInt dep = values[sp];
3889 
3890     if ((dep < 0) || (dep > depth)) continue;
3891     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3892     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3893     if (pointIS[dep]) {
3894       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3895       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3896     }
3897   }
3898   if (depth >= 0) {
3899     /* Calculate number of additional points */
3900     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3901     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3902     /* Calculate hybrid bound for each dimension */
3903     pMaxNew[0] += depthShift[depth];
3904     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3905     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3906 
3907     /* Calculate point offset for each dimension */
3908     depthOffset[depth] = 0;
3909     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3910     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3911     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3912   }
3913   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3914   /* Step 3: Set cone/support sizes for new points */
3915   for (dep = 0; dep <= depth; ++dep) {
3916     for (p = 0; p < numSplitPoints[dep]; ++p) {
3917       const PetscInt  oldp   = splitPoints[dep][p];
3918       const PetscInt  newp   = depthOffset[dep] + oldp;
3919       const PetscInt  splitp = pMaxNew[dep] + p;
3920       const PetscInt *support;
3921       PetscInt        coneSize, supportSize, q, e;
3922 
3923       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3924       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3925       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3926       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3927       if (dep == depth-1) {
3928         const PetscInt ccell = pMaxNew[depth] + p;
3929         /* Add cohesive cells, they are prisms */
3930         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3931       } else if (dep == 0) {
3932         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3933 
3934         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3935         /* Split old vertex: Edges in old split faces and new cohesive edge */
3936         for (e = 0, q = 0; e < supportSize; ++e) {
3937           PetscInt val;
3938 
3939           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3940           if ((val == 1) || (val == (shift + 1))) ++q;
3941         }
3942         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3943         /* Split new vertex: Edges in new split faces and new cohesive edge */
3944         for (e = 0, q = 0; e < supportSize; ++e) {
3945           PetscInt val;
3946 
3947           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3948           if ((val == 1) || (val == -(shift + 1))) ++q;
3949         }
3950         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
3951         /* Add cohesive edges */
3952         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
3953         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3954       } else if (dep == dim-2) {
3955         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3956         /* Split old edge: Faces in positive side cells and old split faces */
3957         for (e = 0, q = 0; e < supportSize; ++e) {
3958           PetscInt val;
3959 
3960           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3961           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
3962         }
3963         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
3964         /* Split new edge: Faces in negative side cells and new split faces */
3965         for (e = 0, q = 0; e < supportSize; ++e) {
3966           PetscInt val;
3967 
3968           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3969           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
3970         }
3971         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
3972       }
3973     }
3974   }
3975   /* Step 4: Setup split DM */
3976   ierr = DMSetUp(sdm);CHKERRQ(ierr);
3977   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3978   /* Step 6: Set cones and supports for new points */
3979   for (dep = 0; dep <= depth; ++dep) {
3980     for (p = 0; p < numSplitPoints[dep]; ++p) {
3981       const PetscInt  oldp   = splitPoints[dep][p];
3982       const PetscInt  newp   = depthOffset[dep] + oldp;
3983       const PetscInt  splitp = pMaxNew[dep] + p;
3984       const PetscInt *cone, *support, *ornt;
3985       PetscInt        coneSize, supportSize, q, v, e, s;
3986 
3987       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3988       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
3989       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
3990       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3991       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3992       if (dep == depth-1) {
3993         const PetscInt  ccell = pMaxNew[depth] + p;
3994         const PetscInt *supportF;
3995 
3996         /* Split face:       copy in old face to new face to start */
3997         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
3998         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
3999         /* Split old face:   old vertices/edges in cone so no change */
4000         /* Split new face:   new vertices/edges in cone */
4001         for (q = 0; q < coneSize; ++q) {
4002           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4003 
4004           coneNew[2+q] = pMaxNew[dim-2] + v;
4005         }
4006         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4007         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4008         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4009         coneNew[0] = newp;
4010         coneNew[1] = splitp;
4011         for (q = 0; q < coneSize; ++q) {
4012           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4013         }
4014         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4015 
4016 
4017         for (s = 0; s < supportSize; ++s) {
4018           PetscInt val;
4019 
4020           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4021           if (val < 0) {
4022             /* Split old face:   Replace negative side cell with cohesive cell */
4023             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4024           } else {
4025             /* Split new face:   Replace positive side cell with cohesive cell */
4026             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4027           }
4028         }
4029       } else if (dep == 0) {
4030         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4031 
4032         /* Split old vertex: Edges in old split faces and new cohesive edge */
4033         for (e = 0, q = 0; e < supportSize; ++e) {
4034           PetscInt val;
4035 
4036           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4037           if ((val == 1) || (val == (shift + 1))) {
4038             supportNew[q++] = depthOffset[1] + support[e];
4039           }
4040         }
4041         supportNew[q] = cedge;
4042 
4043         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4044         /* Split new vertex: Edges in new split faces and new cohesive edge */
4045         for (e = 0, q = 0; e < supportSize; ++e) {
4046           PetscInt val, edge;
4047 
4048           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4049           if (val == 1) {
4050             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4051             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4052             supportNew[q++] = pMaxNew[1] + edge;
4053           } else if (val == -(shift + 1)) {
4054             supportNew[q++] = depthOffset[1] + support[e];
4055           }
4056         }
4057         supportNew[q] = cedge;
4058         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4059         /* Cohesive edge:    Old and new split vertex, punting on support */
4060         coneNew[0] = newp;
4061         coneNew[1] = splitp;
4062         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4063       } else if (dep == dim-2) {
4064         /* Split old edge:   old vertices in cone so no change */
4065         /* Split new edge:   new vertices in cone */
4066         for (q = 0; q < coneSize; ++q) {
4067           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4068 
4069           coneNew[q] = pMaxNew[dim-3] + v;
4070         }
4071         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4072         /* Split old edge: Faces in positive side cells and old split faces */
4073         for (e = 0, q = 0; e < supportSize; ++e) {
4074           PetscInt val;
4075 
4076           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4077           if ((val == dim-1) || (val == (shift + dim-1))) {
4078             supportNew[q++] = depthOffset[dim-1] + support[e];
4079           }
4080         }
4081         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4082         /* Split new edge: Faces in negative side cells and new split faces */
4083         for (e = 0, q = 0; e < supportSize; ++e) {
4084           PetscInt val, face;
4085 
4086           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4087           if (val == dim-1) {
4088             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4089             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4090             supportNew[q++] = pMaxNew[dim-1] + face;
4091           } else if (val == -(shift + dim-1)) {
4092             supportNew[q++] = depthOffset[dim-1] + support[e];
4093           }
4094         }
4095         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4096       }
4097     }
4098   }
4099   /* Step 6b: Replace split points in negative side cones */
4100   for (sp = 0; sp < numSP; ++sp) {
4101     PetscInt        dep = values[sp];
4102     IS              pIS;
4103     PetscInt        numPoints;
4104     const PetscInt *points;
4105 
4106     if (dep >= 0) continue;
4107     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4108     if (!pIS) continue;
4109     dep  = -dep - shift;
4110     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4111     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4112     for (p = 0; p < numPoints; ++p) {
4113       const PetscInt  oldp = points[p];
4114       const PetscInt  newp = depthOffset[dep] + oldp;
4115       const PetscInt *cone;
4116       PetscInt        coneSize, c;
4117       PetscBool       replaced = PETSC_FALSE;
4118 
4119       /* Negative edge: replace split vertex */
4120       /* Negative cell: replace split face */
4121       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4122       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4123       for (c = 0; c < coneSize; ++c) {
4124         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4125         PetscInt       csplitp, cp, val;
4126 
4127         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4128         if (val == dep-1) {
4129           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4130           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4131           csplitp  = pMaxNew[dep-1] + cp;
4132           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4133           replaced = PETSC_TRUE;
4134         }
4135       }
4136       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4137     }
4138     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4139     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4140   }
4141   /* Step 7: Stratify */
4142   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4143   /* Step 8: Coordinates */
4144   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4145   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4146   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4147   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4148   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4149     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4150     const PetscInt splitp = pMaxNew[0] + v;
4151     PetscInt       dof, off, soff, d;
4152 
4153     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4154     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4155     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4156     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4157   }
4158   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4159   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4160   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4161   /* Step 10: Labels */
4162   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4163   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4164   for (dep = 0; dep <= depth; ++dep) {
4165     for (p = 0; p < numSplitPoints[dep]; ++p) {
4166       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4167       const PetscInt splitp = pMaxNew[dep] + p;
4168       PetscInt       l;
4169 
4170       for (l = 0; l < numLabels; ++l) {
4171         DMLabel     mlabel;
4172         const char *lname;
4173         PetscInt    val;
4174 
4175         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4176         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4177         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4178         if (val >= 0) {
4179           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4180           if (dep == 0) {
4181             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4182             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4183           }
4184         }
4185       }
4186     }
4187   }
4188   for (sp = 0; sp < numSP; ++sp) {
4189     const PetscInt dep = values[sp];
4190 
4191     if ((dep < 0) || (dep > depth)) continue;
4192     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4193     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4194   }
4195   if (label) {
4196     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4197     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4198   }
4199   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4200   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4201   PetscFunctionReturn(0);
4202 }
4203 
4204 #undef __FUNCT__
4205 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4206 /*@C
4207   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4208 
4209   Collective on dm
4210 
4211   Input Parameters:
4212 + dm - The original DM
4213 - labelName - The label specifying the boundary faces (this could be auto-generated)
4214 
4215   Output Parameters:
4216 - dmSplit - The new DM
4217 
4218   Level: developer
4219 
4220 .seealso: DMCreate()
4221 */
4222 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4223 {
4224   DM             sdm;
4225   PetscInt       dim;
4226   PetscErrorCode ierr;
4227 
4228   PetscFunctionBegin;
4229   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4230   PetscValidPointer(dmSplit, 4);
4231   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &sdm);CHKERRQ(ierr);
4232   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4233   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4234   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4235   switch (dim) {
4236   case 2:
4237   case 3:
4238     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4239     break;
4240   default:
4241     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4242   }
4243   *dmSplit = sdm;
4244   PetscFunctionReturn(0);
4245 }
4246 
4247 #undef __FUNCT__
4248 #define __FUNCT__ "DMLabelCohesiveComplete"
4249 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4250 {
4251   IS              dimIS;
4252   const PetscInt *points;
4253   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4254   PetscErrorCode  ierr;
4255 
4256   PetscFunctionBegin;
4257   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4258   /* Cell orientation for face gives the side of the fault */
4259   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4260   if (!dimIS) PetscFunctionReturn(0);
4261   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4262   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4263   for (p = 0; p < numPoints; ++p) {
4264     const PetscInt *support;
4265     PetscInt        supportSize, s;
4266 
4267     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4268     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4269     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4270     for (s = 0; s < supportSize; ++s) {
4271       const PetscInt *cone, *ornt;
4272       PetscInt        coneSize, c;
4273       PetscBool       pos = PETSC_TRUE;
4274 
4275       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4276       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4277       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4278       for (c = 0; c < coneSize; ++c) {
4279         if (cone[c] == points[p]) {
4280           if (ornt[c] >= 0) {
4281             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4282           } else {
4283             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4284             pos  = PETSC_FALSE;
4285           }
4286           break;
4287         }
4288       }
4289       if (c == coneSize) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4290       /* Put faces touching the fault in the label */
4291       for (c = 0; c < coneSize; ++c) {
4292         const PetscInt point = cone[c];
4293 
4294         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4295         if (val == -1) {
4296           PetscInt *closure = NULL;
4297           PetscInt  closureSize, cl;
4298 
4299           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4300           for (cl = 0; cl < closureSize*2; cl += 2) {
4301             const PetscInt clp = closure[cl];
4302 
4303             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4304             if ((val >= 0) && (val < dim-1)) {
4305               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4306               break;
4307             }
4308           }
4309           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4310         }
4311       }
4312     }
4313   }
4314   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4315   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4316   /* Search for other cells/faces/edges connected to the fault by a vertex */
4317   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4318   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4319   if (!dimIS) PetscFunctionReturn(0);
4320   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4321   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4322   for (p = 0; p < numPoints; ++p) {
4323     PetscInt *star = NULL;
4324     PetscInt  starSize, s;
4325     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4326 
4327     /* First mark cells connected to the fault */
4328     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4329     while (again) {
4330       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4331       again = 0;
4332       for (s = 0; s < starSize*2; s += 2) {
4333         const PetscInt  point = star[s];
4334         const PetscInt *cone;
4335         PetscInt        coneSize, c;
4336 
4337         if ((point < cStart) || (point >= cEnd)) continue;
4338         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4339         if (val != -1) continue;
4340         again = 2;
4341         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4342         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4343         for (c = 0; c < coneSize; ++c) {
4344           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4345           if (val != -1) {
4346             if (abs(val) < shift) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4347             if (val > 0) {
4348               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4349             } else {
4350               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4351             }
4352             again = 1;
4353             break;
4354           }
4355         }
4356       }
4357     }
4358     /* Classify the rest by cell membership */
4359     for (s = 0; s < starSize*2; s += 2) {
4360       const PetscInt point = star[s];
4361 
4362       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4363       if (val == -1) {
4364         PetscInt  *sstar = NULL;
4365         PetscInt   sstarSize, ss;
4366         PetscBool  marked = PETSC_FALSE;
4367 
4368         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4369         for (ss = 0; ss < sstarSize*2; ss += 2) {
4370           const PetscInt spoint = sstar[ss];
4371 
4372           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4373           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4374           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4375           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4376           if (val > 0) {
4377             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4378           } else {
4379             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4380           }
4381           marked = PETSC_TRUE;
4382           break;
4383         }
4384         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4385         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
4386       }
4387     }
4388     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4389   }
4390   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4391   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4392   PetscFunctionReturn(0);
4393 }
4394 
4395 #undef __FUNCT__
4396 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4397 /*
4398   This takes as input the common mesh generator output, a list of the vertices for each cell
4399 */
4400 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4401 {
4402   PetscInt      *cone, c, p;
4403   PetscErrorCode ierr;
4404 
4405   PetscFunctionBegin;
4406   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4407   for (c = 0; c < numCells; ++c) {
4408     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4409   }
4410   ierr = DMSetUp(dm);CHKERRQ(ierr);
4411   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4412   for (c = 0; c < numCells; ++c) {
4413     for (p = 0; p < numCorners; ++p) {
4414       cone[p] = cells[c*numCorners+p]+numCells;
4415     }
4416     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4417   }
4418   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4419   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4420   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4421   PetscFunctionReturn(0);
4422 }
4423 
4424 #undef __FUNCT__
4425 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4426 /*
4427   This takes as input the coordinates for each vertex
4428 */
4429 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4430 {
4431   PetscSection   coordSection;
4432   Vec            coordinates;
4433   PetscScalar   *coords;
4434   PetscInt       coordSize, v, d;
4435   PetscErrorCode ierr;
4436 
4437   PetscFunctionBegin;
4438   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4439   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4440   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4441   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4442   for (v = numCells; v < numCells+numVertices; ++v) {
4443     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4444     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4445   }
4446   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4447   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4448   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4449   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4450   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4451   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4452   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4453   for (v = 0; v < numVertices; ++v) {
4454     for (d = 0; d < spaceDim; ++d) {
4455       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4456     }
4457   }
4458   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4459   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4460   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4461   PetscFunctionReturn(0);
4462 }
4463 
4464 #undef __FUNCT__
4465 #define __FUNCT__ "DMPlexCreateFromCellList"
4466 /*
4467   This takes as input the common mesh generator output, a list of the vertices for each cell
4468 */
4469 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], PetscInt spaceDim, const double vertexCoords[], DM *dm)
4470 {
4471   PetscErrorCode ierr;
4472 
4473   PetscFunctionBegin;
4474   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4475   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4476   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4477   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4478   if (interpolate) {
4479     DM idm;
4480 
4481     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
4482     ierr = DMDestroy(dm);CHKERRQ(ierr);
4483     *dm  = idm;
4484   }
4485   ierr = DMPlexBuildCoordinates_Private(*dm, spaceDim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4486   PetscFunctionReturn(0);
4487 }
4488 
4489 #undef __FUNCT__
4490 #define __FUNCT__ "DMPlexCreateFromDAG"
4491 /*
4492   This takes as input the raw Hasse Diagram data
4493 */
4494 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
4495 {
4496   Vec            coordinates;
4497   PetscSection   coordSection;
4498   PetscScalar    *coords;
4499   PetscInt       coordSize, firstVertex = numPoints[depth], pStart = 0, pEnd = 0, p, v, dim, d, off;
4500   PetscErrorCode ierr;
4501 
4502   PetscFunctionBegin;
4503   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4504   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
4505   ierr = DMPlexSetChart(dm, pStart, pEnd);CHKERRQ(ierr);
4506   for (p = pStart; p < pEnd; ++p) {
4507     ierr = DMPlexSetConeSize(dm, p, coneSize[p-pStart]);CHKERRQ(ierr);
4508   }
4509   ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
4510   for (p = pStart, off = 0; p < pEnd; off += coneSize[p-pStart], ++p) {
4511     ierr = DMPlexSetCone(dm, p, &cones[off]);CHKERRQ(ierr);
4512     ierr = DMPlexSetConeOrientation(dm, p, &coneOrientations[off]);CHKERRQ(ierr);
4513   }
4514   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4515   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4516   /* Build coordinates */
4517   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4518   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4519   ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
4520   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numPoints[0]);CHKERRQ(ierr);
4521   for (v = firstVertex; v < firstVertex+numPoints[0]; ++v) {
4522     ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
4523   }
4524   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4525   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4526   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4527   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4528   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4529   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4530   for (v = 0; v < numPoints[0]; ++v) {
4531     PetscInt off;
4532 
4533     ierr = PetscSectionGetOffset(coordSection, v+firstVertex, &off);CHKERRQ(ierr);
4534     for (d = 0; d < dim; ++d) {
4535       coords[off+d] = vertexCoords[v*dim+d];
4536     }
4537   }
4538   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4539   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4540   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4541   PetscFunctionReturn(0);
4542 }
4543 
4544 #if defined(PETSC_HAVE_TRIANGLE)
4545 #include <triangle.h>
4546 
4547 #undef __FUNCT__
4548 #define __FUNCT__ "InitInput_Triangle"
4549 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4550 {
4551   PetscFunctionBegin;
4552   inputCtx->numberofpoints             = 0;
4553   inputCtx->numberofpointattributes    = 0;
4554   inputCtx->pointlist                  = NULL;
4555   inputCtx->pointattributelist         = NULL;
4556   inputCtx->pointmarkerlist            = NULL;
4557   inputCtx->numberofsegments           = 0;
4558   inputCtx->segmentlist                = NULL;
4559   inputCtx->segmentmarkerlist          = NULL;
4560   inputCtx->numberoftriangleattributes = 0;
4561   inputCtx->trianglelist               = NULL;
4562   inputCtx->numberofholes              = 0;
4563   inputCtx->holelist                   = NULL;
4564   inputCtx->numberofregions            = 0;
4565   inputCtx->regionlist                 = NULL;
4566   PetscFunctionReturn(0);
4567 }
4568 
4569 #undef __FUNCT__
4570 #define __FUNCT__ "InitOutput_Triangle"
4571 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4572 {
4573   PetscFunctionBegin;
4574   outputCtx->numberofpoints        = 0;
4575   outputCtx->pointlist             = NULL;
4576   outputCtx->pointattributelist    = NULL;
4577   outputCtx->pointmarkerlist       = NULL;
4578   outputCtx->numberoftriangles     = 0;
4579   outputCtx->trianglelist          = NULL;
4580   outputCtx->triangleattributelist = NULL;
4581   outputCtx->neighborlist          = NULL;
4582   outputCtx->segmentlist           = NULL;
4583   outputCtx->segmentmarkerlist     = NULL;
4584   outputCtx->numberofedges         = 0;
4585   outputCtx->edgelist              = NULL;
4586   outputCtx->edgemarkerlist        = NULL;
4587   PetscFunctionReturn(0);
4588 }
4589 
4590 #undef __FUNCT__
4591 #define __FUNCT__ "FiniOutput_Triangle"
4592 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4593 {
4594   PetscFunctionBegin;
4595   free(outputCtx->pointmarkerlist);
4596   free(outputCtx->edgelist);
4597   free(outputCtx->edgemarkerlist);
4598   free(outputCtx->trianglelist);
4599   free(outputCtx->neighborlist);
4600   PetscFunctionReturn(0);
4601 }
4602 
4603 #undef __FUNCT__
4604 #define __FUNCT__ "DMPlexGenerate_Triangle"
4605 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4606 {
4607   MPI_Comm             comm;
4608   PetscInt             dim              = 2;
4609   const PetscBool      createConvexHull = PETSC_FALSE;
4610   const PetscBool      constrained      = PETSC_FALSE;
4611   struct triangulateio in;
4612   struct triangulateio out;
4613   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4614   PetscMPIInt          rank;
4615   PetscErrorCode       ierr;
4616 
4617   PetscFunctionBegin;
4618   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4619   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4620   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4621   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4622   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4623 
4624   in.numberofpoints = vEnd - vStart;
4625   if (in.numberofpoints > 0) {
4626     PetscSection coordSection;
4627     Vec          coordinates;
4628     PetscScalar *array;
4629 
4630     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4631     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4632     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4633     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4634     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4635     for (v = vStart; v < vEnd; ++v) {
4636       const PetscInt idx = v - vStart;
4637       PetscInt       off, d;
4638 
4639       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4640       for (d = 0; d < dim; ++d) {
4641         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4642       }
4643       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4644     }
4645     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4646   }
4647   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4648   in.numberofsegments = eEnd - eStart;
4649   if (in.numberofsegments > 0) {
4650     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4651     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4652     for (e = eStart; e < eEnd; ++e) {
4653       const PetscInt  idx = e - eStart;
4654       const PetscInt *cone;
4655 
4656       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4657 
4658       in.segmentlist[idx*2+0] = cone[0] - vStart;
4659       in.segmentlist[idx*2+1] = cone[1] - vStart;
4660 
4661       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4662     }
4663   }
4664 #if 0 /* Do not currently support holes */
4665   PetscReal *holeCoords;
4666   PetscInt   h, d;
4667 
4668   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4669   if (in.numberofholes > 0) {
4670     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4671     for (h = 0; h < in.numberofholes; ++h) {
4672       for (d = 0; d < dim; ++d) {
4673         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4674       }
4675     }
4676   }
4677 #endif
4678   if (!rank) {
4679     char args[32];
4680 
4681     /* Take away 'Q' for verbose output */
4682     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4683     if (createConvexHull) {
4684       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4685     }
4686     if (constrained) {
4687       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4688     }
4689     triangulate(args, &in, &out, NULL);
4690   }
4691   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4692   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4693   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4694   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4695   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4696 
4697   {
4698     const PetscInt numCorners  = 3;
4699     const PetscInt numCells    = out.numberoftriangles;
4700     const PetscInt numVertices = out.numberofpoints;
4701     const int     *cells      = out.trianglelist;
4702     const double  *meshCoords = out.pointlist;
4703 
4704     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4705     /* Set labels */
4706     for (v = 0; v < numVertices; ++v) {
4707       if (out.pointmarkerlist[v]) {
4708         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4709       }
4710     }
4711     if (interpolate) {
4712       for (e = 0; e < out.numberofedges; e++) {
4713         if (out.edgemarkerlist[e]) {
4714           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4715           const PetscInt *edges;
4716           PetscInt        numEdges;
4717 
4718           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4719           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4720           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4721           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4722         }
4723       }
4724     }
4725     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4726   }
4727 #if 0 /* Do not currently support holes */
4728   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4729 #endif
4730   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4731   PetscFunctionReturn(0);
4732 }
4733 
4734 #undef __FUNCT__
4735 #define __FUNCT__ "DMPlexRefine_Triangle"
4736 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4737 {
4738   MPI_Comm             comm;
4739   PetscInt             dim  = 2;
4740   struct triangulateio in;
4741   struct triangulateio out;
4742   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4743   PetscMPIInt          rank;
4744   PetscErrorCode       ierr;
4745 
4746   PetscFunctionBegin;
4747   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4748   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4749   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4750   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4751   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4752   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4753   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4754 
4755   in.numberofpoints = vEnd - vStart;
4756   if (in.numberofpoints > 0) {
4757     PetscSection coordSection;
4758     Vec          coordinates;
4759     PetscScalar *array;
4760 
4761     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4762     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4763     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4764     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4765     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4766     for (v = vStart; v < vEnd; ++v) {
4767       const PetscInt idx = v - vStart;
4768       PetscInt       off, d;
4769 
4770       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4771       for (d = 0; d < dim; ++d) {
4772         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4773       }
4774       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4775     }
4776     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4777   }
4778   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4779 
4780   in.numberofcorners   = 3;
4781   in.numberoftriangles = cEnd - cStart;
4782 
4783   in.trianglearealist  = (double*) maxVolumes;
4784   if (in.numberoftriangles > 0) {
4785     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4786     for (c = cStart; c < cEnd; ++c) {
4787       const PetscInt idx      = c - cStart;
4788       PetscInt      *closure = NULL;
4789       PetscInt       closureSize;
4790 
4791       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4792       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4793       for (v = 0; v < 3; ++v) {
4794         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4795       }
4796       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4797     }
4798   }
4799   /* TODO: Segment markers are missing on input */
4800 #if 0 /* Do not currently support holes */
4801   PetscReal *holeCoords;
4802   PetscInt   h, d;
4803 
4804   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4805   if (in.numberofholes > 0) {
4806     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4807     for (h = 0; h < in.numberofholes; ++h) {
4808       for (d = 0; d < dim; ++d) {
4809         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4810       }
4811     }
4812   }
4813 #endif
4814   if (!rank) {
4815     char args[32];
4816 
4817     /* Take away 'Q' for verbose output */
4818     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4819     triangulate(args, &in, &out, NULL);
4820   }
4821   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4822   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4823   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4824   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4825   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4826 
4827   {
4828     const PetscInt numCorners  = 3;
4829     const PetscInt numCells    = out.numberoftriangles;
4830     const PetscInt numVertices = out.numberofpoints;
4831     const int     *cells      = out.trianglelist;
4832     const double  *meshCoords = out.pointlist;
4833     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4834 
4835     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4836     /* Set labels */
4837     for (v = 0; v < numVertices; ++v) {
4838       if (out.pointmarkerlist[v]) {
4839         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4840       }
4841     }
4842     if (interpolate) {
4843       PetscInt e;
4844 
4845       for (e = 0; e < out.numberofedges; e++) {
4846         if (out.edgemarkerlist[e]) {
4847           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4848           const PetscInt *edges;
4849           PetscInt        numEdges;
4850 
4851           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4852           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4853           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4854           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4855         }
4856       }
4857     }
4858     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4859   }
4860 #if 0 /* Do not currently support holes */
4861   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4862 #endif
4863   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4864   PetscFunctionReturn(0);
4865 }
4866 #endif
4867 
4868 #if defined(PETSC_HAVE_TETGEN)
4869 #include <tetgen.h>
4870 #undef __FUNCT__
4871 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4872 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4873 {
4874   MPI_Comm       comm;
4875   const PetscInt dim  = 3;
4876   ::tetgenio     in;
4877   ::tetgenio     out;
4878   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4879   PetscMPIInt    rank;
4880   PetscErrorCode ierr;
4881 
4882   PetscFunctionBegin;
4883   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4884   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4885   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4886   in.numberofpoints = vEnd - vStart;
4887   if (in.numberofpoints > 0) {
4888     PetscSection coordSection;
4889     Vec          coordinates;
4890     PetscScalar *array;
4891 
4892     in.pointlist       = new double[in.numberofpoints*dim];
4893     in.pointmarkerlist = new int[in.numberofpoints];
4894 
4895     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4896     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4897     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4898     for (v = vStart; v < vEnd; ++v) {
4899       const PetscInt idx = v - vStart;
4900       PetscInt       off, d;
4901 
4902       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4903       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4904       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4905     }
4906     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4907   }
4908   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4909 
4910   in.numberoffacets = fEnd - fStart;
4911   if (in.numberoffacets > 0) {
4912     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4913     in.facetmarkerlist = new int[in.numberoffacets];
4914     for (f = fStart; f < fEnd; ++f) {
4915       const PetscInt idx     = f - fStart;
4916       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
4917 
4918       in.facetlist[idx].numberofpolygons = 1;
4919       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4920       in.facetlist[idx].numberofholes    = 0;
4921       in.facetlist[idx].holelist         = NULL;
4922 
4923       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4924       for (p = 0; p < numPoints*2; p += 2) {
4925         const PetscInt point = points[p];
4926         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4927       }
4928 
4929       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4930       poly->numberofvertices = numVertices;
4931       poly->vertexlist       = new int[poly->numberofvertices];
4932       for (v = 0; v < numVertices; ++v) {
4933         const PetscInt vIdx = points[v] - vStart;
4934         poly->vertexlist[v] = vIdx;
4935       }
4936       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4937       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4938     }
4939   }
4940   if (!rank) {
4941     char args[32];
4942 
4943     /* Take away 'Q' for verbose output */
4944     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4945     ::tetrahedralize(args, &in, &out);
4946   }
4947   {
4948     const PetscInt numCorners  = 4;
4949     const PetscInt numCells    = out.numberoftetrahedra;
4950     const PetscInt numVertices = out.numberofpoints;
4951     const int     *cells      = out.tetrahedronlist;
4952     const double  *meshCoords = out.pointlist;
4953 
4954     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4955     /* Set labels */
4956     for (v = 0; v < numVertices; ++v) {
4957       if (out.pointmarkerlist[v]) {
4958         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4959       }
4960     }
4961     if (interpolate) {
4962       PetscInt e;
4963 
4964       for (e = 0; e < out.numberofedges; e++) {
4965         if (out.edgemarkerlist[e]) {
4966           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4967           const PetscInt *edges;
4968           PetscInt        numEdges;
4969 
4970           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4971           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4972           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4973           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4974         }
4975       }
4976       for (f = 0; f < out.numberoftrifaces; f++) {
4977         if (out.trifacemarkerlist[f]) {
4978           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4979           const PetscInt *faces;
4980           PetscInt        numFaces;
4981 
4982           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4983           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4984           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4985           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4986         }
4987       }
4988     }
4989     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4990   }
4991   PetscFunctionReturn(0);
4992 }
4993 
4994 #undef __FUNCT__
4995 #define __FUNCT__ "DMPlexRefine_Tetgen"
4996 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4997 {
4998   MPI_Comm       comm;
4999   const PetscInt dim  = 3;
5000   ::tetgenio     in;
5001   ::tetgenio     out;
5002   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5003   PetscMPIInt    rank;
5004   PetscErrorCode ierr;
5005 
5006   PetscFunctionBegin;
5007   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5008   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5009   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5010   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5011   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5012 
5013   in.numberofpoints = vEnd - vStart;
5014   if (in.numberofpoints > 0) {
5015     PetscSection coordSection;
5016     Vec          coordinates;
5017     PetscScalar *array;
5018 
5019     in.pointlist       = new double[in.numberofpoints*dim];
5020     in.pointmarkerlist = new int[in.numberofpoints];
5021 
5022     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5023     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5024     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5025     for (v = vStart; v < vEnd; ++v) {
5026       const PetscInt idx = v - vStart;
5027       PetscInt       off, d;
5028 
5029       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5030       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5031       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5032     }
5033     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5034   }
5035   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5036 
5037   in.numberofcorners       = 4;
5038   in.numberoftetrahedra    = cEnd - cStart;
5039   in.tetrahedronvolumelist = (double*) maxVolumes;
5040   if (in.numberoftetrahedra > 0) {
5041     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5042     for (c = cStart; c < cEnd; ++c) {
5043       const PetscInt idx      = c - cStart;
5044       PetscInt      *closure = NULL;
5045       PetscInt       closureSize;
5046 
5047       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5048       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5049       for (v = 0; v < 4; ++v) {
5050         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5051       }
5052       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5053     }
5054   }
5055   /* TODO: Put in boundary faces with markers */
5056   if (!rank) {
5057     char args[32];
5058 
5059     /* Take away 'Q' for verbose output */
5060     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5061     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5062     ::tetrahedralize(args, &in, &out);
5063   }
5064   in.tetrahedronvolumelist = NULL;
5065 
5066   {
5067     const PetscInt numCorners  = 4;
5068     const PetscInt numCells    = out.numberoftetrahedra;
5069     const PetscInt numVertices = out.numberofpoints;
5070     const int     *cells      = out.tetrahedronlist;
5071     const double  *meshCoords = out.pointlist;
5072     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5073 
5074     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
5075     /* Set labels */
5076     for (v = 0; v < numVertices; ++v) {
5077       if (out.pointmarkerlist[v]) {
5078         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5079       }
5080     }
5081     if (interpolate) {
5082       PetscInt e, f;
5083 
5084       for (e = 0; e < out.numberofedges; e++) {
5085         if (out.edgemarkerlist[e]) {
5086           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5087           const PetscInt *edges;
5088           PetscInt        numEdges;
5089 
5090           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5091           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5092           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5093           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5094         }
5095       }
5096       for (f = 0; f < out.numberoftrifaces; f++) {
5097         if (out.trifacemarkerlist[f]) {
5098           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5099           const PetscInt *faces;
5100           PetscInt        numFaces;
5101 
5102           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5103           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5104           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5105           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5106         }
5107       }
5108     }
5109     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5110   }
5111   PetscFunctionReturn(0);
5112 }
5113 #endif
5114 
5115 #if defined(PETSC_HAVE_CTETGEN)
5116 #include "ctetgen.h"
5117 
5118 #undef __FUNCT__
5119 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5120 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5121 {
5122   MPI_Comm       comm;
5123   const PetscInt dim  = 3;
5124   PLC           *in, *out;
5125   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5126   PetscMPIInt    rank;
5127   PetscErrorCode ierr;
5128 
5129   PetscFunctionBegin;
5130   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5131   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5132   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5133   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5134   ierr = PLCCreate(&in);CHKERRQ(ierr);
5135   ierr = PLCCreate(&out);CHKERRQ(ierr);
5136 
5137   in->numberofpoints = vEnd - vStart;
5138   if (in->numberofpoints > 0) {
5139     PetscSection coordSection;
5140     Vec          coordinates;
5141     PetscScalar *array;
5142 
5143     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5144     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5145     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5146     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5147     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5148     for (v = vStart; v < vEnd; ++v) {
5149       const PetscInt idx = v - vStart;
5150       PetscInt       off, d, m;
5151 
5152       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5153       for (d = 0; d < dim; ++d) {
5154         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5155       }
5156       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5157 
5158       in->pointmarkerlist[idx] = (int) m;
5159     }
5160     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5161   }
5162   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5163 
5164   in->numberoffacets = fEnd - fStart;
5165   if (in->numberoffacets > 0) {
5166     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5167     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5168     for (f = fStart; f < fEnd; ++f) {
5169       const PetscInt idx     = f - fStart;
5170       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5171       polygon       *poly;
5172 
5173       in->facetlist[idx].numberofpolygons = 1;
5174 
5175       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5176 
5177       in->facetlist[idx].numberofholes    = 0;
5178       in->facetlist[idx].holelist         = NULL;
5179 
5180       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5181       for (p = 0; p < numPoints*2; p += 2) {
5182         const PetscInt point = points[p];
5183         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5184       }
5185 
5186       poly                   = in->facetlist[idx].polygonlist;
5187       poly->numberofvertices = numVertices;
5188       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5189       for (v = 0; v < numVertices; ++v) {
5190         const PetscInt vIdx = points[v] - vStart;
5191         poly->vertexlist[v] = vIdx;
5192       }
5193       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5194       in->facetmarkerlist[idx] = (int) m;
5195       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5196     }
5197   }
5198   if (!rank) {
5199     TetGenOpts t;
5200 
5201     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5202     t.in        = boundary; /* Should go away */
5203     t.plc       = 1;
5204     t.quality   = 1;
5205     t.edgesout  = 1;
5206     t.zeroindex = 1;
5207     t.quiet     = 1;
5208     t.verbose   = verbose;
5209     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5210     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5211   }
5212   {
5213     const PetscInt numCorners  = 4;
5214     const PetscInt numCells    = out->numberoftetrahedra;
5215     const PetscInt numVertices = out->numberofpoints;
5216     const int     *cells      = out->tetrahedronlist;
5217     const double  *meshCoords = out->pointlist;
5218 
5219     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
5220     /* Set labels */
5221     for (v = 0; v < numVertices; ++v) {
5222       if (out->pointmarkerlist[v]) {
5223         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5224       }
5225     }
5226     if (interpolate) {
5227       PetscInt e;
5228 
5229       for (e = 0; e < out->numberofedges; e++) {
5230         if (out->edgemarkerlist[e]) {
5231           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5232           const PetscInt *edges;
5233           PetscInt        numEdges;
5234 
5235           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5236           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5237           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5238           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5239         }
5240       }
5241       for (f = 0; f < out->numberoftrifaces; f++) {
5242         if (out->trifacemarkerlist[f]) {
5243           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5244           const PetscInt *faces;
5245           PetscInt        numFaces;
5246 
5247           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5248           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5249           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5250           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5251         }
5252       }
5253     }
5254     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5255   }
5256 
5257   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5258   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5259   PetscFunctionReturn(0);
5260 }
5261 
5262 #undef __FUNCT__
5263 #define __FUNCT__ "DMPlexRefine_CTetgen"
5264 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5265 {
5266   MPI_Comm       comm;
5267   const PetscInt dim  = 3;
5268   PLC           *in, *out;
5269   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5270   PetscMPIInt    rank;
5271   PetscErrorCode ierr;
5272 
5273   PetscFunctionBegin;
5274   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5275   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5276   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5277   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5278   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5279   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5280   ierr = PLCCreate(&in);CHKERRQ(ierr);
5281   ierr = PLCCreate(&out);CHKERRQ(ierr);
5282 
5283   in->numberofpoints = vEnd - vStart;
5284   if (in->numberofpoints > 0) {
5285     PetscSection coordSection;
5286     Vec          coordinates;
5287     PetscScalar *array;
5288 
5289     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5290     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5291     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5292     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5293     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5294     for (v = vStart; v < vEnd; ++v) {
5295       const PetscInt idx = v - vStart;
5296       PetscInt       off, d, m;
5297 
5298       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5299       for (d = 0; d < dim; ++d) {
5300         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5301       }
5302       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5303 
5304       in->pointmarkerlist[idx] = (int) m;
5305     }
5306     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5307   }
5308   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5309 
5310   in->numberofcorners       = 4;
5311   in->numberoftetrahedra    = cEnd - cStart;
5312   in->tetrahedronvolumelist = maxVolumes;
5313   if (in->numberoftetrahedra > 0) {
5314     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5315     for (c = cStart; c < cEnd; ++c) {
5316       const PetscInt idx      = c - cStart;
5317       PetscInt      *closure = NULL;
5318       PetscInt       closureSize;
5319 
5320       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5321       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5322       for (v = 0; v < 4; ++v) {
5323         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5324       }
5325       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5326     }
5327   }
5328   if (!rank) {
5329     TetGenOpts t;
5330 
5331     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5332 
5333     t.in        = dm; /* Should go away */
5334     t.refine    = 1;
5335     t.varvolume = 1;
5336     t.quality   = 1;
5337     t.edgesout  = 1;
5338     t.zeroindex = 1;
5339     t.quiet     = 1;
5340     t.verbose   = verbose; /* Change this */
5341 
5342     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5343     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5344   }
5345   {
5346     const PetscInt numCorners  = 4;
5347     const PetscInt numCells    = out->numberoftetrahedra;
5348     const PetscInt numVertices = out->numberofpoints;
5349     const int     *cells       = out->tetrahedronlist;
5350     const double  *meshCoords  = out->pointlist;
5351     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5352 
5353     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
5354     /* Set labels */
5355     for (v = 0; v < numVertices; ++v) {
5356       if (out->pointmarkerlist[v]) {
5357         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5358       }
5359     }
5360     if (interpolate) {
5361       PetscInt e, f;
5362 
5363       for (e = 0; e < out->numberofedges; e++) {
5364         if (out->edgemarkerlist[e]) {
5365           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5366           const PetscInt *edges;
5367           PetscInt        numEdges;
5368 
5369           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5370           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5371           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5372           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5373         }
5374       }
5375       for (f = 0; f < out->numberoftrifaces; f++) {
5376         if (out->trifacemarkerlist[f]) {
5377           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5378           const PetscInt *faces;
5379           PetscInt        numFaces;
5380 
5381           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5382           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5383           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5384           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5385         }
5386       }
5387     }
5388     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5389   }
5390   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5391   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5392   PetscFunctionReturn(0);
5393 }
5394 #endif
5395 
5396 #undef __FUNCT__
5397 #define __FUNCT__ "DMPlexGenerate"
5398 /*@C
5399   DMPlexGenerate - Generates a mesh.
5400 
5401   Not Collective
5402 
5403   Input Parameters:
5404 + boundary - The DMPlex boundary object
5405 . name - The mesh generation package name
5406 - interpolate - Flag to create intermediate mesh elements
5407 
5408   Output Parameter:
5409 . mesh - The DMPlex object
5410 
5411   Level: intermediate
5412 
5413 .keywords: mesh, elements
5414 .seealso: DMPlexCreate(), DMRefine()
5415 @*/
5416 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5417 {
5418   PetscInt       dim;
5419   char           genname[1024];
5420   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5421   PetscErrorCode ierr;
5422 
5423   PetscFunctionBegin;
5424   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5425   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5426   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5427   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5428   if (flg) name = genname;
5429   if (name) {
5430     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5431     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5432     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5433   }
5434   switch (dim) {
5435   case 1:
5436     if (!name || isTriangle) {
5437 #if defined(PETSC_HAVE_TRIANGLE)
5438       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5439 #else
5440       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5441 #endif
5442     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5443     break;
5444   case 2:
5445     if (!name || isCTetgen) {
5446 #if defined(PETSC_HAVE_CTETGEN)
5447       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5448 #else
5449       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5450 #endif
5451     } else if (isTetgen) {
5452 #if defined(PETSC_HAVE_TETGEN)
5453       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5454 #else
5455       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5456 #endif
5457     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5458     break;
5459   default:
5460     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5461   }
5462   PetscFunctionReturn(0);
5463 }
5464 
5465 typedef PetscInt CellRefiner;
5466 
5467 #undef __FUNCT__
5468 #define __FUNCT__ "GetDepthStart_Private"
5469 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5470 {
5471   PetscFunctionBegin;
5472   if (cStart) *cStart = 0;
5473   if (vStart) *vStart = depthSize[depth];
5474   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5475   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5476   PetscFunctionReturn(0);
5477 }
5478 
5479 #undef __FUNCT__
5480 #define __FUNCT__ "GetDepthEnd_Private"
5481 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5482 {
5483   PetscFunctionBegin;
5484   if (cEnd) *cEnd = depthSize[depth];
5485   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5486   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5487   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5488   PetscFunctionReturn(0);
5489 }
5490 
5491 #undef __FUNCT__
5492 #define __FUNCT__ "CellRefinerGetSizes"
5493 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5494 {
5495   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5496   PetscErrorCode ierr;
5497 
5498   PetscFunctionBegin;
5499   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5500   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5501   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5502   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5503   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5504   switch (refiner) {
5505   case 1:
5506     /* Simplicial 2D */
5507     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5508     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5509     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5510     break;
5511   case 3:
5512     /* Hybrid 2D */
5513     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5514     cMax = PetscMin(cEnd, cMax);
5515     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5516     fMax         = PetscMin(fEnd, fMax);
5517     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5518     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 */
5519     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5520     break;
5521   case 2:
5522     /* Hex 2D */
5523     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5524     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5525     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5526     break;
5527   default:
5528     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5529   }
5530   PetscFunctionReturn(0);
5531 }
5532 
5533 #undef __FUNCT__
5534 #define __FUNCT__ "CellRefinerSetConeSizes"
5535 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5536 {
5537   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5538   PetscErrorCode ierr;
5539 
5540   PetscFunctionBegin;
5541   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5542   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5543   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5544   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5545   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5546   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5547   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5548   switch (refiner) {
5549   case 1:
5550     /* Simplicial 2D */
5551     /* All cells have 3 faces */
5552     for (c = cStart; c < cEnd; ++c) {
5553       for (r = 0; r < 4; ++r) {
5554         const PetscInt newp = (c - cStart)*4 + r;
5555 
5556         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5557       }
5558     }
5559     /* Split faces have 2 vertices and the same cells as the parent */
5560     for (f = fStart; f < fEnd; ++f) {
5561       for (r = 0; r < 2; ++r) {
5562         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5563         PetscInt       size;
5564 
5565         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5566         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5567         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5568       }
5569     }
5570     /* Interior faces have 2 vertices and 2 cells */
5571     for (c = cStart; c < cEnd; ++c) {
5572       for (r = 0; r < 3; ++r) {
5573         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5574 
5575         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5576         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5577       }
5578     }
5579     /* Old vertices have identical supports */
5580     for (v = vStart; v < vEnd; ++v) {
5581       const PetscInt newp = vStartNew + (v - vStart);
5582       PetscInt       size;
5583 
5584       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5585       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5586     }
5587     /* Face vertices have 2 + cells*2 supports */
5588     for (f = fStart; f < fEnd; ++f) {
5589       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5590       PetscInt       size;
5591 
5592       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5593       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5594     }
5595     break;
5596   case 2:
5597     /* Hex 2D */
5598     /* All cells have 4 faces */
5599     for (c = cStart; c < cEnd; ++c) {
5600       for (r = 0; r < 4; ++r) {
5601         const PetscInt newp = (c - cStart)*4 + r;
5602 
5603         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5604       }
5605     }
5606     /* Split faces have 2 vertices and the same cells as the parent */
5607     for (f = fStart; f < fEnd; ++f) {
5608       for (r = 0; r < 2; ++r) {
5609         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5610         PetscInt       size;
5611 
5612         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5613         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5614         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5615       }
5616     }
5617     /* Interior faces have 2 vertices and 2 cells */
5618     for (c = cStart; c < cEnd; ++c) {
5619       for (r = 0; r < 4; ++r) {
5620         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5621 
5622         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5623         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5624       }
5625     }
5626     /* Old vertices have identical supports */
5627     for (v = vStart; v < vEnd; ++v) {
5628       const PetscInt newp = vStartNew + (v - vStart);
5629       PetscInt       size;
5630 
5631       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5632       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5633     }
5634     /* Face vertices have 2 + cells supports */
5635     for (f = fStart; f < fEnd; ++f) {
5636       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5637       PetscInt       size;
5638 
5639       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5640       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5641     }
5642     /* Cell vertices have 4 supports */
5643     for (c = cStart; c < cEnd; ++c) {
5644       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5645 
5646       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5647     }
5648     break;
5649   case 3:
5650     /* Hybrid 2D */
5651     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5652     cMax = PetscMin(cEnd, cMax);
5653     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5654     fMax = PetscMin(fEnd, fMax);
5655     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5656     /* Interior cells have 3 faces */
5657     for (c = cStart; c < cMax; ++c) {
5658       for (r = 0; r < 4; ++r) {
5659         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5660 
5661         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5662       }
5663     }
5664     /* Hybrid cells have 4 faces */
5665     for (c = cMax; c < cEnd; ++c) {
5666       for (r = 0; r < 2; ++r) {
5667         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5668 
5669         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5670       }
5671     }
5672     /* Interior split faces have 2 vertices and the same cells as the parent */
5673     for (f = fStart; f < fMax; ++f) {
5674       for (r = 0; r < 2; ++r) {
5675         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5676         PetscInt       size;
5677 
5678         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5679         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5680         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5681       }
5682     }
5683     /* Interior cell faces have 2 vertices and 2 cells */
5684     for (c = cStart; c < cMax; ++c) {
5685       for (r = 0; r < 3; ++r) {
5686         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5687 
5688         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5689         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5690       }
5691     }
5692     /* Hybrid faces have 2 vertices and the same cells */
5693     for (f = fMax; f < fEnd; ++f) {
5694       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5695       PetscInt       size;
5696 
5697       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5698       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5699       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5700     }
5701     /* Hybrid cell faces have 2 vertices and 2 cells */
5702     for (c = cMax; c < cEnd; ++c) {
5703       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5704 
5705       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5706       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5707     }
5708     /* Old vertices have identical supports */
5709     for (v = vStart; v < vEnd; ++v) {
5710       const PetscInt newp = vStartNew + (v - vStart);
5711       PetscInt       size;
5712 
5713       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5714       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5715     }
5716     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5717     for (f = fStart; f < fMax; ++f) {
5718       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5719       const PetscInt *support;
5720       PetscInt       size, newSize = 2, s;
5721 
5722       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5723       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5724       for (s = 0; s < size; ++s) {
5725         if (support[s] >= cMax) newSize += 1;
5726         else newSize += 2;
5727       }
5728       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5729     }
5730     break;
5731   default:
5732     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5733   }
5734   PetscFunctionReturn(0);
5735 }
5736 
5737 #undef __FUNCT__
5738 #define __FUNCT__ "CellRefinerSetCones"
5739 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5740 {
5741   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;
5742   PetscInt       maxSupportSize, *supportRef;
5743   PetscErrorCode ierr;
5744 
5745   PetscFunctionBegin;
5746   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5747   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5748   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5749   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5750   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5751   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5752   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5753   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5754   switch (refiner) {
5755   case 1:
5756     /* Simplicial 2D */
5757     /*
5758      2
5759      |\
5760      | \
5761      |  \
5762      |   \
5763      | C  \
5764      |     \
5765      |      \
5766      2---1---1
5767      |\  D  / \
5768      | 2   0   \
5769      |A \ /  B  \
5770      0---0-------1
5771      */
5772     /* All cells have 3 faces */
5773     for (c = cStart; c < cEnd; ++c) {
5774       const PetscInt  newp = cStartNew + (c - cStart)*4;
5775       const PetscInt *cone, *ornt;
5776       PetscInt        coneNew[3], orntNew[3];
5777 
5778       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5779       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5780       /* A triangle */
5781       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5782       orntNew[0] = ornt[0];
5783       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5784       orntNew[1] = -2;
5785       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5786       orntNew[2] = ornt[2];
5787       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5788       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5789 #if 1
5790       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
5791       for (p = 0; p < 3; ++p) {
5792         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5793       }
5794 #endif
5795       /* B triangle */
5796       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5797       orntNew[0] = ornt[0];
5798       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5799       orntNew[1] = ornt[1];
5800       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5801       orntNew[2] = -2;
5802       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5803       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5804 #if 1
5805       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
5806       for (p = 0; p < 3; ++p) {
5807         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5808       }
5809 #endif
5810       /* C triangle */
5811       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5812       orntNew[0] = -2;
5813       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5814       orntNew[1] = ornt[1];
5815       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5816       orntNew[2] = ornt[2];
5817       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5818       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5819 #if 1
5820       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
5821       for (p = 0; p < 3; ++p) {
5822         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5823       }
5824 #endif
5825       /* D triangle */
5826       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5827       orntNew[0] = 0;
5828       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5829       orntNew[1] = 0;
5830       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5831       orntNew[2] = 0;
5832       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5833       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5834 #if 1
5835       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
5836       for (p = 0; p < 3; ++p) {
5837         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5838       }
5839 #endif
5840     }
5841     /* Split faces have 2 vertices and the same cells as the parent */
5842     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5843     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5844     for (f = fStart; f < fEnd; ++f) {
5845       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5846 
5847       for (r = 0; r < 2; ++r) {
5848         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5849         const PetscInt *cone, *support;
5850         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5851 
5852         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5853         coneNew[0]       = vStartNew + (cone[0] - vStart);
5854         coneNew[1]       = vStartNew + (cone[1] - vStart);
5855         coneNew[(r+1)%2] = newv;
5856         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5857 #if 1
5858         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5859         for (p = 0; p < 2; ++p) {
5860           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5861         }
5862 #endif
5863         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5864         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5865         for (s = 0; s < supportSize; ++s) {
5866           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5867           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5868           for (c = 0; c < coneSize; ++c) {
5869             if (cone[c] == f) break;
5870           }
5871           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5872         }
5873         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5874 #if 1
5875         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5876         for (p = 0; p < supportSize; ++p) {
5877           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5878         }
5879 #endif
5880       }
5881     }
5882     /* Interior faces have 2 vertices and 2 cells */
5883     for (c = cStart; c < cEnd; ++c) {
5884       const PetscInt *cone;
5885 
5886       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5887       for (r = 0; r < 3; ++r) {
5888         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5889         PetscInt       coneNew[2];
5890         PetscInt       supportNew[2];
5891 
5892         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5893         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5894         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5895 #if 1
5896         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5897         for (p = 0; p < 2; ++p) {
5898           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5899         }
5900 #endif
5901         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5902         supportNew[1] = (c - cStart)*4 + 3;
5903         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5904 #if 1
5905         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5906         for (p = 0; p < 2; ++p) {
5907           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5908         }
5909 #endif
5910       }
5911     }
5912     /* Old vertices have identical supports */
5913     for (v = vStart; v < vEnd; ++v) {
5914       const PetscInt  newp = vStartNew + (v - vStart);
5915       const PetscInt *support, *cone;
5916       PetscInt        size, s;
5917 
5918       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5919       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5920       for (s = 0; s < size; ++s) {
5921         PetscInt r = 0;
5922 
5923         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5924         if (cone[1] == v) r = 1;
5925         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5926       }
5927       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5928 #if 1
5929       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5930       for (p = 0; p < size; ++p) {
5931         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5932       }
5933 #endif
5934     }
5935     /* Face vertices have 2 + cells*2 supports */
5936     for (f = fStart; f < fEnd; ++f) {
5937       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5938       const PetscInt *cone, *support;
5939       PetscInt        size, s;
5940 
5941       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5942       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5943       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5944       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5945       for (s = 0; s < size; ++s) {
5946         PetscInt r = 0;
5947 
5948         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5949         if      (cone[1] == f) r = 1;
5950         else if (cone[2] == f) r = 2;
5951         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5952         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5953       }
5954       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5955 #if 1
5956       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5957       for (p = 0; p < 2+size*2; ++p) {
5958         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5959       }
5960 #endif
5961     }
5962     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5963     break;
5964   case 2:
5965     /* Hex 2D */
5966     /*
5967      3---------2---------2
5968      |         |         |
5969      |    D    2    C    |
5970      |         |         |
5971      3----3----0----1----1
5972      |         |         |
5973      |    A    0    B    |
5974      |         |         |
5975      0---------0---------1
5976      */
5977     /* All cells have 4 faces */
5978     for (c = cStart; c < cEnd; ++c) {
5979       const PetscInt  newp = (c - cStart)*4;
5980       const PetscInt *cone, *ornt;
5981       PetscInt        coneNew[4], orntNew[4];
5982 
5983       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5984       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5985       /* A quad */
5986       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5987       orntNew[0] = ornt[0];
5988       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5989       orntNew[1] = 0;
5990       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5991       orntNew[2] = -2;
5992       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5993       orntNew[3] = ornt[3];
5994       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5995       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5996 #if 1
5997       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
5998       for (p = 0; p < 4; ++p) {
5999         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6000       }
6001 #endif
6002       /* B quad */
6003       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6004       orntNew[0] = ornt[0];
6005       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6006       orntNew[1] = ornt[1];
6007       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6008       orntNew[2] = 0;
6009       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6010       orntNew[3] = -2;
6011       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6012       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6013 #if 1
6014       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6015       for (p = 0; p < 4; ++p) {
6016         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6017       }
6018 #endif
6019       /* C quad */
6020       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6021       orntNew[0] = -2;
6022       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6023       orntNew[1] = ornt[1];
6024       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6025       orntNew[2] = ornt[2];
6026       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6027       orntNew[3] = 0;
6028       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6029       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6030 #if 1
6031       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6032       for (p = 0; p < 4; ++p) {
6033         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6034       }
6035 #endif
6036       /* D quad */
6037       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6038       orntNew[0] = 0;
6039       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6040       orntNew[1] = -2;
6041       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6042       orntNew[2] = ornt[2];
6043       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6044       orntNew[3] = ornt[3];
6045       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6046       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6047 #if 1
6048       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6049       for (p = 0; p < 4; ++p) {
6050         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6051       }
6052 #endif
6053     }
6054     /* Split faces have 2 vertices and the same cells as the parent */
6055     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6056     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6057     for (f = fStart; f < fEnd; ++f) {
6058       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6059 
6060       for (r = 0; r < 2; ++r) {
6061         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6062         const PetscInt *cone, *support;
6063         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6064 
6065         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6066         coneNew[0]       = vStartNew + (cone[0] - vStart);
6067         coneNew[1]       = vStartNew + (cone[1] - vStart);
6068         coneNew[(r+1)%2] = newv;
6069         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6070 #if 1
6071         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6072         for (p = 0; p < 2; ++p) {
6073           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6074         }
6075 #endif
6076         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6077         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6078         for (s = 0; s < supportSize; ++s) {
6079           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6080           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6081           for (c = 0; c < coneSize; ++c) {
6082             if (cone[c] == f) break;
6083           }
6084           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6085         }
6086         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6087 #if 1
6088         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6089         for (p = 0; p < supportSize; ++p) {
6090           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6091         }
6092 #endif
6093       }
6094     }
6095     /* Interior faces have 2 vertices and 2 cells */
6096     for (c = cStart; c < cEnd; ++c) {
6097       const PetscInt *cone;
6098       PetscInt        coneNew[2], supportNew[2];
6099 
6100       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6101       for (r = 0; r < 4; ++r) {
6102         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6103 
6104         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6105         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6106         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6107 #if 1
6108         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6109         for (p = 0; p < 2; ++p) {
6110           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6111         }
6112 #endif
6113         supportNew[0] = (c - cStart)*4 + r;
6114         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6115         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6116 #if 1
6117         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6118         for (p = 0; p < 2; ++p) {
6119           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6120         }
6121 #endif
6122       }
6123     }
6124     /* Old vertices have identical supports */
6125     for (v = vStart; v < vEnd; ++v) {
6126       const PetscInt  newp = vStartNew + (v - vStart);
6127       const PetscInt *support, *cone;
6128       PetscInt        size, s;
6129 
6130       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6131       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6132       for (s = 0; s < size; ++s) {
6133         PetscInt r = 0;
6134 
6135         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6136         if (cone[1] == v) r = 1;
6137         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6138       }
6139       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6140 #if 1
6141       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6142       for (p = 0; p < size; ++p) {
6143         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6144       }
6145 #endif
6146     }
6147     /* Face vertices have 2 + cells supports */
6148     for (f = fStart; f < fEnd; ++f) {
6149       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6150       const PetscInt *cone, *support;
6151       PetscInt        size, s;
6152 
6153       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6154       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6155       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6156       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6157       for (s = 0; s < size; ++s) {
6158         PetscInt r = 0;
6159 
6160         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6161         if      (cone[1] == f) r = 1;
6162         else if (cone[2] == f) r = 2;
6163         else if (cone[3] == f) r = 3;
6164         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6165       }
6166       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6167 #if 1
6168       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6169       for (p = 0; p < 2+size; ++p) {
6170         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6171       }
6172 #endif
6173     }
6174     /* Cell vertices have 4 supports */
6175     for (c = cStart; c < cEnd; ++c) {
6176       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6177       PetscInt       supportNew[4];
6178 
6179       for (r = 0; r < 4; ++r) {
6180         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6181       }
6182       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6183     }
6184     break;
6185   case 3:
6186     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6187     cMax = PetscMin(cEnd, cMax);
6188     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6189     fMax = PetscMin(fEnd, fMax);
6190     /* Interior cells have 3 faces */
6191     for (c = cStart; c < cMax; ++c) {
6192       const PetscInt  newp = cStartNew + (c - cStart)*4;
6193       const PetscInt *cone, *ornt;
6194       PetscInt        coneNew[3], orntNew[3];
6195 
6196       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6197       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6198       /* A triangle */
6199       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6200       orntNew[0] = ornt[0];
6201       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6202       orntNew[1] = -2;
6203       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6204       orntNew[2] = ornt[2];
6205       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6206       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6207 #if 1
6208       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6209       for (p = 0; p < 3; ++p) {
6210         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6211       }
6212 #endif
6213       /* B triangle */
6214       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6215       orntNew[0] = ornt[0];
6216       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6217       orntNew[1] = ornt[1];
6218       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6219       orntNew[2] = -2;
6220       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6221       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6222 #if 1
6223       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6224       for (p = 0; p < 3; ++p) {
6225         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6226       }
6227 #endif
6228       /* C triangle */
6229       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6230       orntNew[0] = -2;
6231       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6232       orntNew[1] = ornt[1];
6233       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6234       orntNew[2] = ornt[2];
6235       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6236       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6237 #if 1
6238       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6239       for (p = 0; p < 3; ++p) {
6240         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6241       }
6242 #endif
6243       /* D triangle */
6244       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6245       orntNew[0] = 0;
6246       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6247       orntNew[1] = 0;
6248       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6249       orntNew[2] = 0;
6250       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6251       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6252 #if 1
6253       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6254       for (p = 0; p < 3; ++p) {
6255         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6256       }
6257 #endif
6258     }
6259     /*
6260      2----3----3
6261      |         |
6262      |    B    |
6263      |         |
6264      0----4--- 1
6265      |         |
6266      |    A    |
6267      |         |
6268      0----2----1
6269      */
6270     /* Hybrid cells have 4 faces */
6271     for (c = cMax; c < cEnd; ++c) {
6272       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6273       const PetscInt *cone, *ornt;
6274       PetscInt        coneNew[4], orntNew[4];
6275 
6276       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6277       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6278       /* A quad */
6279       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6280       orntNew[0] = ornt[0];
6281       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6282       orntNew[1] = ornt[1];
6283       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6284       orntNew[2] = 0;
6285       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6286       orntNew[3] = 0;
6287       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6288       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6289 #if 1
6290       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6291       for (p = 0; p < 4; ++p) {
6292         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6293       }
6294 #endif
6295       /* B quad */
6296       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6297       orntNew[0] = ornt[0];
6298       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6299       orntNew[1] = ornt[1];
6300       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6301       orntNew[2] = 0;
6302       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6303       orntNew[3] = 0;
6304       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6305       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6306 #if 1
6307       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6308       for (p = 0; p < 4; ++p) {
6309         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6310       }
6311 #endif
6312     }
6313     /* Interior split faces have 2 vertices and the same cells as the parent */
6314     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6315     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6316     for (f = fStart; f < fMax; ++f) {
6317       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6318 
6319       for (r = 0; r < 2; ++r) {
6320         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6321         const PetscInt *cone, *support;
6322         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6323 
6324         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6325         coneNew[0]       = vStartNew + (cone[0] - vStart);
6326         coneNew[1]       = vStartNew + (cone[1] - vStart);
6327         coneNew[(r+1)%2] = newv;
6328         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6329 #if 1
6330         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6331         for (p = 0; p < 2; ++p) {
6332           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6333         }
6334 #endif
6335         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6336         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6337         for (s = 0; s < supportSize; ++s) {
6338           if (support[s] >= cMax) {
6339             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6340           } else {
6341             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6342             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6343             for (c = 0; c < coneSize; ++c) {
6344               if (cone[c] == f) break;
6345             }
6346             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6347           }
6348         }
6349         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6350 #if 1
6351         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6352         for (p = 0; p < supportSize; ++p) {
6353           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6354         }
6355 #endif
6356       }
6357     }
6358     /* Interior cell faces have 2 vertices and 2 cells */
6359     for (c = cStart; c < cMax; ++c) {
6360       const PetscInt *cone;
6361 
6362       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6363       for (r = 0; r < 3; ++r) {
6364         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6365         PetscInt       coneNew[2];
6366         PetscInt       supportNew[2];
6367 
6368         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6369         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6370         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6371 #if 1
6372         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6373         for (p = 0; p < 2; ++p) {
6374           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6375         }
6376 #endif
6377         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6378         supportNew[1] = (c - cStart)*4 + 3;
6379         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6380 #if 1
6381         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6382         for (p = 0; p < 2; ++p) {
6383           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6384         }
6385 #endif
6386       }
6387     }
6388     /* Interior hybrid faces have 2 vertices and the same cells */
6389     for (f = fMax; f < fEnd; ++f) {
6390       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6391       const PetscInt *cone;
6392       const PetscInt *support;
6393       PetscInt        coneNew[2];
6394       PetscInt        supportNew[2];
6395       PetscInt        size, s, r;
6396 
6397       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6398       coneNew[0] = vStartNew + (cone[0] - vStart);
6399       coneNew[1] = vStartNew + (cone[1] - vStart);
6400       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6401 #if 1
6402       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6403       for (p = 0; p < 2; ++p) {
6404         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6405       }
6406 #endif
6407       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6408       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6409       for (s = 0; s < size; ++s) {
6410         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6411         for (r = 0; r < 2; ++r) {
6412           if (cone[r+2] == f) break;
6413         }
6414         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6415       }
6416       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6417 #if 1
6418       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6419       for (p = 0; p < size; ++p) {
6420         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6421       }
6422 #endif
6423     }
6424     /* Cell hybrid faces have 2 vertices and 2 cells */
6425     for (c = cMax; c < cEnd; ++c) {
6426       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6427       const PetscInt *cone;
6428       PetscInt        coneNew[2];
6429       PetscInt        supportNew[2];
6430 
6431       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6432       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6433       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6434       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6435 #if 1
6436       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6437       for (p = 0; p < 2; ++p) {
6438         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6439       }
6440 #endif
6441       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6442       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6443       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6444 #if 1
6445       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6446       for (p = 0; p < 2; ++p) {
6447         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6448       }
6449 #endif
6450     }
6451     /* Old vertices have identical supports */
6452     for (v = vStart; v < vEnd; ++v) {
6453       const PetscInt  newp = vStartNew + (v - vStart);
6454       const PetscInt *support, *cone;
6455       PetscInt        size, s;
6456 
6457       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6458       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6459       for (s = 0; s < size; ++s) {
6460         if (support[s] >= fMax) {
6461           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6462         } else {
6463           PetscInt r = 0;
6464 
6465           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6466           if (cone[1] == v) r = 1;
6467           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6468         }
6469       }
6470       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6471 #if 1
6472       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6473       for (p = 0; p < size; ++p) {
6474         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6475       }
6476 #endif
6477     }
6478     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6479     for (f = fStart; f < fMax; ++f) {
6480       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6481       const PetscInt *cone, *support;
6482       PetscInt        size, newSize = 2, s;
6483 
6484       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6485       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6486       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6487       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6488       for (s = 0; s < size; ++s) {
6489         PetscInt r = 0;
6490 
6491         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6492         if (support[s] >= cMax) {
6493           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6494 
6495           newSize += 1;
6496         } else {
6497           if      (cone[1] == f) r = 1;
6498           else if (cone[2] == f) r = 2;
6499           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6500           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6501 
6502           newSize += 2;
6503         }
6504       }
6505       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6506 #if 1
6507       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6508       for (p = 0; p < newSize; ++p) {
6509         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6510       }
6511 #endif
6512     }
6513     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6514     break;
6515   default:
6516     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6517   }
6518   PetscFunctionReturn(0);
6519 }
6520 
6521 #undef __FUNCT__
6522 #define __FUNCT__ "CellRefinerSetCoordinates"
6523 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6524 {
6525   PetscSection   coordSection, coordSectionNew;
6526   Vec            coordinates, coordinatesNew;
6527   PetscScalar   *coords, *coordsNew;
6528   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6529   PetscErrorCode ierr;
6530 
6531   PetscFunctionBegin;
6532   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6533   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6534   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6535   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6536   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6537   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6538   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6539   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6540   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6541   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6542   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6543   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6544   if (fMax < 0) fMax = fEnd;
6545   switch (refiner) {
6546   case 1:
6547   case 2:
6548   case 3:
6549     /* Simplicial and Hex 2D */
6550     /* All vertices have the dim coordinates */
6551     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6552       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6553       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6554     }
6555     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6556     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6557     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6558     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6559     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6560     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6561     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6562     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6563     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6564     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6565     /* Old vertices have the same coordinates */
6566     for (v = vStart; v < vEnd; ++v) {
6567       const PetscInt newv = vStartNew + (v - vStart);
6568       PetscInt       off, offnew, d;
6569 
6570       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6571       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6572       for (d = 0; d < dim; ++d) {
6573         coordsNew[offnew+d] = coords[off+d];
6574       }
6575     }
6576     /* Face vertices have the average of endpoint coordinates */
6577     for (f = fStart; f < fMax; ++f) {
6578       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6579       const PetscInt *cone;
6580       PetscInt        coneSize, offA, offB, offnew, d;
6581 
6582       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6583       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6584       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6585       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6586       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6587       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6588       for (d = 0; d < dim; ++d) {
6589         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6590       }
6591     }
6592     /* Just Hex 2D */
6593     if (refiner == 2) {
6594       /* Cell vertices have the average of corner coordinates */
6595       for (c = cStart; c < cEnd; ++c) {
6596         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6597         PetscInt      *cone = NULL;
6598         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6599 
6600         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6601         for (p = 0; p < closureSize*2; p += 2) {
6602           const PetscInt point = cone[p];
6603           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6604         }
6605         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6606         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6607         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6608         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6609         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6610         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6611         for (d = 0; d < dim; ++d) {
6612           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6613         }
6614         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6615       }
6616     }
6617     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6618     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6619     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6620     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6621     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6622     break;
6623   default:
6624     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6625   }
6626   PetscFunctionReturn(0);
6627 }
6628 
6629 #undef __FUNCT__
6630 #define __FUNCT__ "DMPlexCreateProcessSF"
6631 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6632 {
6633   PetscInt           numRoots, numLeaves, l;
6634   const PetscInt    *localPoints;
6635   const PetscSFNode *remotePoints;
6636   PetscInt          *localPointsNew;
6637   PetscSFNode       *remotePointsNew;
6638   PetscInt          *ranks, *ranksNew;
6639   PetscErrorCode     ierr;
6640 
6641   PetscFunctionBegin;
6642   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6643   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6644   for (l = 0; l < numLeaves; ++l) {
6645     ranks[l] = remotePoints[l].rank;
6646   }
6647   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6648   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6649   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6650   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6651   for (l = 0; l < numLeaves; ++l) {
6652     ranksNew[l]              = ranks[l];
6653     localPointsNew[l]        = l;
6654     remotePointsNew[l].index = 0;
6655     remotePointsNew[l].rank  = ranksNew[l];
6656   }
6657   ierr = PetscFree(ranks);CHKERRQ(ierr);
6658   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6659   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
6660   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6661   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6662   PetscFunctionReturn(0);
6663 }
6664 
6665 #undef __FUNCT__
6666 #define __FUNCT__ "CellRefinerCreateSF"
6667 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6668 {
6669   PetscSF            sf, sfNew, sfProcess;
6670   IS                 processRanks;
6671   MPI_Datatype       depthType;
6672   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6673   const PetscInt    *localPoints, *neighbors;
6674   const PetscSFNode *remotePoints;
6675   PetscInt          *localPointsNew;
6676   PetscSFNode       *remotePointsNew;
6677   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6678   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6679   PetscErrorCode     ierr;
6680 
6681   PetscFunctionBegin;
6682   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6683   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6684   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6685   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6686   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6687   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6688   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6689   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6690   switch (refiner) {
6691   case 3:
6692     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6693     cMax = PetscMin(cEnd, cMax);
6694     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6695     fMax = PetscMin(fEnd, fMax);
6696   }
6697   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6698   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6699   /* Caculate size of new SF */
6700   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6701   if (numRoots < 0) PetscFunctionReturn(0);
6702   for (l = 0; l < numLeaves; ++l) {
6703     const PetscInt p = localPoints[l];
6704 
6705     switch (refiner) {
6706     case 1:
6707       /* Simplicial 2D */
6708       if ((p >= vStart) && (p < vEnd)) {
6709         /* Old vertices stay the same */
6710         ++numLeavesNew;
6711       } else if ((p >= fStart) && (p < fEnd)) {
6712         /* Old faces add new faces and vertex */
6713         numLeavesNew += 1 + 2;
6714       } else if ((p >= cStart) && (p < cEnd)) {
6715         /* Old cells add new cells and interior faces */
6716         numLeavesNew += 4 + 3;
6717       }
6718       break;
6719     case 2:
6720       /* Hex 2D */
6721       if ((p >= vStart) && (p < vEnd)) {
6722         /* Old vertices stay the same */
6723         ++numLeavesNew;
6724       } else if ((p >= fStart) && (p < fEnd)) {
6725         /* Old faces add new faces and vertex */
6726         numLeavesNew += 1 + 2;
6727       } else if ((p >= cStart) && (p < cEnd)) {
6728         /* Old cells add new cells and interior faces */
6729         numLeavesNew += 4 + 4;
6730       }
6731       break;
6732     default:
6733       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6734     }
6735   }
6736   /* Communicate depthSizes for each remote rank */
6737   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6738   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6739   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6740   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);
6741   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6742   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6743   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6744   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6745   for (n = 0; n < numNeighbors; ++n) {
6746     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6747   }
6748   depthSizeOld[depth]   = cMax;
6749   depthSizeOld[0]       = vMax;
6750   depthSizeOld[depth-1] = fMax;
6751   depthSizeOld[1]       = eMax;
6752 
6753   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6754   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6755 
6756   depthSizeOld[depth]   = cEnd - cStart;
6757   depthSizeOld[0]       = vEnd - vStart;
6758   depthSizeOld[depth-1] = fEnd - fStart;
6759   depthSizeOld[1]       = eEnd - eStart;
6760 
6761   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6762   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6763   for (n = 0; n < numNeighbors; ++n) {
6764     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6765   }
6766   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6767   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6768   /* Calculate new point SF */
6769   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6770   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6771   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6772   for (l = 0, m = 0; l < numLeaves; ++l) {
6773     PetscInt    p     = localPoints[l];
6774     PetscInt    rp    = remotePoints[l].index, n;
6775     PetscMPIInt rrank = remotePoints[l].rank;
6776 
6777     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6778     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6779     switch (refiner) {
6780     case 1:
6781       /* Simplicial 2D */
6782       if ((p >= vStart) && (p < vEnd)) {
6783         /* Old vertices stay the same */
6784         localPointsNew[m]        = vStartNew     + (p  - vStart);
6785         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6786         remotePointsNew[m].rank  = rrank;
6787         ++m;
6788       } else if ((p >= fStart) && (p < fEnd)) {
6789         /* Old faces add new faces and vertex */
6790         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6791         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6792         remotePointsNew[m].rank  = rrank;
6793         ++m;
6794         for (r = 0; r < 2; ++r, ++m) {
6795           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6796           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6797           remotePointsNew[m].rank  = rrank;
6798         }
6799       } else if ((p >= cStart) && (p < cEnd)) {
6800         /* Old cells add new cells and interior faces */
6801         for (r = 0; r < 4; ++r, ++m) {
6802           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6803           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6804           remotePointsNew[m].rank  = rrank;
6805         }
6806         for (r = 0; r < 3; ++r, ++m) {
6807           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6808           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6809           remotePointsNew[m].rank  = rrank;
6810         }
6811       }
6812       break;
6813     case 2:
6814       /* Hex 2D */
6815       if ((p >= vStart) && (p < vEnd)) {
6816         /* Old vertices stay the same */
6817         localPointsNew[m]        = vStartNew     + (p  - vStart);
6818         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6819         remotePointsNew[m].rank  = rrank;
6820         ++m;
6821       } else if ((p >= fStart) && (p < fEnd)) {
6822         /* Old faces add new faces and vertex */
6823         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6824         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6825         remotePointsNew[m].rank  = rrank;
6826         ++m;
6827         for (r = 0; r < 2; ++r, ++m) {
6828           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6829           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6830           remotePointsNew[m].rank  = rrank;
6831         }
6832       } else if ((p >= cStart) && (p < cEnd)) {
6833         /* Old cells add new cells and interior faces */
6834         for (r = 0; r < 4; ++r, ++m) {
6835           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6836           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6837           remotePointsNew[m].rank  = rrank;
6838         }
6839         for (r = 0; r < 4; ++r, ++m) {
6840           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6841           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6842           remotePointsNew[m].rank  = rrank;
6843         }
6844       }
6845       break;
6846     case 3:
6847       /* Hybrid simplicial 2D */
6848       if ((p >= vStart) && (p < vEnd)) {
6849         /* Old vertices stay the same */
6850         localPointsNew[m]        = vStartNew     + (p  - vStart);
6851         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6852         remotePointsNew[m].rank  = rrank;
6853         ++m;
6854       } else if ((p >= fStart) && (p < fMax)) {
6855         /* Old interior faces add new faces and vertex */
6856         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6857         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6858         remotePointsNew[m].rank  = rrank;
6859         ++m;
6860         for (r = 0; r < 2; ++r, ++m) {
6861           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6862           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6863           remotePointsNew[m].rank  = rrank;
6864         }
6865       } else if ((p >= fMax) && (p < fEnd)) {
6866         /* Old hybrid faces stay the same */
6867         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6868         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6869         remotePointsNew[m].rank  = rrank;
6870         ++m;
6871       } else if ((p >= cStart) && (p < cMax)) {
6872         /* Old interior cells add new cells and interior faces */
6873         for (r = 0; r < 4; ++r, ++m) {
6874           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6875           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6876           remotePointsNew[m].rank  = rrank;
6877         }
6878         for (r = 0; r < 3; ++r, ++m) {
6879           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6880           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6881           remotePointsNew[m].rank  = rrank;
6882         }
6883       } else if ((p >= cStart) && (p < cMax)) {
6884         /* Old hybrid cells add new cells and hybrid face */
6885         for (r = 0; r < 2; ++r, ++m) {
6886           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6887           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6888           remotePointsNew[m].rank  = rrank;
6889         }
6890         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6891         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]);
6892         remotePointsNew[m].rank  = rrank;
6893         ++m;
6894       }
6895       break;
6896     default:
6897       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6898     }
6899   }
6900   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6901   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6902   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6903   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6904   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6905   PetscFunctionReturn(0);
6906 }
6907 
6908 #undef __FUNCT__
6909 #define __FUNCT__ "CellRefinerCreateLabels"
6910 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6911 {
6912   PetscInt       numLabels, l;
6913   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6914   PetscErrorCode ierr;
6915 
6916   PetscFunctionBegin;
6917   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6918   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6919   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6920   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6921 
6922   cStartNew = 0;
6923   vStartNew = depthSize[2];
6924   fStartNew = depthSize[2] + depthSize[0];
6925 
6926   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6927   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6928   switch (refiner) {
6929   case 3:
6930     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6931     cMax = PetscMin(cEnd, cMax);
6932     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6933     fMax = PetscMin(fEnd, fMax);
6934   }
6935   for (l = 0; l < numLabels; ++l) {
6936     DMLabel         label, labelNew;
6937     const char     *lname;
6938     PetscBool       isDepth;
6939     IS              valueIS;
6940     const PetscInt *values;
6941     PetscInt        numValues, val;
6942 
6943     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6944     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6945     if (isDepth) continue;
6946     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6947     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6948     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6949     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6950     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6951     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6952     for (val = 0; val < numValues; ++val) {
6953       IS              pointIS;
6954       const PetscInt *points;
6955       PetscInt        numPoints, n;
6956 
6957       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6958       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6959       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6960       for (n = 0; n < numPoints; ++n) {
6961         const PetscInt p = points[n];
6962         switch (refiner) {
6963         case 1:
6964           /* Simplicial 2D */
6965           if ((p >= vStart) && (p < vEnd)) {
6966             /* Old vertices stay the same */
6967             newp = vStartNew + (p - vStart);
6968             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6969           } else if ((p >= fStart) && (p < fEnd)) {
6970             /* Old faces add new faces and vertex */
6971             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6972             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6973             for (r = 0; r < 2; ++r) {
6974               newp = fStartNew + (p - fStart)*2 + r;
6975               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6976             }
6977           } else if ((p >= cStart) && (p < cEnd)) {
6978             /* Old cells add new cells and interior faces */
6979             for (r = 0; r < 4; ++r) {
6980               newp = cStartNew + (p - cStart)*4 + r;
6981               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6982             }
6983             for (r = 0; r < 3; ++r) {
6984               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6985               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6986             }
6987           }
6988           break;
6989         case 2:
6990           /* Hex 2D */
6991           if ((p >= vStart) && (p < vEnd)) {
6992             /* Old vertices stay the same */
6993             newp = vStartNew + (p - vStart);
6994             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6995           } else if ((p >= fStart) && (p < fEnd)) {
6996             /* Old faces add new faces and vertex */
6997             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6998             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6999             for (r = 0; r < 2; ++r) {
7000               newp = fStartNew + (p - fStart)*2 + r;
7001               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7002             }
7003           } else if ((p >= cStart) && (p < cEnd)) {
7004             /* Old cells add new cells and interior faces and vertex */
7005             for (r = 0; r < 4; ++r) {
7006               newp = cStartNew + (p - cStart)*4 + r;
7007               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7008             }
7009             for (r = 0; r < 4; ++r) {
7010               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7011               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7012             }
7013             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7014             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7015           }
7016           break;
7017         case 3:
7018           /* Hybrid simplicial 2D */
7019           if ((p >= vStart) && (p < vEnd)) {
7020             /* Old vertices stay the same */
7021             newp = vStartNew + (p - vStart);
7022             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7023           } else if ((p >= fStart) && (p < fMax)) {
7024             /* Old interior faces add new faces and vertex */
7025             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7026             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7027             for (r = 0; r < 2; ++r) {
7028               newp = fStartNew + (p - fStart)*2 + r;
7029               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7030             }
7031           } else if ((p >= fMax) && (p < fEnd)) {
7032             /* Old hybrid faces stay the same */
7033             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7034             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7035           } else if ((p >= cStart) && (p < cMax)) {
7036             /* Old interior cells add new cells and interior faces */
7037             for (r = 0; r < 4; ++r) {
7038               newp = cStartNew + (p - cStart)*4 + r;
7039               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7040             }
7041             for (r = 0; r < 3; ++r) {
7042               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7043               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7044             }
7045           } else if ((p >= cMax) && (p < cEnd)) {
7046             /* Old hybrid cells add new cells and hybrid face */
7047             for (r = 0; r < 2; ++r) {
7048               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7049               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7050             }
7051             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7052             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7053           }
7054           break;
7055         default:
7056           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7057         }
7058       }
7059       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7060       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7061     }
7062     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7063     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7064     if (0) {
7065       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7066       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7067       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7068     }
7069   }
7070   PetscFunctionReturn(0);
7071 }
7072 
7073 #undef __FUNCT__
7074 #define __FUNCT__ "DMPlexRefine_Uniform"
7075 /* This will only work for interpolated meshes */
7076 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7077 {
7078   DM             rdm;
7079   PetscInt      *depthSize;
7080   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7081   PetscErrorCode ierr;
7082 
7083   PetscFunctionBegin;
7084   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
7085   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7086   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7087   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7088   /* Calculate number of new points of each depth */
7089   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7090   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7091   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7092   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7093   /* Step 1: Set chart */
7094   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7095   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7096   /* Step 2: Set cone/support sizes */
7097   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7098   /* Step 3: Setup refined DM */
7099   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7100   /* Step 4: Set cones and supports */
7101   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7102   /* Step 5: Stratify */
7103   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7104   /* Step 6: Set coordinates for vertices */
7105   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7106   /* Step 7: Create pointSF */
7107   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7108   /* Step 8: Create labels */
7109   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7110   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7111 
7112   *dmRefined = rdm;
7113   PetscFunctionReturn(0);
7114 }
7115 
7116 #undef __FUNCT__
7117 #define __FUNCT__ "DMPlexSetRefinementUniform"
7118 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7119 {
7120   DM_Plex *mesh = (DM_Plex*) dm->data;
7121 
7122   PetscFunctionBegin;
7123   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7124   mesh->refinementUniform = refinementUniform;
7125   PetscFunctionReturn(0);
7126 }
7127 
7128 #undef __FUNCT__
7129 #define __FUNCT__ "DMPlexGetRefinementUniform"
7130 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7131 {
7132   DM_Plex *mesh = (DM_Plex*) dm->data;
7133 
7134   PetscFunctionBegin;
7135   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7136   PetscValidPointer(refinementUniform,  2);
7137   *refinementUniform = mesh->refinementUniform;
7138   PetscFunctionReturn(0);
7139 }
7140 
7141 #undef __FUNCT__
7142 #define __FUNCT__ "DMPlexSetRefinementLimit"
7143 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7144 {
7145   DM_Plex *mesh = (DM_Plex*) dm->data;
7146 
7147   PetscFunctionBegin;
7148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7149   mesh->refinementLimit = refinementLimit;
7150   PetscFunctionReturn(0);
7151 }
7152 
7153 #undef __FUNCT__
7154 #define __FUNCT__ "DMPlexGetRefinementLimit"
7155 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7156 {
7157   DM_Plex *mesh = (DM_Plex*) dm->data;
7158 
7159   PetscFunctionBegin;
7160   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7161   PetscValidPointer(refinementLimit,  2);
7162   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7163   *refinementLimit = mesh->refinementLimit;
7164   PetscFunctionReturn(0);
7165 }
7166 
7167 #undef __FUNCT__
7168 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7169 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7170 {
7171   PetscInt       dim, cStart, coneSize, cMax;
7172   PetscErrorCode ierr;
7173 
7174   PetscFunctionBegin;
7175   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7176   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7177   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7178   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7179   switch (dim) {
7180   case 2:
7181     switch (coneSize) {
7182     case 3:
7183       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7184       else *cellRefiner = 1; /* Triangular */
7185       break;
7186     case 4:
7187       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7188       else *cellRefiner = 2; /* Quadrilateral */
7189       break;
7190     default:
7191       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7192     }
7193     break;
7194   default:
7195     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7196   }
7197   PetscFunctionReturn(0);
7198 }
7199 
7200 #undef __FUNCT__
7201 #define __FUNCT__ "DMRefine_Plex"
7202 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7203 {
7204   PetscReal      refinementLimit;
7205   PetscInt       dim, cStart, cEnd;
7206   char           genname[1024], *name = NULL;
7207   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7208   PetscErrorCode ierr;
7209 
7210   PetscFunctionBegin;
7211   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7212   if (isUniform) {
7213     CellRefiner cellRefiner;
7214 
7215     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7216     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7217     PetscFunctionReturn(0);
7218   }
7219   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7220   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7221   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7222   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7223   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7224   if (flg) name = genname;
7225   if (name) {
7226     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7227     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7228     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7229   }
7230   switch (dim) {
7231   case 2:
7232     if (!name || isTriangle) {
7233 #if defined(PETSC_HAVE_TRIANGLE)
7234       double  *maxVolumes;
7235       PetscInt c;
7236 
7237       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7238       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7239       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7240 #else
7241       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7242 #endif
7243     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7244     break;
7245   case 3:
7246     if (!name || isCTetgen) {
7247 #if defined(PETSC_HAVE_CTETGEN)
7248       PetscReal *maxVolumes;
7249       PetscInt   c;
7250 
7251       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7252       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7253       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7254 #else
7255       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7256 #endif
7257     } else if (isTetgen) {
7258 #if defined(PETSC_HAVE_TETGEN)
7259       double  *maxVolumes;
7260       PetscInt c;
7261 
7262       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7263       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7264       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7265 #else
7266       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7267 #endif
7268     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7269     break;
7270   default:
7271     SETERRQ1(PetscObjectComm((PetscObject)dm), 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 {
7332   DM_Plex       *mesh = (DM_Plex*) dm->data;
7333   DMLabel        next  = mesh->labels;
7334   PetscBool      flg   = PETSC_FALSE;
7335   PetscInt       depth;
7336   PetscErrorCode ierr;
7337 
7338   PetscFunctionBegin;
7339   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7340   if (stratumValue < 0) {
7341     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7342     PetscFunctionReturn(0);
7343   } else {
7344     PetscInt pStart, pEnd;
7345 
7346     if (start) *start = 0;
7347     if (end)   *end   = 0;
7348     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7349     if (pStart == pEnd) PetscFunctionReturn(0);
7350   }
7351   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7352   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7353   /* We should have a generic GetLabel() and a Label class */
7354   while (next) {
7355     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7356     if (flg) break;
7357     next = next->next;
7358   }
7359   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7360   depth = stratumValue;
7361   if ((depth < 0) || (depth >= next->numStrata)) {
7362     if (start) *start = 0;
7363     if (end)   *end   = 0;
7364   } else {
7365     if (start) *start = next->points[next->stratumOffsets[depth]];
7366     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7367   }
7368   PetscFunctionReturn(0);
7369 }
7370 
7371 #undef __FUNCT__
7372 #define __FUNCT__ "DMPlexGetHeightStratum"
7373 /*@
7374   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7375 
7376   Not Collective
7377 
7378   Input Parameters:
7379 + dm           - The DMPlex object
7380 - stratumValue - The requested height
7381 
7382   Output Parameters:
7383 + start - The first point at this height
7384 - end   - One beyond the last point at this height
7385 
7386   Level: developer
7387 
7388 .keywords: mesh, points
7389 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7390 @*/
7391 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7392 {
7393   DM_Plex       *mesh = (DM_Plex*) dm->data;
7394   DMLabel        next  = mesh->labels;
7395   PetscBool      flg   = PETSC_FALSE;
7396   PetscInt       depth;
7397   PetscErrorCode ierr;
7398 
7399   PetscFunctionBegin;
7400   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7401   if (stratumValue < 0) {
7402     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7403   } else {
7404     PetscInt pStart, pEnd;
7405 
7406     if (start) *start = 0;
7407     if (end)   *end   = 0;
7408     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7409     if (pStart == pEnd) PetscFunctionReturn(0);
7410   }
7411   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7412   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7413   /* We should have a generic GetLabel() and a Label class */
7414   while (next) {
7415     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7416     if (flg) break;
7417     next = next->next;
7418   }
7419   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7420   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7421   if ((depth < 0) || (depth >= next->numStrata)) {
7422     if (start) *start = 0;
7423     if (end)   *end   = 0;
7424   } else {
7425     if (start) *start = next->points[next->stratumOffsets[depth]];
7426     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7427   }
7428   PetscFunctionReturn(0);
7429 }
7430 
7431 #undef __FUNCT__
7432 #define __FUNCT__ "DMPlexCreateSectionInitial"
7433 /* Set the number of dof on each point and separate by fields */
7434 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7435 {
7436   PetscInt      *numDofTot;
7437   PetscInt       pStart = 0, pEnd = 0;
7438   PetscInt       p, d, f;
7439   PetscErrorCode ierr;
7440 
7441   PetscFunctionBegin;
7442   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7443   for (d = 0; d <= dim; ++d) {
7444     numDofTot[d] = 0;
7445     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7446   }
7447   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7448   if (numFields > 0) {
7449     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7450     if (numComp) {
7451       for (f = 0; f < numFields; ++f) {
7452         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7453       }
7454     }
7455   }
7456   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7457   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7458   for (d = 0; d <= dim; ++d) {
7459     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7460     for (p = pStart; p < pEnd; ++p) {
7461       for (f = 0; f < numFields; ++f) {
7462         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7463       }
7464       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7465     }
7466   }
7467   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7468   PetscFunctionReturn(0);
7469 }
7470 
7471 #undef __FUNCT__
7472 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7473 /* Set the number of dof on each point and separate by fields
7474    If constDof is PETSC_DETERMINE, constrain every dof on the point
7475 */
7476 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7477 {
7478   PetscInt       numFields;
7479   PetscInt       bc;
7480   PetscErrorCode ierr;
7481 
7482   PetscFunctionBegin;
7483   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7484   for (bc = 0; bc < numBC; ++bc) {
7485     PetscInt        field = 0;
7486     const PetscInt *idx;
7487     PetscInt        n, i;
7488 
7489     if (numFields) field = bcField[bc];
7490     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7491     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7492     for (i = 0; i < n; ++i) {
7493       const PetscInt p        = idx[i];
7494       PetscInt       numConst = constDof;
7495 
7496       /* Constrain every dof on the point */
7497       if (numConst < 0) {
7498         if (numFields) {
7499           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7500         } else {
7501           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7502         }
7503       }
7504       if (numFields) {
7505         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7506       }
7507       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7508     }
7509     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7510   }
7511   PetscFunctionReturn(0);
7512 }
7513 
7514 #undef __FUNCT__
7515 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7516 /* Set the constrained indices on each point and separate by fields */
7517 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7518 {
7519   PetscInt      *maxConstraints;
7520   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7521   PetscErrorCode ierr;
7522 
7523   PetscFunctionBegin;
7524   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7525   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7526   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7527   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7528   for (p = pStart; p < pEnd; ++p) {
7529     PetscInt cdof;
7530 
7531     if (numFields) {
7532       for (f = 0; f < numFields; ++f) {
7533         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7534         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7535       }
7536     } else {
7537       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7538       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7539     }
7540   }
7541   for (f = 0; f < numFields; ++f) {
7542     maxConstraints[numFields] += maxConstraints[f];
7543   }
7544   if (maxConstraints[numFields]) {
7545     PetscInt *indices;
7546 
7547     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7548     for (p = pStart; p < pEnd; ++p) {
7549       PetscInt cdof, d;
7550 
7551       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7552       if (cdof) {
7553         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7554         if (numFields) {
7555           PetscInt numConst = 0, foff = 0;
7556 
7557           for (f = 0; f < numFields; ++f) {
7558             PetscInt cfdof, fdof;
7559 
7560             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7561             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7562             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7563             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7564             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7565             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7566             numConst += cfdof;
7567             foff     += fdof;
7568           }
7569           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7570         } else {
7571           for (d = 0; d < cdof; ++d) indices[d] = d;
7572         }
7573         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7574       }
7575     }
7576     ierr = PetscFree(indices);CHKERRQ(ierr);
7577   }
7578   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7579   PetscFunctionReturn(0);
7580 }
7581 
7582 #undef __FUNCT__
7583 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7584 /* Set the constrained field indices on each point */
7585 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7586 {
7587   const PetscInt *points, *indices;
7588   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7589   PetscErrorCode  ierr;
7590 
7591   PetscFunctionBegin;
7592   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7593   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7594 
7595   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7596   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7597   if (!constraintIndices) {
7598     PetscInt *idx, i;
7599 
7600     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7601     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7602     for (i = 0; i < maxDof; ++i) idx[i] = i;
7603     for (p = 0; p < numPoints; ++p) {
7604       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7605     }
7606     ierr = PetscFree(idx);CHKERRQ(ierr);
7607   } else {
7608     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7609     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7610     for (p = 0; p < numPoints; ++p) {
7611       PetscInt fcdof;
7612 
7613       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7614       if (fcdof != numConstraints) SETERRQ4(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
7615       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7616     }
7617     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7618   }
7619   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7620   PetscFunctionReturn(0);
7621 }
7622 
7623 #undef __FUNCT__
7624 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7625 /* Set the constrained indices on each point and separate by fields */
7626 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7627 {
7628   PetscInt      *indices;
7629   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7630   PetscErrorCode ierr;
7631 
7632   PetscFunctionBegin;
7633   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7634   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7635   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7636   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7637   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7638   for (p = pStart; p < pEnd; ++p) {
7639     PetscInt cdof, d;
7640 
7641     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7642     if (cdof) {
7643       PetscInt numConst = 0, foff = 0;
7644 
7645       for (f = 0; f < numFields; ++f) {
7646         const PetscInt *fcind;
7647         PetscInt        fdof, fcdof;
7648 
7649         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7650         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7651         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7652         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7653         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
7654         foff     += fdof;
7655         numConst += fcdof;
7656       }
7657       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7658       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7659     }
7660   }
7661   ierr = PetscFree(indices);CHKERRQ(ierr);
7662   PetscFunctionReturn(0);
7663 }
7664 
7665 #undef __FUNCT__
7666 #define __FUNCT__ "DMPlexCreateSection"
7667 /*@C
7668   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7669 
7670   Not Collective
7671 
7672   Input Parameters:
7673 + dm        - The DMPlex object
7674 . dim       - The spatial dimension of the problem
7675 . numFields - The number of fields in the problem
7676 . numComp   - An array of size numFields that holds the number of components for each field
7677 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7678 . numBC     - The number of boundary conditions
7679 . bcField   - An array of size numBC giving the field number for each boundry condition
7680 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7681 
7682   Output Parameter:
7683 . section - The PetscSection object
7684 
7685   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
7686   nubmer of dof for field 0 on each edge.
7687 
7688   Level: developer
7689 
7690 .keywords: mesh, elements
7691 .seealso: DMPlexCreate(), PetscSectionCreate()
7692 @*/
7693 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
7694 {
7695   PetscErrorCode ierr;
7696 
7697   PetscFunctionBegin;
7698   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7699   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7700   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7701   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7702   {
7703     PetscBool view = PETSC_FALSE;
7704 
7705     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7706     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7707   }
7708   PetscFunctionReturn(0);
7709 }
7710 
7711 #undef __FUNCT__
7712 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7713 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
7714 {
7715   PetscSection   section;
7716   PetscErrorCode ierr;
7717 
7718   PetscFunctionBegin;
7719   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7720   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7721   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7722   ierr = PetscSectionDestroy(&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 {
7746   DM             cdm;
7747   PetscErrorCode ierr;
7748 
7749   PetscFunctionBegin;
7750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7751   PetscValidPointer(section, 2);
7752   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7753   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7754   PetscFunctionReturn(0);
7755 }
7756 
7757 #undef __FUNCT__
7758 #define __FUNCT__ "DMPlexSetCoordinateSection"
7759 /*@
7760   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7761 
7762   Not Collective
7763 
7764   Input Parameters:
7765 + dm      - The DMPlex object
7766 - section - The PetscSection object
7767 
7768   Level: intermediate
7769 
7770 .keywords: mesh, coordinates
7771 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7772 @*/
7773 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
7774 {
7775   DM             cdm;
7776   PetscErrorCode ierr;
7777 
7778   PetscFunctionBegin;
7779   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7780   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
7781   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7782   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7783   PetscFunctionReturn(0);
7784 }
7785 
7786 #undef __FUNCT__
7787 #define __FUNCT__ "DMPlexGetConeSection"
7788 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
7789 {
7790   DM_Plex *mesh = (DM_Plex*) dm->data;
7791 
7792   PetscFunctionBegin;
7793   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7794   if (section) *section = mesh->coneSection;
7795   PetscFunctionReturn(0);
7796 }
7797 
7798 #undef __FUNCT__
7799 #define __FUNCT__ "DMPlexGetCones"
7800 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
7801 {
7802   DM_Plex *mesh = (DM_Plex*) dm->data;
7803 
7804   PetscFunctionBegin;
7805   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7806   if (cones) *cones = mesh->cones;
7807   PetscFunctionReturn(0);
7808 }
7809 
7810 #undef __FUNCT__
7811 #define __FUNCT__ "DMPlexGetConeOrientations"
7812 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
7813 {
7814   DM_Plex *mesh = (DM_Plex*) dm->data;
7815 
7816   PetscFunctionBegin;
7817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7818   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7819   PetscFunctionReturn(0);
7820 }
7821 
7822 #undef __FUNCT__
7823 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7824 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7825 {
7826   const PetscInt embedDim = 2;
7827   PetscReal      x        = PetscRealPart(point[0]);
7828   PetscReal      y        = PetscRealPart(point[1]);
7829   PetscReal      v0[2], J[4], invJ[4], detJ;
7830   PetscReal      xi, eta;
7831   PetscErrorCode ierr;
7832 
7833   PetscFunctionBegin;
7834   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7835   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7836   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7837 
7838   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
7839   else *cell = -1;
7840   PetscFunctionReturn(0);
7841 }
7842 
7843 #undef __FUNCT__
7844 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7845 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7846 {
7847   PetscSection       coordSection;
7848   Vec                coordsLocal;
7849   const PetscScalar *coords;
7850   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7851   PetscReal          x         = PetscRealPart(point[0]);
7852   PetscReal          y         = PetscRealPart(point[1]);
7853   PetscInt           crossings = 0, f;
7854   PetscErrorCode     ierr;
7855 
7856   PetscFunctionBegin;
7857   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7858   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7859   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7860   for (f = 0; f < 4; ++f) {
7861     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7862     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7863     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7864     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7865     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7866     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7867     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7868     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7869     if ((cond1 || cond2)  && above) ++crossings;
7870   }
7871   if (crossings % 2) *cell = c;
7872   else *cell = -1;
7873   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, 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)) *cell = c;
7896   else *cell = -1;
7897   PetscFunctionReturn(0);
7898 }
7899 
7900 #undef __FUNCT__
7901 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7902 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7903 {
7904   PetscSection       coordSection;
7905   Vec                coordsLocal;
7906   const PetscScalar *coords;
7907   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7908                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7909   PetscBool          found = PETSC_TRUE;
7910   PetscInt           f;
7911   PetscErrorCode     ierr;
7912 
7913   PetscFunctionBegin;
7914   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7915   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7916   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7917   for (f = 0; f < 6; ++f) {
7918     /* Check the point is under plane */
7919     /*   Get face normal */
7920     PetscReal v_i[3];
7921     PetscReal v_j[3];
7922     PetscReal normal[3];
7923     PetscReal pp[3];
7924     PetscReal dot;
7925 
7926     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
7927     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
7928     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
7929     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
7930     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
7931     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
7932     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
7933     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
7934     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
7935     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
7936     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
7937     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
7938     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7939 
7940     /* Check that projected point is in face (2D location problem) */
7941     if (dot < 0.0) {
7942       found = PETSC_FALSE;
7943       break;
7944     }
7945   }
7946   if (found) *cell = c;
7947   else *cell = -1;
7948   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7949   PetscFunctionReturn(0);
7950 }
7951 
7952 #undef __FUNCT__
7953 #define __FUNCT__ "DMLocatePoints_Plex"
7954 /*
7955  Need to implement using the guess
7956 */
7957 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7958 {
7959   PetscInt       cell = -1 /*, guess = -1*/;
7960   PetscInt       bs, numPoints, p;
7961   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7962   PetscInt      *cells;
7963   PetscScalar   *a;
7964   PetscErrorCode ierr;
7965 
7966   PetscFunctionBegin;
7967   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7968   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7969   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7970   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7971   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7972   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7973   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7974   if (bs != dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
7975   numPoints /= bs;
7976   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7977   for (p = 0; p < numPoints; ++p) {
7978     const PetscScalar *point = &a[p*bs];
7979 
7980     switch (dim) {
7981     case 2:
7982       for (c = cStart; c < cEnd; ++c) {
7983         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7984         switch (coneSize) {
7985         case 3:
7986           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7987           break;
7988         case 4:
7989           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7990           break;
7991         default:
7992           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7993         }
7994         if (cell >= 0) break;
7995       }
7996       break;
7997     case 3:
7998       for (c = cStart; c < cEnd; ++c) {
7999         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8000         switch (coneSize) {
8001         case 4:
8002           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8003           break;
8004         case 8:
8005           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8006           break;
8007         default:
8008           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8009         }
8010         if (cell >= 0) break;
8011       }
8012       break;
8013     default:
8014       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8015     }
8016     cells[p] = cell;
8017   }
8018   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8019   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8020   PetscFunctionReturn(0);
8021 }
8022 
8023 /******************************** FEM Support **********************************/
8024 
8025 #undef __FUNCT__
8026 #define __FUNCT__ "DMPlexVecGetClosure"
8027 /*@C
8028   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8029 
8030   Not collective
8031 
8032   Input Parameters:
8033 + dm - The DM
8034 . section - The section describing the layout in v, or NULL to use the default section
8035 . v - The local vector
8036 - point - The sieve point in the DM
8037 
8038   Output Parameters:
8039 + csize - The number of values in the closure, or NULL
8040 - values - The array of values, which is a borrowed array and should not be freed
8041 
8042   Level: intermediate
8043 
8044 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8045 @*/
8046 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8047 {
8048   PetscScalar   *array, *vArray;
8049   PetscInt      *points = NULL;
8050   PetscInt       offsets[32];
8051   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8052   PetscErrorCode ierr;
8053 
8054   PetscFunctionBegin;
8055   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8056   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8057   if (!section) {
8058     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8059   }
8060   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8061   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8062   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8063   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8064   /* Compress out points not in the section */
8065   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8066   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8067     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8068       points[q*2]   = points[p];
8069       points[q*2+1] = points[p+1];
8070       ++q;
8071     }
8072   }
8073   numPoints = q;
8074   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8075     PetscInt dof, fdof;
8076 
8077     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8078     for (f = 0; f < numFields; ++f) {
8079       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8080       offsets[f+1] += fdof;
8081     }
8082     size += dof;
8083   }
8084   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8085   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8086   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8087   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8088   for (p = 0; p < numPoints*2; p += 2) {
8089     PetscInt     o = points[p+1];
8090     PetscInt     dof, off, d;
8091     PetscScalar *varr;
8092 
8093     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8094     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8095     varr = &vArray[off];
8096     if (numFields) {
8097       PetscInt fdof, foff, fcomp, f, c;
8098 
8099       for (f = 0, foff = 0; f < numFields; ++f) {
8100         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8101         if (o >= 0) {
8102           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8103             array[offsets[f]] = varr[foff+d];
8104           }
8105         } else {
8106           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8107           for (d = fdof/fcomp-1; d >= 0; --d) {
8108             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8109               array[offsets[f]] = varr[foff+d*fcomp+c];
8110             }
8111           }
8112         }
8113         foff += fdof;
8114       }
8115     } else {
8116       if (o >= 0) {
8117         for (d = 0; d < dof; ++d, ++offsets[0]) {
8118           array[offsets[0]] = varr[d];
8119         }
8120       } else {
8121         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8122           array[offsets[0]] = varr[d];
8123         }
8124       }
8125     }
8126   }
8127   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8128   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8129   if (csize) *csize = size;
8130   *values = array;
8131   PetscFunctionReturn(0);
8132 }
8133 
8134 #undef __FUNCT__
8135 #define __FUNCT__ "DMPlexVecRestoreClosure"
8136 /*@C
8137   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8138 
8139   Not collective
8140 
8141   Input Parameters:
8142 + dm - The DM
8143 . section - The section describing the layout in v, or NULL to use the default section
8144 . v - The local vector
8145 . point - The sieve point in the DM
8146 . csize - The number of values in the closure, or NULL
8147 - values - The array of values, which is a borrowed array and should not be freed
8148 
8149   Level: intermediate
8150 
8151 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8152 @*/
8153 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8154 {
8155   PetscInt       size = 0;
8156   PetscErrorCode ierr;
8157 
8158   PetscFunctionBegin;
8159   /* Should work without recalculating size */
8160   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8161   PetscFunctionReturn(0);
8162 }
8163 
8164 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8165 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8166 
8167 #undef __FUNCT__
8168 #define __FUNCT__ "updatePoint_private"
8169 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8170 {
8171   PetscInt        cdof;   /* The number of constraints on this point */
8172   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8173   PetscScalar    *a;
8174   PetscInt        off, cind = 0, k;
8175   PetscErrorCode  ierr;
8176 
8177   PetscFunctionBegin;
8178   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8179   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8180   a    = &array[off];
8181   if (!cdof || setBC) {
8182     if (orientation >= 0) {
8183       for (k = 0; k < dof; ++k) {
8184         fuse(&a[k], values[k]);
8185       }
8186     } else {
8187       for (k = 0; k < dof; ++k) {
8188         fuse(&a[k], values[dof-k-1]);
8189       }
8190     }
8191   } else {
8192     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8193     if (orientation >= 0) {
8194       for (k = 0; k < dof; ++k) {
8195         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8196         fuse(&a[k], values[k]);
8197       }
8198     } else {
8199       for (k = 0; k < dof; ++k) {
8200         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8201         fuse(&a[k], values[dof-k-1]);
8202       }
8203     }
8204   }
8205   PetscFunctionReturn(0);
8206 }
8207 
8208 #undef __FUNCT__
8209 #define __FUNCT__ "updatePointFields_private"
8210 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8211 {
8212   PetscScalar   *a;
8213   PetscInt       numFields, off, foff, f;
8214   PetscErrorCode ierr;
8215 
8216   PetscFunctionBegin;
8217   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8218   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8219   a    = &array[off];
8220   for (f = 0, foff = 0; f < numFields; ++f) {
8221     PetscInt        fdof, fcomp, fcdof;
8222     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8223     PetscInt        cind = 0, k, c;
8224 
8225     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8226     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8227     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8228     if (!fcdof || setBC) {
8229       if (orientation >= 0) {
8230         for (k = 0; k < fdof; ++k) {
8231           fuse(&a[foff+k], values[foffs[f]+k]);
8232         }
8233       } else {
8234         for (k = fdof/fcomp-1; k >= 0; --k) {
8235           for (c = 0; c < fcomp; ++c) {
8236             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8237           }
8238         }
8239       }
8240     } else {
8241       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8242       if (orientation >= 0) {
8243         for (k = 0; k < fdof; ++k) {
8244           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8245           fuse(&a[foff+k], values[foffs[f]+k]);
8246         }
8247       } else {
8248         for (k = fdof/fcomp-1; k >= 0; --k) {
8249           for (c = 0; c < fcomp; ++c) {
8250             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8251             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8252           }
8253         }
8254       }
8255     }
8256     foff     += fdof;
8257     foffs[f] += fdof;
8258   }
8259   PetscFunctionReturn(0);
8260 }
8261 
8262 #undef __FUNCT__
8263 #define __FUNCT__ "DMPlexVecSetClosure"
8264 /*@C
8265   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8266 
8267   Not collective
8268 
8269   Input Parameters:
8270 + dm - The DM
8271 . section - The section describing the layout in v, or NULL to use the default sectionw
8272 . v - The local vector
8273 . point - The sieve point in the DM
8274 . values - The array of values, which is a borrowed array and should not be freed
8275 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8276 
8277   Level: intermediate
8278 
8279 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8280 @*/
8281 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8282 {
8283   PetscScalar   *array;
8284   PetscInt      *points = NULL;
8285   PetscInt       offsets[32];
8286   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8287   PetscErrorCode ierr;
8288 
8289   PetscFunctionBegin;
8290   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8291   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8292   if (!section) {
8293     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8294   }
8295   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8296   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8297   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8298   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8299   /* Compress out points not in the section */
8300   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8301   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8302     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8303       points[q*2]   = points[p];
8304       points[q*2+1] = points[p+1];
8305       ++q;
8306     }
8307   }
8308   numPoints = q;
8309   for (p = 0; p < numPoints*2; p += 2) {
8310     PetscInt fdof;
8311 
8312     for (f = 0; f < numFields; ++f) {
8313       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8314       offsets[f+1] += fdof;
8315     }
8316   }
8317   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8318   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8319   if (numFields) {
8320     switch (mode) {
8321     case INSERT_VALUES:
8322       for (p = 0; p < numPoints*2; p += 2) {
8323         PetscInt o = points[p+1];
8324         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8325       } break;
8326     case INSERT_ALL_VALUES:
8327       for (p = 0; p < numPoints*2; p += 2) {
8328         PetscInt o = points[p+1];
8329         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8330       } break;
8331     case ADD_VALUES:
8332       for (p = 0; p < numPoints*2; p += 2) {
8333         PetscInt o = points[p+1];
8334         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8335       } break;
8336     case ADD_ALL_VALUES:
8337       for (p = 0; p < numPoints*2; p += 2) {
8338         PetscInt o = points[p+1];
8339         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8340       } break;
8341     default:
8342       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8343     }
8344   } else {
8345     switch (mode) {
8346     case INSERT_VALUES:
8347       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8348         PetscInt o = points[p+1];
8349         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8350         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8351       } break;
8352     case INSERT_ALL_VALUES:
8353       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8354         PetscInt o = points[p+1];
8355         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8356         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8357       } break;
8358     case ADD_VALUES:
8359       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8360         PetscInt o = points[p+1];
8361         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8362         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8363       } break;
8364     case ADD_ALL_VALUES:
8365       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8366         PetscInt o = points[p+1];
8367         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8368         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8369       } break;
8370     default:
8371       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8372     }
8373   }
8374   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8375   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8376   PetscFunctionReturn(0);
8377 }
8378 
8379 #undef __FUNCT__
8380 #define __FUNCT__ "DMPlexPrintMatSetValues"
8381 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8382 {
8383   PetscMPIInt    rank;
8384   PetscInt       i, j;
8385   PetscErrorCode ierr;
8386 
8387   PetscFunctionBegin;
8388   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8389   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8390   for (i = 0; i < numIndices; i++) {
8391     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8392   }
8393   for (i = 0; i < numIndices; i++) {
8394     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8395     for (j = 0; j < numIndices; j++) {
8396 #if defined(PETSC_USE_COMPLEX)
8397       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8398 #else
8399       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8400 #endif
8401     }
8402     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8403   }
8404   PetscFunctionReturn(0);
8405 }
8406 
8407 #undef __FUNCT__
8408 #define __FUNCT__ "indicesPoint_private"
8409 /* . off - The global offset of this point */
8410 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8411 {
8412   PetscInt        dof;    /* The number of unknowns on this point */
8413   PetscInt        cdof;   /* The number of constraints on this point */
8414   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8415   PetscInt        cind = 0, k;
8416   PetscErrorCode  ierr;
8417 
8418   PetscFunctionBegin;
8419   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8420   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8421   if (!cdof || setBC) {
8422     if (orientation >= 0) {
8423       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8424     } else {
8425       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8426     }
8427   } else {
8428     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8429     if (orientation >= 0) {
8430       for (k = 0; k < dof; ++k) {
8431         if ((cind < cdof) && (k == cdofs[cind])) {
8432           /* Insert check for returning constrained indices */
8433           indices[*loff+k] = -(off+k+1);
8434           ++cind;
8435         } else {
8436           indices[*loff+k] = off+k-cind;
8437         }
8438       }
8439     } else {
8440       for (k = 0; k < dof; ++k) {
8441         if ((cind < cdof) && (k == cdofs[cind])) {
8442           /* Insert check for returning constrained indices */
8443           indices[*loff+dof-k-1] = -(off+k+1);
8444           ++cind;
8445         } else {
8446           indices[*loff+dof-k-1] = off+k-cind;
8447         }
8448       }
8449     }
8450   }
8451   *loff += dof;
8452   PetscFunctionReturn(0);
8453 }
8454 
8455 #undef __FUNCT__
8456 #define __FUNCT__ "indicesPointFields_private"
8457 /* . off - The global offset of this point */
8458 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8459 {
8460   PetscInt       numFields, foff, f;
8461   PetscErrorCode ierr;
8462 
8463   PetscFunctionBegin;
8464   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8465   for (f = 0, foff = 0; f < numFields; ++f) {
8466     PetscInt        fdof, fcomp, cfdof;
8467     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8468     PetscInt        cind = 0, k, c;
8469 
8470     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8471     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8472     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8473     if (!cfdof || setBC) {
8474       if (orientation >= 0) {
8475         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8476       } else {
8477         for (k = fdof/fcomp-1; k >= 0; --k) {
8478           for (c = 0; c < fcomp; ++c) {
8479             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8480           }
8481         }
8482       }
8483     } else {
8484       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8485       if (orientation >= 0) {
8486         for (k = 0; k < fdof; ++k) {
8487           if ((cind < cfdof) && (k == fcdofs[cind])) {
8488             indices[foffs[f]+k] = -(off+foff+k+1);
8489             ++cind;
8490           } else {
8491             indices[foffs[f]+k] = off+foff+k-cind;
8492           }
8493         }
8494       } else {
8495         for (k = fdof/fcomp-1; k >= 0; --k) {
8496           for (c = 0; c < fcomp; ++c) {
8497             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8498               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8499               ++cind;
8500             } else {
8501               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8502             }
8503           }
8504         }
8505       }
8506     }
8507     foff     += fdof - cfdof;
8508     foffs[f] += fdof;
8509   }
8510   PetscFunctionReturn(0);
8511 }
8512 
8513 #undef __FUNCT__
8514 #define __FUNCT__ "DMPlexMatSetClosure"
8515 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8516 {
8517   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8518   PetscInt      *points = NULL;
8519   PetscInt      *indices;
8520   PetscInt       offsets[32];
8521   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8522   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8523   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8524   PetscErrorCode ierr;
8525 
8526   PetscFunctionBegin;
8527   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8528   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8529   if (useDefault) {
8530     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8531   }
8532   if (useGlobalDefault) {
8533     if (useDefault) {
8534       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8535     } else {
8536       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8537     }
8538   }
8539   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8540   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8541   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8542   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8543   /* Compress out points not in the section */
8544   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8545   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8546     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8547       points[q*2]   = points[p];
8548       points[q*2+1] = points[p+1];
8549       ++q;
8550     }
8551   }
8552   numPoints = q;
8553   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8554     PetscInt fdof;
8555 
8556     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8557     for (f = 0; f < numFields; ++f) {
8558       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8559       offsets[f+1] += fdof;
8560     }
8561     numIndices += dof;
8562   }
8563   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8564 
8565   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), 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) {
8575       PetscInt o = points[p+1];
8576       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8577       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
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(PetscObjectComm((PetscObject)A), &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, NULL, &coords);CHKERRQ(ierr);
8615   if (v0) {
8616     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8617   }
8618   if (J) {
8619     for (d = 0; d < dim; d++) {
8620       for (f = 0; f < dim; f++) {
8621         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8622       }
8623     }
8624     *detJ = J[0]*J[3] - J[1]*J[2];
8625 #if 0
8626     if (detJ < 0.0) {
8627       const PetscReal xLength = mesh->periodicity[0];
8628 
8629       if (xLength != 0.0) {
8630         PetscReal v0x = coords[0*dim+0];
8631 
8632         if (v0x == 0.0) v0x = v0[0] = xLength;
8633         for (f = 0; f < dim; f++) {
8634           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8635 
8636           J[0*dim+f] = 0.5*(px - v0x);
8637         }
8638       }
8639       detJ = J[0]*J[3] - J[1]*J[2];
8640     }
8641 #endif
8642     PetscLogFlops(8.0 + 3.0);
8643   }
8644   if (invJ) {
8645     const PetscReal invDet = 1.0/(*detJ);
8646 
8647     invJ[0] =  invDet*J[3];
8648     invJ[1] = -invDet*J[1];
8649     invJ[2] = -invDet*J[2];
8650     invJ[3] =  invDet*J[0];
8651     PetscLogFlops(5.0);
8652   }
8653   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8654   PetscFunctionReturn(0);
8655 }
8656 
8657 #undef __FUNCT__
8658 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8659 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8660 {
8661   PetscSection       coordSection;
8662   Vec                coordinates;
8663   const PetscScalar *coords;
8664   const PetscInt     dim = 2;
8665   PetscInt           d, f;
8666   PetscErrorCode     ierr;
8667 
8668   PetscFunctionBegin;
8669   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8670   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8671   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8672   if (v0) {
8673     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8674   }
8675   if (J) {
8676     for (d = 0; d < dim; d++) {
8677       for (f = 0; f < dim; f++) {
8678         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8679       }
8680     }
8681     *detJ = J[0]*J[3] - J[1]*J[2];
8682     PetscLogFlops(8.0 + 3.0);
8683   }
8684   if (invJ) {
8685     const PetscReal invDet = 1.0/(*detJ);
8686 
8687     invJ[0] =  invDet*J[3];
8688     invJ[1] = -invDet*J[1];
8689     invJ[2] = -invDet*J[2];
8690     invJ[3] =  invDet*J[0];
8691     PetscLogFlops(5.0);
8692   }
8693   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8694   PetscFunctionReturn(0);
8695 }
8696 
8697 #undef __FUNCT__
8698 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8699 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8700 {
8701   PetscSection       coordSection;
8702   Vec                coordinates;
8703   const PetscScalar *coords;
8704   const PetscInt     dim = 3;
8705   PetscInt           d, f;
8706   PetscErrorCode     ierr;
8707 
8708   PetscFunctionBegin;
8709   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8710   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8711   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8712   if (v0) {
8713     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8714   }
8715   if (J) {
8716     for (d = 0; d < dim; d++) {
8717       for (f = 0; f < dim; f++) {
8718         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8719       }
8720     }
8721     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8722     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8723              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8724              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8725     PetscLogFlops(18.0 + 12.0);
8726   }
8727   if (invJ) {
8728     const PetscReal invDet = 1.0/(*detJ);
8729 
8730     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8731     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8732     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8733     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8734     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8735     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8736     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8737     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8738     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8739     PetscLogFlops(37.0);
8740   }
8741   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8742   PetscFunctionReturn(0);
8743 }
8744 
8745 #undef __FUNCT__
8746 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8747 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8748 {
8749   PetscSection       coordSection;
8750   Vec                coordinates;
8751   const PetscScalar *coords;
8752   const PetscInt     dim = 3;
8753   PetscInt           d;
8754   PetscErrorCode     ierr;
8755 
8756   PetscFunctionBegin;
8757   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8758   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8759   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8760   if (v0) {
8761     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8762   }
8763   if (J) {
8764     for (d = 0; d < dim; d++) {
8765       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8766       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8767       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8768     }
8769     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8770              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8771              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8772     PetscLogFlops(18.0 + 12.0);
8773   }
8774   if (invJ) {
8775     const PetscReal invDet = -1.0/(*detJ);
8776 
8777     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8778     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8779     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8780     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8781     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8782     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8783     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8784     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8785     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8786     PetscLogFlops(37.0);
8787   }
8788   *detJ *= 8.0;
8789   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8790   PetscFunctionReturn(0);
8791 }
8792 
8793 #undef __FUNCT__
8794 #define __FUNCT__ "DMPlexComputeCellGeometry"
8795 /*@C
8796   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8797 
8798   Collective on DM
8799 
8800   Input Arguments:
8801 + dm   - the DM
8802 - cell - the cell
8803 
8804   Output Arguments:
8805 + v0   - the translation part of this affine transform
8806 . J    - the Jacobian of the transform to the reference element
8807 . invJ - the inverse of the Jacobian
8808 - detJ - the Jacobian determinant
8809 
8810   Level: advanced
8811 
8812 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8813 @*/
8814 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
8815 {
8816   PetscInt       dim, coneSize;
8817   PetscErrorCode ierr;
8818 
8819   PetscFunctionBegin;
8820   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8821   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8822   switch (dim) {
8823   case 2:
8824     switch (coneSize) {
8825     case 3:
8826       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8827       break;
8828     case 4:
8829       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8830       break;
8831     default:
8832       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8833     }
8834     break;
8835   case 3:
8836     switch (coneSize) {
8837     case 4:
8838       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8839       break;
8840     case 8:
8841       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8842       break;
8843     default:
8844       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8845     }
8846     break;
8847   default:
8848     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8849   }
8850   PetscFunctionReturn(0);
8851 }
8852 
8853 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8854 {
8855   switch (i) {
8856   case 0:
8857     switch (j) {
8858     case 0: return 0;
8859     case 1:
8860       switch (k) {
8861       case 0: return 0;
8862       case 1: return 0;
8863       case 2: return 1;
8864       }
8865     case 2:
8866       switch (k) {
8867       case 0: return 0;
8868       case 1: return -1;
8869       case 2: return 0;
8870       }
8871     }
8872   case 1:
8873     switch (j) {
8874     case 0:
8875       switch (k) {
8876       case 0: return 0;
8877       case 1: return 0;
8878       case 2: return -1;
8879       }
8880     case 1: return 0;
8881     case 2:
8882       switch (k) {
8883       case 0: return 1;
8884       case 1: return 0;
8885       case 2: return 0;
8886       }
8887     }
8888   case 2:
8889     switch (j) {
8890     case 0:
8891       switch (k) {
8892       case 0: return 0;
8893       case 1: return 1;
8894       case 2: return 0;
8895       }
8896     case 1:
8897       switch (k) {
8898       case 0: return -1;
8899       case 1: return 0;
8900       case 2: return 0;
8901       }
8902     case 2: return 0;
8903     }
8904   }
8905   return 0;
8906 }
8907 
8908 #undef __FUNCT__
8909 #define __FUNCT__ "DMPlexCreateRigidBody"
8910 /*@C
8911   DMPlexCreateRigidBody - create rigid body modes from coordinates
8912 
8913   Collective on DM
8914 
8915   Input Arguments:
8916 + dm - the DM
8917 . section - the local section associated with the rigid field, or NULL for the default section
8918 - globalSection - the global section associated with the rigid field, or NULL for the default section
8919 
8920   Output Argument:
8921 . sp - the null space
8922 
8923   Note: This is necessary to take account of Dirichlet conditions on the displacements
8924 
8925   Level: advanced
8926 
8927 .seealso: MatNullSpaceCreate()
8928 @*/
8929 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8930 {
8931   MPI_Comm       comm;
8932   Vec            coordinates, localMode, mode[6];
8933   PetscSection   coordSection;
8934   PetscScalar   *coords;
8935   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8936   PetscErrorCode ierr;
8937 
8938   PetscFunctionBegin;
8939   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
8940   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8941   if (dim == 1) {
8942     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
8943     PetscFunctionReturn(0);
8944   }
8945   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8946   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8947   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8948   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8949   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8950   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8951   m    = (dim*(dim+1))/2;
8952   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8953   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8954   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8955   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8956   /* Assume P1 */
8957   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8958   for (d = 0; d < dim; ++d) {
8959     PetscScalar values[3] = {0.0, 0.0, 0.0};
8960 
8961     values[d] = 1.0;
8962     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
8963     for (v = vStart; v < vEnd; ++v) {
8964       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8965     }
8966     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8967     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8968   }
8969   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8970   for (d = dim; d < dim*(dim+1)/2; ++d) {
8971     PetscInt i, j, k = dim > 2 ? d - dim : d;
8972 
8973     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8974     for (v = vStart; v < vEnd; ++v) {
8975       PetscScalar values[3] = {0.0, 0.0, 0.0};
8976       PetscInt    off;
8977 
8978       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8979       for (i = 0; i < dim; ++i) {
8980         for (j = 0; j < dim; ++j) {
8981           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8982         }
8983       }
8984       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8985     }
8986     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8987     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8988   }
8989   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8990   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8991   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
8992   /* Orthonormalize system */
8993   for (i = dim; i < m; ++i) {
8994     PetscScalar dots[6];
8995 
8996     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8997     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8998     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8999     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
9000   }
9001   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9002   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9003   PetscFunctionReturn(0);
9004 }
9005 
9006 #undef __FUNCT__
9007 #define __FUNCT__ "DMPlexGetHybridBounds"
9008 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9009 {
9010   DM_Plex       *mesh = (DM_Plex*) dm->data;
9011   PetscInt       dim;
9012   PetscErrorCode ierr;
9013 
9014   PetscFunctionBegin;
9015   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9016   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9017   if (cMax) *cMax = mesh->hybridPointMax[dim];
9018   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9019   if (eMax) *eMax = mesh->hybridPointMax[1];
9020   if (vMax) *vMax = mesh->hybridPointMax[0];
9021   PetscFunctionReturn(0);
9022 }
9023 
9024 #undef __FUNCT__
9025 #define __FUNCT__ "DMPlexSetHybridBounds"
9026 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9027 {
9028   DM_Plex       *mesh = (DM_Plex*) dm->data;
9029   PetscInt       dim;
9030   PetscErrorCode ierr;
9031 
9032   PetscFunctionBegin;
9033   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9034   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9035   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9036   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9037   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9038   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9039   PetscFunctionReturn(0);
9040 }
9041 
9042 #undef __FUNCT__
9043 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9044 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9045 {
9046   DM_Plex *mesh = (DM_Plex*) dm->data;
9047 
9048   PetscFunctionBegin;
9049   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9050   PetscValidPointer(cellHeight, 2);
9051   *cellHeight = mesh->vtkCellHeight;
9052   PetscFunctionReturn(0);
9053 }
9054 
9055 #undef __FUNCT__
9056 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9057 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9058 {
9059   DM_Plex *mesh = (DM_Plex*) dm->data;
9060 
9061   PetscFunctionBegin;
9062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9063   mesh->vtkCellHeight = cellHeight;
9064   PetscFunctionReturn(0);
9065 }
9066 
9067 #undef __FUNCT__
9068 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9069 /* We can easily have a form that takes an IS instead */
9070 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9071 {
9072   PetscSection   section, globalSection;
9073   PetscInt      *numbers, p;
9074   PetscErrorCode ierr;
9075 
9076   PetscFunctionBegin;
9077   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
9078   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9079   for (p = pStart; p < pEnd; ++p) {
9080     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9081   }
9082   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9083   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9084   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9085   for (p = pStart; p < pEnd; ++p) {
9086     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9087   }
9088   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9089   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9090   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9091   PetscFunctionReturn(0);
9092 }
9093 
9094 #undef __FUNCT__
9095 #define __FUNCT__ "DMPlexGetCellNumbering"
9096 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9097 {
9098   DM_Plex       *mesh = (DM_Plex*) dm->data;
9099   PetscInt       cellHeight, cStart, cEnd, cMax;
9100   PetscErrorCode ierr;
9101 
9102   PetscFunctionBegin;
9103   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9104   if (!mesh->globalCellNumbers) {
9105     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9106     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9107     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
9108     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9109     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9110   }
9111   *globalCellNumbers = mesh->globalCellNumbers;
9112   PetscFunctionReturn(0);
9113 }
9114 
9115 #undef __FUNCT__
9116 #define __FUNCT__ "DMPlexGetVertexNumbering"
9117 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9118 {
9119   DM_Plex       *mesh = (DM_Plex*) dm->data;
9120   PetscInt       vStart, vEnd, vMax;
9121   PetscErrorCode ierr;
9122 
9123   PetscFunctionBegin;
9124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9125   if (!mesh->globalVertexNumbers) {
9126     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9127     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9128     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9129     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9130   }
9131   *globalVertexNumbers = mesh->globalVertexNumbers;
9132   PetscFunctionReturn(0);
9133 }
9134 
9135 #undef __FUNCT__
9136 #define __FUNCT__ "DMPlexGetScale"
9137 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9138 {
9139   DM_Plex *mesh = (DM_Plex*) dm->data;
9140 
9141   PetscFunctionBegin;
9142   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9143   PetscValidPointer(scale, 3);
9144   *scale = mesh->scale[unit];
9145   PetscFunctionReturn(0);
9146 }
9147 
9148 #undef __FUNCT__
9149 #define __FUNCT__ "DMPlexSetScale"
9150 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9151 {
9152   DM_Plex *mesh = (DM_Plex*) dm->data;
9153 
9154   PetscFunctionBegin;
9155   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9156   mesh->scale[unit] = scale;
9157   PetscFunctionReturn(0);
9158 }
9159 
9160 
9161 /*******************************************************************************
9162 This should be in a separate Discretization object, but I am not sure how to lay
9163 it out yet, so I am stuffing things here while I experiment.
9164 *******************************************************************************/
9165 #undef __FUNCT__
9166 #define __FUNCT__ "DMPlexSetFEMIntegration"
9167 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9168                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9169                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9170                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9171                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9172                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9173                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9174                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9175                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9176                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9177                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9178                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9179                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9180                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9181                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9182                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9183                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9184 {
9185   DM_Plex *mesh = (DM_Plex*) dm->data;
9186 
9187   PetscFunctionBegin;
9188   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9189   mesh->integrateResidualFEM       = integrateResidualFEM;
9190   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9191   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9192   PetscFunctionReturn(0);
9193 }
9194 
9195 #undef __FUNCT__
9196 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9197 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9198 {
9199   Vec            coordinates;
9200   PetscSection   section, cSection;
9201   PetscInt       dim, vStart, vEnd, v, c, d;
9202   PetscScalar   *values, *cArray;
9203   PetscReal     *coords;
9204   PetscErrorCode ierr;
9205 
9206   PetscFunctionBegin;
9207   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9208   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9209   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9210   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9211   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9212   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9213   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9214   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9215   for (v = vStart; v < vEnd; ++v) {
9216     PetscInt dof, off;
9217 
9218     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9219     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9220     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9221     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9222     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9223     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9224   }
9225   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9226   /* Temporary, must be replaced by a projection on the finite element basis */
9227   {
9228     PetscInt eStart = 0, eEnd = 0, e, depth;
9229 
9230     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9231     --depth;
9232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9233     for (e = eStart; e < eEnd; ++e) {
9234       const PetscInt *cone = NULL;
9235       PetscInt        coneSize, d;
9236       PetscScalar    *coordsA, *coordsB;
9237 
9238       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9240       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9241       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9242       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9243       for (d = 0; d < dim; ++d) {
9244         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9245       }
9246       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9247       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9248     }
9249   }
9250 
9251   ierr = PetscFree(coords);CHKERRQ(ierr);
9252   ierr = PetscFree(values);CHKERRQ(ierr);
9253 #if 0
9254   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9255   PetscReal      detJ;
9256 
9257   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9258   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9259   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9260 
9261   for (PetscInt c = cStart; c < cEnd; ++c) {
9262     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9263     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9264     const int                          oSize   = pV.getSize();
9265     int                                v       = 0;
9266 
9267     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9268     for (PetscInt cl = 0; cl < oSize; ++cl) {
9269       const PetscInt fDim;
9270 
9271       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9272       if (pointDim) {
9273         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9274           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9275         }
9276       }
9277     }
9278     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9279     pV.clear();
9280   }
9281   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9282   ierr = PetscFree(values);CHKERRQ(ierr);
9283 #endif
9284   PetscFunctionReturn(0);
9285 }
9286 
9287 #undef __FUNCT__
9288 #define __FUNCT__ "DMPlexProjectFunction"
9289 /*@C
9290   DMPlexProjectFunction - This projects the given function into the function space provided.
9291 
9292   Input Parameters:
9293 + dm      - The DM
9294 . numComp - The number of components (functions)
9295 . funcs   - The coordinate functions to evaluate
9296 - mode    - The insertion mode for values
9297 
9298   Output Parameter:
9299 . X - vector
9300 
9301   Level: developer
9302 
9303   Note:
9304   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9305   We will eventually fix it.
9306 
9307 ,seealso: DMPlexComputeL2Diff()
9308 */
9309 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9310 {
9311   Vec            localX;
9312   PetscErrorCode ierr;
9313 
9314   PetscFunctionBegin;
9315   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9316   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9317   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9318   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9319   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9320   PetscFunctionReturn(0);
9321 }
9322 
9323 #undef __FUNCT__
9324 #define __FUNCT__ "DMPlexComputeL2Diff"
9325 /*@C
9326   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9327 
9328   Input Parameters:
9329 + dm    - The DM
9330 . quad  - The PetscQuadrature object for each field
9331 . funcs - The functions to evaluate for each field component
9332 - X     - The coefficient vector u_h
9333 
9334   Output Parameter:
9335 . diff - The diff ||u - u_h||_2
9336 
9337   Level: developer
9338 
9339 .seealso: DMPlexProjectFunction()
9340 */
9341 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9342 {
9343   const PetscInt debug = 0;
9344   PetscSection   section;
9345   Vec            localX;
9346   PetscReal     *coords, *v0, *J, *invJ, detJ;
9347   PetscReal      localDiff = 0.0;
9348   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9349   PetscErrorCode ierr;
9350 
9351   PetscFunctionBegin;
9352   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9353   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9354   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9355   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9356   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9357   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9358   for (field = 0; field < numFields; ++field) {
9359     numComponents += quad[field].numComponents;
9360   }
9361   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9362   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9363   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9364   for (c = cStart; c < cEnd; ++c) {
9365     const PetscScalar *x;
9366     PetscReal          elemDiff = 0.0;
9367 
9368     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9369     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9370     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9371 
9372     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9373       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9374       const PetscReal *quadPoints    = quad[field].quadPoints;
9375       const PetscReal *quadWeights   = quad[field].quadWeights;
9376       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9377       const PetscInt   numBasisComps = quad[field].numComponents;
9378       const PetscReal *basis         = quad[field].basis;
9379       PetscInt         q, d, e, fc, f;
9380 
9381       if (debug) {
9382         char title[1024];
9383         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9384         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9385       }
9386       for (q = 0; q < numQuadPoints; ++q) {
9387         for (d = 0; d < dim; d++) {
9388           coords[d] = v0[d];
9389           for (e = 0; e < dim; e++) {
9390             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9391           }
9392         }
9393         for (fc = 0; fc < numBasisComps; ++fc) {
9394           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9395           PetscReal       interpolant = 0.0;
9396           for (f = 0; f < numBasisFuncs; ++f) {
9397             const PetscInt fidx = f*numBasisComps+fc;
9398             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9399           }
9400           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9401           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9402         }
9403       }
9404       comp        += numBasisComps;
9405       fieldOffset += numBasisFuncs*numBasisComps;
9406     }
9407     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9408     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9409     localDiff += elemDiff;
9410   }
9411   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9412   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9413   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9414   *diff = PetscSqrtReal(*diff);
9415   PetscFunctionReturn(0);
9416 }
9417 
9418 #undef __FUNCT__
9419 #define __FUNCT__ "DMPlexComputeResidualFEM"
9420 /*@
9421   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9422 
9423   Input Parameters:
9424 + dm - The mesh
9425 . X  - Local input vector
9426 - user - The user context
9427 
9428   Output Parameter:
9429 . F  - Local output vector
9430 
9431   Note:
9432   The second member of the user context must be an FEMContext.
9433 
9434   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9435   like a GPU, or vectorize on a multicore machine.
9436 
9437 .seealso: DMPlexComputeJacobianActionFEM()
9438 */
9439 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9440 {
9441   DM_Plex         *mesh = (DM_Plex*) dm->data;
9442   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9443   PetscQuadrature *quad = fem->quad;
9444   PetscSection     section;
9445   PetscReal       *v0, *J, *invJ, *detJ;
9446   PetscScalar     *elemVec, *u;
9447   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9448   PetscInt         cellDof = 0, numComponents = 0;
9449   PetscErrorCode   ierr;
9450 
9451   PetscFunctionBegin;
9452   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9453   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9454   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9455   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9456   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9457   numCells = cEnd - cStart;
9458   for (field = 0; field < numFields; ++field) {
9459     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9460     numComponents += quad[field].numComponents;
9461   }
9462   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9463   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9464   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);
9465   for (c = cStart; c < cEnd; ++c) {
9466     const PetscScalar *x;
9467     PetscInt           i;
9468 
9469     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9470     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9471     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9472 
9473     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9474     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9475   }
9476   for (field = 0; field < numFields; ++field) {
9477     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9478     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9479     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9480     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9481     /* Conforming batches */
9482     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9483     PetscInt numBlocks  = 1;
9484     PetscInt batchSize  = numBlocks * blockSize;
9485     PetscInt numBatches = numBatchesTmp;
9486     PetscInt numChunks  = numCells / (numBatches*batchSize);
9487     /* Remainder */
9488     PetscInt numRemainder = numCells % (numBatches * batchSize);
9489     PetscInt offset       = numCells - numRemainder;
9490 
9491     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9492     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9493                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9494   }
9495   for (c = cStart; c < cEnd; ++c) {
9496     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9497     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9498   }
9499   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9500   if (mesh->printFEM) {
9501     PetscMPIInt rank, numProcs;
9502     PetscInt    p;
9503 
9504     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9505     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9506     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9507     for (p = 0; p < numProcs; ++p) {
9508       if (p == rank) {
9509         Vec f;
9510 
9511         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9512         ierr = VecCopy(F, f);CHKERRQ(ierr);
9513         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9514         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9515         ierr = VecDestroy(&f);CHKERRQ(ierr);
9516         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9517       }
9518       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9519     }
9520   }
9521   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9522   PetscFunctionReturn(0);
9523 }
9524 
9525 #undef __FUNCT__
9526 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9527 /*@C
9528   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9529 
9530   Input Parameters:
9531 + dm - The mesh
9532 . J  - The Jacobian shell matrix
9533 . X  - Local input vector
9534 - user - The user context
9535 
9536   Output Parameter:
9537 . F  - Local output vector
9538 
9539   Note:
9540   The second member of the user context must be an FEMContext.
9541 
9542   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9543   like a GPU, or vectorize on a multicore machine.
9544 
9545 .seealso: DMPlexComputeResidualFEM()
9546 */
9547 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9548 {
9549   DM_Plex         *mesh = (DM_Plex*) dm->data;
9550   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9551   PetscQuadrature *quad = fem->quad;
9552   PetscSection     section;
9553   JacActionCtx    *jctx;
9554   PetscReal       *v0, *J, *invJ, *detJ;
9555   PetscScalar     *elemVec, *u, *a;
9556   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9557   PetscInt         cellDof = 0;
9558   PetscErrorCode   ierr;
9559 
9560   PetscFunctionBegin;
9561   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9562   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9563   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9564   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9565   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9566   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9567   numCells = cEnd - cStart;
9568   for (field = 0; field < numFields; ++field) {
9569     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9570   }
9571   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9572   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);
9573   for (c = cStart; c < cEnd; ++c) {
9574     const PetscScalar *x;
9575     PetscInt           i;
9576 
9577     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9578     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9579     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9580     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9581     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9582     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9583     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9584     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9585   }
9586   for (field = 0; field < numFields; ++field) {
9587     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9588     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9589     /* Conforming batches */
9590     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9591     PetscInt numBlocks  = 1;
9592     PetscInt batchSize  = numBlocks * blockSize;
9593     PetscInt numBatches = numBatchesTmp;
9594     PetscInt numChunks  = numCells / (numBatches*batchSize);
9595     /* Remainder */
9596     PetscInt numRemainder = numCells % (numBatches * batchSize);
9597     PetscInt offset       = numCells - numRemainder;
9598 
9599     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);
9600     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],
9601                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9602   }
9603   for (c = cStart; c < cEnd; ++c) {
9604     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9605     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9606   }
9607   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9608   if (mesh->printFEM) {
9609     PetscMPIInt rank, numProcs;
9610     PetscInt    p;
9611 
9612     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9613     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9614     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9615     for (p = 0; p < numProcs; ++p) {
9616       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9617       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9618     }
9619   }
9620   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9621   PetscFunctionReturn(0);
9622 }
9623 
9624 #undef __FUNCT__
9625 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9626 /*@
9627   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9628 
9629   Input Parameters:
9630 + dm - The mesh
9631 . X  - Local input vector
9632 - user - The user context
9633 
9634   Output Parameter:
9635 . Jac  - Jacobian matrix
9636 
9637   Note:
9638   The second member of the user context must be an FEMContext.
9639 
9640   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9641   like a GPU, or vectorize on a multicore machine.
9642 
9643 .seealso: FormFunctionLocal()
9644 */
9645 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9646 {
9647   DM_Plex         *mesh = (DM_Plex*) dm->data;
9648   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9649   PetscQuadrature *quad = fem->quad;
9650   PetscSection     section;
9651   PetscReal       *v0, *J, *invJ, *detJ;
9652   PetscScalar     *elemMat, *u;
9653   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9654   PetscInt         cellDof = 0, numComponents = 0;
9655   PetscBool        isShell;
9656   PetscErrorCode   ierr;
9657 
9658   PetscFunctionBegin;
9659   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9660   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9661   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9662   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9663   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9664   numCells = cEnd - cStart;
9665   for (field = 0; field < numFields; ++field) {
9666     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9667     numComponents += quad[field].numComponents;
9668   }
9669   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9670   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9671   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);
9672   for (c = cStart; c < cEnd; ++c) {
9673     const PetscScalar *x;
9674     PetscInt           i;
9675 
9676     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9677     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9678     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9679 
9680     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9681     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9682   }
9683   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9684   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9685     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9686     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9687     PetscInt       fieldJ;
9688 
9689     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9690       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9691       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9692       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9693       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9694       /* Conforming batches */
9695       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9696       PetscInt numBlocks  = 1;
9697       PetscInt batchSize  = numBlocks * blockSize;
9698       PetscInt numBatches = numBatchesTmp;
9699       PetscInt numChunks  = numCells / (numBatches*batchSize);
9700       /* Remainder */
9701       PetscInt numRemainder = numCells % (numBatches * batchSize);
9702       PetscInt offset       = numCells - numRemainder;
9703 
9704       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9705       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9706                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9707     }
9708   }
9709   for (c = cStart; c < cEnd; ++c) {
9710     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9711     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9712   }
9713   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9714 
9715   /* Assemble matrix, using the 2-step process:
9716        MatAssemblyBegin(), MatAssemblyEnd(). */
9717   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9718   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9719 
9720   if (mesh->printFEM) {
9721     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9722     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9723     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9724   }
9725   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9726   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9727   if (isShell) {
9728     JacActionCtx *jctx;
9729 
9730     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9731     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9732   }
9733   *str = SAME_NONZERO_PATTERN;
9734   PetscFunctionReturn(0);
9735 }
9736 
9737 
9738 #undef __FUNCT__
9739 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9740 /*@C
9741   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9742   the local section and an SF describing the section point overlap.
9743 
9744   Input Parameters:
9745   + s - The PetscSection for the local field layout
9746   . sf - The SF describing parallel layout of the section points
9747   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9748   . label - The label specifying the points
9749   - labelValue - The label stratum specifying the points
9750 
9751   Output Parameter:
9752   . gsection - The PetscSection for the global field layout
9753 
9754   Note: This gives negative sizes and offsets to points not owned by this process
9755 
9756   Level: developer
9757 
9758 .seealso: PetscSectionCreate()
9759 @*/
9760 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9761 {
9762   PetscInt      *neg;
9763   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9764   PetscErrorCode ierr;
9765 
9766   PetscFunctionBegin;
9767   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9768   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9769   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9770   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9771   /* Mark ghost points with negative dof */
9772   for (p = pStart; p < pEnd; ++p) {
9773     PetscInt value;
9774 
9775     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9776     if (value != labelValue) continue;
9777     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9778     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9779     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9780     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9781     neg[p-pStart] = -(dof+1);
9782   }
9783   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9784   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
9785   if (nroots >= 0) {
9786     if (nroots > pEnd - pStart) {
9787       PetscInt *tmpDof;
9788       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9789       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9790       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9791       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9792       for (p = pStart; p < pEnd; ++p) {
9793         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
9794       }
9795       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9796     } else {
9797       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9798       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9799     }
9800   }
9801   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9802   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9803     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9804 
9805     (*gsection)->atlasOff[p] = off;
9806 
9807     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9808   }
9809   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9810   globalOff -= off;
9811   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9812     (*gsection)->atlasOff[p] += globalOff;
9813 
9814     neg[p] = -((*gsection)->atlasOff[p]+1);
9815   }
9816   /* Put in negative offsets for ghost points */
9817   if (nroots >= 0) {
9818     if (nroots > pEnd - pStart) {
9819       PetscInt *tmpOff;
9820       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9821       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9822       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9823       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9824       for (p = pStart; p < pEnd; ++p) {
9825         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
9826       }
9827       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9828     } else {
9829       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9830       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9831     }
9832   }
9833   ierr = PetscFree(neg);CHKERRQ(ierr);
9834   PetscFunctionReturn(0);
9835 }
9836