xref: /petsc/src/dm/impls/plex/plex.c (revision 2bdb15eae0e5a7e54521bb6ad85b44df9d3cce2f)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/isimpl.h>
4 #include <petscsf.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_Stratify, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM;
8 
9 PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 PETSC_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     PetscInt    numLabels, l;
282     PetscMPIInt size;
283 
284     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
285     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
286     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
287     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
288     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
289     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
290     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
291     if (depth == 1) {
292       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
293       pEnd = pEnd - pStart;
294       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
295       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
296       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
297       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
298       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
299       pEnd = pEnd - pStart;
300       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
301       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
302       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
303       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
304     } else {
305       for (d = 0; d <= dim; d++) {
306         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
307         pEnd = pEnd - pStart;
308         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
309         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
310         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
311         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
312       }
313     }
314     ierr = PetscFree(sizes);CHKERRQ(ierr);
315     ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
316     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
317     for (l = 0; l < numLabels; ++l) {
318       DMLabel         label;
319       const char     *name;
320       IS              valueIS;
321       const PetscInt *values;
322       PetscInt        numValues, v;
323 
324       ierr = DMPlexGetLabelName(dm, l, &name);CHKERRQ(ierr);
325       ierr = DMPlexGetLabel(dm, name, &label);CHKERRQ(ierr);
326       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
327       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);CHKERRQ(ierr);
328       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
329       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
330       for (v = 0; v < numValues; ++v) {
331         PetscInt size;
332 
333         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
334         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
335         ierr = PetscViewerASCIIPrintf(viewer, "%d", size);CHKERRQ(ierr);
336       }
337       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
338       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
339       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
340     }
341   }
342   PetscFunctionReturn(0);
343 }
344 
345 #undef __FUNCT__
346 #define __FUNCT__ "DMView_Plex"
347 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
348 {
349   PetscBool      iascii, isbinary;
350   PetscErrorCode ierr;
351 
352   PetscFunctionBegin;
353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
354   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
355   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
356   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
357   if (iascii) {
358     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
359 #if 0
360   } else if (isbinary) {
361     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
362 #endif
363   }
364   PetscFunctionReturn(0);
365 }
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMDestroy_Plex"
369 PetscErrorCode DMDestroy_Plex(DM dm)
370 {
371   DM_Plex       *mesh = (DM_Plex*) dm->data;
372   DMLabel        next  = mesh->labels;
373   PetscErrorCode ierr;
374 
375   PetscFunctionBegin;
376   if (--mesh->refct > 0) PetscFunctionReturn(0);
377   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
378   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
379   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
380   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
381   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
382   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
383   while (next) {
384     DMLabel tmp = next->next;
385 
386     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
387     next = tmp;
388   }
389   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
390   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
391   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
392   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
393   ierr = PetscFree(mesh);CHKERRQ(ierr);
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "DMCreateMatrix_Plex"
399 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
400 {
401   PetscSection   section, sectionGlobal;
402   PetscInt       bs = -1;
403   PetscInt       localSize;
404   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock;
405   PetscErrorCode ierr;
406 
407   PetscFunctionBegin;
408 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
409   ierr = MatInitializePackage();CHKERRQ(ierr);
410 #endif
411   if (!mtype) mtype = MATAIJ;
412   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
413   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
414   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
415   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
416   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
417   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
418   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
419   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
420   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
421   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
422   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
423   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
424   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
425   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
426   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
427   if (!isShell) {
428     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
429     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
430 
431     if (bs < 0) {
432       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
433         PetscInt pStart, pEnd, p, dof, cdof;
434 
435         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
436         for (p = pStart; p < pEnd; ++p) {
437           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
438           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
439           if (dof-cdof) {
440             if (bs < 0) {
441               bs = dof-cdof;
442             } else if (bs != dof-cdof) {
443               /* Layout does not admit a pointwise block size */
444               bs = 1;
445               break;
446             }
447           }
448         }
449         /* Must have same blocksize on all procs (some might have no points) */
450         bsLocal = bs;
451         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
452         bsLocal = bs < 0 ? bsMax : bs;
453         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
454         if (bsMin != bsMax) {
455           bs = 1;
456         } else {
457           bs = bsMax;
458         }
459       } else {
460         bs = 1;
461       }
462     }
463     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
464     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
465     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
466     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
467     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
468     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
469     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
470   }
471   PetscFunctionReturn(0);
472 }
473 
474 #undef __FUNCT__
475 #define __FUNCT__ "DMPlexGetDimension"
476 /*@
477   DMPlexGetDimension - Return the topological mesh dimension
478 
479   Not collective
480 
481   Input Parameter:
482 . mesh - The DMPlex
483 
484   Output Parameter:
485 . dim - The topological mesh dimension
486 
487   Level: beginner
488 
489 .seealso: DMPlexCreate()
490 @*/
491 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
492 {
493   DM_Plex *mesh = (DM_Plex*) dm->data;
494 
495   PetscFunctionBegin;
496   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
497   PetscValidPointer(dim, 2);
498   *dim = mesh->dim;
499   PetscFunctionReturn(0);
500 }
501 
502 #undef __FUNCT__
503 #define __FUNCT__ "DMPlexSetDimension"
504 /*@
505   DMPlexSetDimension - Set the topological mesh dimension
506 
507   Collective on mesh
508 
509   Input Parameters:
510 + mesh - The DMPlex
511 - dim - The topological mesh dimension
512 
513   Level: beginner
514 
515 .seealso: DMPlexCreate()
516 @*/
517 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
518 {
519   DM_Plex *mesh = (DM_Plex*) dm->data;
520 
521   PetscFunctionBegin;
522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
523   PetscValidLogicalCollectiveInt(dm, dim, 2);
524   mesh->dim               = dim;
525   mesh->preallocCenterDim = dim;
526   PetscFunctionReturn(0);
527 }
528 
529 #undef __FUNCT__
530 #define __FUNCT__ "DMPlexGetChart"
531 /*@
532   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
533 
534   Not collective
535 
536   Input Parameter:
537 . mesh - The DMPlex
538 
539   Output Parameters:
540 + pStart - The first mesh point
541 - pEnd   - The upper bound for mesh points
542 
543   Level: beginner
544 
545 .seealso: DMPlexCreate(), DMPlexSetChart()
546 @*/
547 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
548 {
549   DM_Plex       *mesh = (DM_Plex*) dm->data;
550   PetscErrorCode ierr;
551 
552   PetscFunctionBegin;
553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
554   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
555   PetscFunctionReturn(0);
556 }
557 
558 #undef __FUNCT__
559 #define __FUNCT__ "DMPlexSetChart"
560 /*@
561   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
562 
563   Not collective
564 
565   Input Parameters:
566 + mesh - The DMPlex
567 . pStart - The first mesh point
568 - pEnd   - The upper bound for mesh points
569 
570   Output Parameters:
571 
572   Level: beginner
573 
574 .seealso: DMPlexCreate(), DMPlexGetChart()
575 @*/
576 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
577 {
578   DM_Plex       *mesh = (DM_Plex*) dm->data;
579   PetscErrorCode ierr;
580 
581   PetscFunctionBegin;
582   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
583   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
584   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
585   PetscFunctionReturn(0);
586 }
587 
588 #undef __FUNCT__
589 #define __FUNCT__ "DMPlexGetConeSize"
590 /*@
591   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
592 
593   Not collective
594 
595   Input Parameters:
596 + mesh - The DMPlex
597 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
598 
599   Output Parameter:
600 . size - The cone size for point p
601 
602   Level: beginner
603 
604 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
605 @*/
606 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
607 {
608   DM_Plex       *mesh = (DM_Plex*) dm->data;
609   PetscErrorCode ierr;
610 
611   PetscFunctionBegin;
612   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
613   PetscValidPointer(size, 3);
614   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
615   PetscFunctionReturn(0);
616 }
617 
618 #undef __FUNCT__
619 #define __FUNCT__ "DMPlexSetConeSize"
620 /*@
621   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
622 
623   Not collective
624 
625   Input Parameters:
626 + mesh - The DMPlex
627 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
628 - size - The cone size for point p
629 
630   Output Parameter:
631 
632   Note:
633   This should be called after DMPlexSetChart().
634 
635   Level: beginner
636 
637 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
638 @*/
639 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
640 {
641   DM_Plex       *mesh = (DM_Plex*) dm->data;
642   PetscErrorCode ierr;
643 
644   PetscFunctionBegin;
645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
646   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
647 
648   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
649   PetscFunctionReturn(0);
650 }
651 
652 #undef __FUNCT__
653 #define __FUNCT__ "DMPlexGetCone"
654 /*@C
655   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
656 
657   Not collective
658 
659   Input Parameters:
660 + mesh - The DMPlex
661 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
662 
663   Output Parameter:
664 . cone - An array of points which are on the in-edges for point p
665 
666   Level: beginner
667 
668   Fortran Notes:
669   Since it returns an array, this routine is only available in Fortran 90, and you must
670   include petsc.h90 in your code.
671 
672   You must also call DMPlexRestoreCone() after you finish using the returned array.
673 
674 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
675 @*/
676 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
677 {
678   DM_Plex       *mesh = (DM_Plex*) dm->data;
679   PetscInt       off;
680   PetscErrorCode ierr;
681 
682   PetscFunctionBegin;
683   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
684   PetscValidPointer(cone, 3);
685   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
686   *cone = &mesh->cones[off];
687   PetscFunctionReturn(0);
688 }
689 
690 #undef __FUNCT__
691 #define __FUNCT__ "DMPlexSetCone"
692 /*@
693   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
694 
695   Not collective
696 
697   Input Parameters:
698 + mesh - The DMPlex
699 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
700 - cone - An array of points which are on the in-edges for point p
701 
702   Output Parameter:
703 
704   Note:
705   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
706 
707   Level: beginner
708 
709 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
710 @*/
711 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
712 {
713   DM_Plex       *mesh = (DM_Plex*) dm->data;
714   PetscInt       pStart, pEnd;
715   PetscInt       dof, off, c;
716   PetscErrorCode ierr;
717 
718   PetscFunctionBegin;
719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
720   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
721   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
722   if (dof) PetscValidPointer(cone, 3);
723   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
724   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);
725   for (c = 0; c < dof; ++c) {
726     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);
727     mesh->cones[off+c] = cone[c];
728   }
729   PetscFunctionReturn(0);
730 }
731 
732 #undef __FUNCT__
733 #define __FUNCT__ "DMPlexGetConeOrientation"
734 /*@C
735   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
736 
737   Not collective
738 
739   Input Parameters:
740 + mesh - The DMPlex
741 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
742 
743   Output Parameter:
744 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
745                     integer giving the prescription for cone traversal. If it is negative, the cone is
746                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
747                     the index of the cone point on which to start.
748 
749   Level: beginner
750 
751   Fortran Notes:
752   Since it returns an array, this routine is only available in Fortran 90, and you must
753   include petsc.h90 in your code.
754 
755   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
756 
757 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
758 @*/
759 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
760 {
761   DM_Plex       *mesh = (DM_Plex*) dm->data;
762   PetscInt       off;
763   PetscErrorCode ierr;
764 
765   PetscFunctionBegin;
766   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
767 #if defined(PETSC_USE_DEBUG)
768   {
769     PetscInt dof;
770     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
771     if (dof) PetscValidPointer(coneOrientation, 3);
772   }
773 #endif
774   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
775 
776   *coneOrientation = &mesh->coneOrientations[off];
777   PetscFunctionReturn(0);
778 }
779 
780 #undef __FUNCT__
781 #define __FUNCT__ "DMPlexSetConeOrientation"
782 /*@
783   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
784 
785   Not collective
786 
787   Input Parameters:
788 + mesh - The DMPlex
789 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
790 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
791                     integer giving the prescription for cone traversal. If it is negative, the cone is
792                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
793                     the index of the cone point on which to start.
794 
795   Output Parameter:
796 
797   Note:
798   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
799 
800   Level: beginner
801 
802 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
803 @*/
804 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
805 {
806   DM_Plex       *mesh = (DM_Plex*) dm->data;
807   PetscInt       pStart, pEnd;
808   PetscInt       dof, off, c;
809   PetscErrorCode ierr;
810 
811   PetscFunctionBegin;
812   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
813   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
814   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
815   if (dof) PetscValidPointer(coneOrientation, 3);
816   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
817   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);
818   for (c = 0; c < dof; ++c) {
819     PetscInt cdof, o = coneOrientation[c];
820 
821     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
822     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);
823     mesh->coneOrientations[off+c] = o;
824   }
825   PetscFunctionReturn(0);
826 }
827 
828 #undef __FUNCT__
829 #define __FUNCT__ "DMPlexInsertCone"
830 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
831 {
832   DM_Plex       *mesh = (DM_Plex*) dm->data;
833   PetscInt       pStart, pEnd;
834   PetscInt       dof, off;
835   PetscErrorCode ierr;
836 
837   PetscFunctionBegin;
838   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
839   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
840   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);
841   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);
842   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
843   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
844   if ((conePos < 0) || (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);
845   mesh->cones[off+conePos] = conePoint;
846   PetscFunctionReturn(0);
847 }
848 
849 #undef __FUNCT__
850 #define __FUNCT__ "DMPlexInsertConeOrientation"
851 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
852 {
853   DM_Plex       *mesh = (DM_Plex*) dm->data;
854   PetscInt       pStart, pEnd;
855   PetscInt       dof, off;
856   PetscErrorCode ierr;
857 
858   PetscFunctionBegin;
859   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
860   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
861   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);
862   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
863   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
864   if ((conePos < 0) || (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);
865   mesh->coneOrientations[off+conePos] = coneOrientation;
866   PetscFunctionReturn(0);
867 }
868 
869 #undef __FUNCT__
870 #define __FUNCT__ "DMPlexGetSupportSize"
871 /*@
872   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
873 
874   Not collective
875 
876   Input Parameters:
877 + mesh - The DMPlex
878 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
879 
880   Output Parameter:
881 . size - The support size for point p
882 
883   Level: beginner
884 
885 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
886 @*/
887 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
888 {
889   DM_Plex       *mesh = (DM_Plex*) dm->data;
890   PetscErrorCode ierr;
891 
892   PetscFunctionBegin;
893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
894   PetscValidPointer(size, 3);
895   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
896   PetscFunctionReturn(0);
897 }
898 
899 #undef __FUNCT__
900 #define __FUNCT__ "DMPlexSetSupportSize"
901 /*@
902   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
903 
904   Not collective
905 
906   Input Parameters:
907 + mesh - The DMPlex
908 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
909 - size - The support size for point p
910 
911   Output Parameter:
912 
913   Note:
914   This should be called after DMPlexSetChart().
915 
916   Level: beginner
917 
918 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
919 @*/
920 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
921 {
922   DM_Plex       *mesh = (DM_Plex*) dm->data;
923   PetscErrorCode ierr;
924 
925   PetscFunctionBegin;
926   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
927   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
928 
929   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
930   PetscFunctionReturn(0);
931 }
932 
933 #undef __FUNCT__
934 #define __FUNCT__ "DMPlexGetSupport"
935 /*@C
936   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
937 
938   Not collective
939 
940   Input Parameters:
941 + mesh - The DMPlex
942 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
943 
944   Output Parameter:
945 . support - An array of points which are on the out-edges for point p
946 
947   Level: beginner
948 
949   Fortran Notes:
950   Since it returns an array, this routine is only available in Fortran 90, and you must
951   include petsc.h90 in your code.
952 
953   You must also call DMPlexRestoreSupport() after you finish using the returned array.
954 
955 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
956 @*/
957 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
958 {
959   DM_Plex       *mesh = (DM_Plex*) dm->data;
960   PetscInt       off;
961   PetscErrorCode ierr;
962 
963   PetscFunctionBegin;
964   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
965   PetscValidPointer(support, 3);
966   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
967   *support = &mesh->supports[off];
968   PetscFunctionReturn(0);
969 }
970 
971 #undef __FUNCT__
972 #define __FUNCT__ "DMPlexSetSupport"
973 /*@
974   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
975 
976   Not collective
977 
978   Input Parameters:
979 + mesh - The DMPlex
980 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
981 - support - An array of points which are on the in-edges for point p
982 
983   Output Parameter:
984 
985   Note:
986   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
987 
988   Level: beginner
989 
990 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
991 @*/
992 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
993 {
994   DM_Plex       *mesh = (DM_Plex*) dm->data;
995   PetscInt       pStart, pEnd;
996   PetscInt       dof, off, c;
997   PetscErrorCode ierr;
998 
999   PetscFunctionBegin;
1000   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1001   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1002   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1003   if (dof) PetscValidPointer(support, 3);
1004   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1005   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);
1006   for (c = 0; c < dof; ++c) {
1007     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);
1008     mesh->supports[off+c] = support[c];
1009   }
1010   PetscFunctionReturn(0);
1011 }
1012 
1013 #undef __FUNCT__
1014 #define __FUNCT__ "DMPlexInsertSupport"
1015 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1016 {
1017   DM_Plex       *mesh = (DM_Plex*) dm->data;
1018   PetscInt       pStart, pEnd;
1019   PetscInt       dof, off;
1020   PetscErrorCode ierr;
1021 
1022   PetscFunctionBegin;
1023   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1024   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1025   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1026   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1027   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);
1028   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);
1029   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);
1030   mesh->supports[off+supportPos] = supportPoint;
1031   PetscFunctionReturn(0);
1032 }
1033 
1034 #undef __FUNCT__
1035 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1036 /*@C
1037   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1038 
1039   Not collective
1040 
1041   Input Parameters:
1042 + mesh - The DMPlex
1043 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1044 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1045 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1046 
1047   Output Parameters:
1048 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1049 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1050 
1051   Note:
1052   If using internal storage (points is NULL on input), each call overwrites the last output.
1053 
1054   Fortran Notes:
1055   Since it returns an array, this routine is only available in Fortran 90, and you must
1056   include petsc.h90 in your code.
1057 
1058   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1059 
1060   Level: beginner
1061 
1062 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1063 @*/
1064 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1065 {
1066   DM_Plex        *mesh = (DM_Plex*) dm->data;
1067   PetscInt       *closure, *fifo;
1068   const PetscInt *tmp = NULL, *tmpO = NULL;
1069   PetscInt        tmpSize, t;
1070   PetscInt        depth       = 0, maxSize;
1071   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1072   PetscErrorCode  ierr;
1073 
1074   PetscFunctionBegin;
1075   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1076   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1077   /* This is only 1-level */
1078   if (useCone) {
1079     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1080     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1081     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1082   } else {
1083     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1084     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1085   }
1086   if (depth == 1) {
1087     if (*points) {
1088       closure = *points;
1089     } else {
1090       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1091       ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1092     }
1093     closure[0] = p; closure[1] = 0;
1094     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1095       closure[closureSize]   = tmp[t];
1096       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1097     }
1098     if (numPoints) *numPoints = closureSize/2;
1099     if (points)    *points    = closure;
1100     PetscFunctionReturn(0);
1101   }
1102   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1103   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1104   if (*points) {
1105     closure = *points;
1106   } else {
1107     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1108   }
1109   closure[0] = p; closure[1] = 0;
1110   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1111     const PetscInt cp = tmp[t];
1112     const PetscInt co = tmpO ? tmpO[t] : 0;
1113 
1114     closure[closureSize]   = cp;
1115     closure[closureSize+1] = co;
1116     fifo[fifoSize]         = cp;
1117     fifo[fifoSize+1]       = co;
1118   }
1119   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1120   while (fifoSize - fifoStart) {
1121     const PetscInt q   = fifo[fifoStart];
1122     const PetscInt o   = fifo[fifoStart+1];
1123     const PetscInt rev = o >= 0 ? 0 : 1;
1124     const PetscInt off = rev ? -(o+1) : o;
1125 
1126     if (useCone) {
1127       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1128       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1129       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1130     } else {
1131       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1132       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1133       tmpO = NULL;
1134     }
1135     for (t = 0; t < tmpSize; ++t) {
1136       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1137       const PetscInt cp = tmp[i];
1138       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1139       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1140        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1141       PetscInt       co = tmpO ? tmpO[i] : 0;
1142       PetscInt       c;
1143 
1144       if (rev) {
1145         PetscInt childSize, coff;
1146         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1147         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1148         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1149       }
1150       /* Check for duplicate */
1151       for (c = 0; c < closureSize; c += 2) {
1152         if (closure[c] == cp) break;
1153       }
1154       if (c == closureSize) {
1155         closure[closureSize]   = cp;
1156         closure[closureSize+1] = co;
1157         fifo[fifoSize]         = cp;
1158         fifo[fifoSize+1]       = co;
1159         closureSize           += 2;
1160         fifoSize              += 2;
1161       }
1162     }
1163     fifoStart += 2;
1164   }
1165   if (numPoints) *numPoints = closureSize/2;
1166   if (points)    *points    = closure;
1167   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1168   PetscFunctionReturn(0);
1169 }
1170 
1171 #undef __FUNCT__
1172 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1173 /*@C
1174   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1175 
1176   Not collective
1177 
1178   Input Parameters:
1179 + mesh - The DMPlex
1180 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1181 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1182 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1183 
1184   Output Parameters:
1185 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1186 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1187 
1188   Note:
1189   If not using internal storage (points is not NULL on input), this call is unnecessary
1190 
1191   Fortran Notes:
1192   Since it returns an array, this routine is only available in Fortran 90, and you must
1193   include petsc.h90 in your code.
1194 
1195   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1196 
1197   Level: beginner
1198 
1199 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1200 @*/
1201 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1202 {
1203   PetscErrorCode ierr;
1204 
1205   PetscFunctionBegin;
1206   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1207   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1208   PetscFunctionReturn(0);
1209 }
1210 
1211 #undef __FUNCT__
1212 #define __FUNCT__ "DMPlexGetMaxSizes"
1213 /*@
1214   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1215 
1216   Not collective
1217 
1218   Input Parameter:
1219 . mesh - The DMPlex
1220 
1221   Output Parameters:
1222 + maxConeSize - The maximum number of in-edges
1223 - maxSupportSize - The maximum number of out-edges
1224 
1225   Level: beginner
1226 
1227 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1228 @*/
1229 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1230 {
1231   DM_Plex *mesh = (DM_Plex*) dm->data;
1232 
1233   PetscFunctionBegin;
1234   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1235   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1236   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1237   PetscFunctionReturn(0);
1238 }
1239 
1240 #undef __FUNCT__
1241 #define __FUNCT__ "DMSetUp_Plex"
1242 PetscErrorCode DMSetUp_Plex(DM dm)
1243 {
1244   DM_Plex       *mesh = (DM_Plex*) dm->data;
1245   PetscInt       size;
1246   PetscErrorCode ierr;
1247 
1248   PetscFunctionBegin;
1249   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1250   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1251   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1252   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1253   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1254   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1255   if (mesh->maxSupportSize) {
1256     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1257     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1258     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1259   }
1260   PetscFunctionReturn(0);
1261 }
1262 
1263 #undef __FUNCT__
1264 #define __FUNCT__ "DMCreateSubDM_Plex"
1265 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1266 {
1267   PetscErrorCode ierr;
1268 
1269   PetscFunctionBegin;
1270   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
1271   ierr = DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1272   PetscFunctionReturn(0);
1273 }
1274 
1275 #undef __FUNCT__
1276 #define __FUNCT__ "DMPlexSymmetrize"
1277 /*@
1278   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1279 
1280   Not collective
1281 
1282   Input Parameter:
1283 . mesh - The DMPlex
1284 
1285   Output Parameter:
1286 
1287   Note:
1288   This should be called after all calls to DMPlexSetCone()
1289 
1290   Level: beginner
1291 
1292 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1293 @*/
1294 PetscErrorCode DMPlexSymmetrize(DM dm)
1295 {
1296   DM_Plex       *mesh = (DM_Plex*) dm->data;
1297   PetscInt      *offsets;
1298   PetscInt       supportSize;
1299   PetscInt       pStart, pEnd, p;
1300   PetscErrorCode ierr;
1301 
1302   PetscFunctionBegin;
1303   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1304   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1305   /* Calculate support sizes */
1306   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1307   for (p = pStart; p < pEnd; ++p) {
1308     PetscInt dof, off, c;
1309 
1310     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1311     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1312     for (c = off; c < off+dof; ++c) {
1313       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1314     }
1315   }
1316   for (p = pStart; p < pEnd; ++p) {
1317     PetscInt dof;
1318 
1319     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1320 
1321     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1322   }
1323   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1324   /* Calculate supports */
1325   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1326   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1327   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1328   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1329   for (p = pStart; p < pEnd; ++p) {
1330     PetscInt dof, off, c;
1331 
1332     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1333     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1334     for (c = off; c < off+dof; ++c) {
1335       const PetscInt q = mesh->cones[c];
1336       PetscInt       offS;
1337 
1338       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1339 
1340       mesh->supports[offS+offsets[q]] = p;
1341       ++offsets[q];
1342     }
1343   }
1344   ierr = PetscFree(offsets);CHKERRQ(ierr);
1345   PetscFunctionReturn(0);
1346 }
1347 
1348 #undef __FUNCT__
1349 #define __FUNCT__ "DMPlexStratify"
1350 /*@
1351   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1352   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1353   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1354   the DAG.
1355 
1356   Not collective
1357 
1358   Input Parameter:
1359 . mesh - The DMPlex
1360 
1361   Output Parameter:
1362 
1363   Notes:
1364   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1365   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1366 
1367   This should be called after all calls to DMPlexSymmetrize()
1368 
1369   Level: beginner
1370 
1371 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1372 @*/
1373 PetscErrorCode DMPlexStratify(DM dm)
1374 {
1375   DMLabel        label;
1376   PetscInt       pStart, pEnd, p;
1377   PetscInt       numRoots = 0, numLeaves = 0;
1378   PetscErrorCode ierr;
1379 
1380   PetscFunctionBegin;
1381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1382   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1383   /* Calculate depth */
1384   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1385   ierr = DMPlexCreateLabel(dm, "depth");CHKERRQ(ierr);
1386   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
1387   /* Initialize roots and count leaves */
1388   for (p = pStart; p < pEnd; ++p) {
1389     PetscInt coneSize, supportSize;
1390 
1391     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1392     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1393     if (!coneSize && supportSize) {
1394       ++numRoots;
1395       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1396     } else if (!supportSize && coneSize) {
1397       ++numLeaves;
1398     } else if (!supportSize && !coneSize) {
1399       /* Isolated points */
1400       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1401     }
1402   }
1403   if (numRoots + numLeaves == (pEnd - pStart)) {
1404     for (p = pStart; p < pEnd; ++p) {
1405       PetscInt coneSize, supportSize;
1406 
1407       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1408       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1409       if (!supportSize && coneSize) {
1410         ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr);
1411       }
1412     }
1413   } else {
1414     IS       pointIS;
1415     PetscInt numPoints = 0, level = 0;
1416 
1417     ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1418     if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1419     while (numPoints) {
1420       const PetscInt *points;
1421       const PetscInt  newLevel = level+1;
1422 
1423       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
1424       for (p = 0; p < numPoints; ++p) {
1425         const PetscInt  point = points[p];
1426         const PetscInt *support;
1427         PetscInt        supportSize, s;
1428 
1429         ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr);
1430         ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr);
1431         for (s = 0; s < supportSize; ++s) {
1432           ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr);
1433         }
1434       }
1435       ++level;
1436       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1437       ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1438       if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1439       else         {numPoints = 0;}
1440     }
1441     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1442   }
1443   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1444   PetscFunctionReturn(0);
1445 }
1446 
1447 #undef __FUNCT__
1448 #define __FUNCT__ "DMPlexGetJoin"
1449 /*@C
1450   DMPlexGetJoin - Get an array for the join of the set of points
1451 
1452   Not Collective
1453 
1454   Input Parameters:
1455 + dm - The DMPlex object
1456 . numPoints - The number of input points for the join
1457 - points - The input points
1458 
1459   Output Parameters:
1460 + numCoveredPoints - The number of points in the join
1461 - coveredPoints - The points in the join
1462 
1463   Level: intermediate
1464 
1465   Note: Currently, this is restricted to a single level join
1466 
1467   Fortran Notes:
1468   Since it returns an array, this routine is only available in Fortran 90, and you must
1469   include petsc.h90 in your code.
1470 
1471   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1472 
1473 .keywords: mesh
1474 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1475 @*/
1476 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1477 {
1478   DM_Plex       *mesh = (DM_Plex*) dm->data;
1479   PetscInt      *join[2];
1480   PetscInt       joinSize, i = 0;
1481   PetscInt       dof, off, p, c, m;
1482   PetscErrorCode ierr;
1483 
1484   PetscFunctionBegin;
1485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1486   PetscValidPointer(points, 2);
1487   PetscValidPointer(numCoveredPoints, 3);
1488   PetscValidPointer(coveredPoints, 4);
1489   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1490   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1491   /* Copy in support of first point */
1492   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
1493   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
1494   for (joinSize = 0; joinSize < dof; ++joinSize) {
1495     join[i][joinSize] = mesh->supports[off+joinSize];
1496   }
1497   /* Check each successive support */
1498   for (p = 1; p < numPoints; ++p) {
1499     PetscInt newJoinSize = 0;
1500 
1501     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
1502     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
1503     for (c = 0; c < dof; ++c) {
1504       const PetscInt point = mesh->supports[off+c];
1505 
1506       for (m = 0; m < joinSize; ++m) {
1507         if (point == join[i][m]) {
1508           join[1-i][newJoinSize++] = point;
1509           break;
1510         }
1511       }
1512     }
1513     joinSize = newJoinSize;
1514     i        = 1-i;
1515   }
1516   *numCoveredPoints = joinSize;
1517   *coveredPoints    = join[i];
1518   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1519   PetscFunctionReturn(0);
1520 }
1521 
1522 #undef __FUNCT__
1523 #define __FUNCT__ "DMPlexRestoreJoin"
1524 /*@C
1525   DMPlexRestoreJoin - Restore an array for the join of the set of points
1526 
1527   Not Collective
1528 
1529   Input Parameters:
1530 + dm - The DMPlex object
1531 . numPoints - The number of input points for the join
1532 - points - The input points
1533 
1534   Output Parameters:
1535 + numCoveredPoints - The number of points in the join
1536 - coveredPoints - The points in the join
1537 
1538   Fortran Notes:
1539   Since it returns an array, this routine is only available in Fortran 90, and you must
1540   include petsc.h90 in your code.
1541 
1542   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1543 
1544   Level: intermediate
1545 
1546 .keywords: mesh
1547 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1548 @*/
1549 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1550 {
1551   PetscErrorCode ierr;
1552 
1553   PetscFunctionBegin;
1554   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1555   PetscValidPointer(coveredPoints, 4);
1556   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1557   PetscFunctionReturn(0);
1558 }
1559 
1560 #undef __FUNCT__
1561 #define __FUNCT__ "DMPlexGetFullJoin"
1562 /*@C
1563   DMPlexGetFullJoin - Get an array for the join of the set of points
1564 
1565   Not Collective
1566 
1567   Input Parameters:
1568 + dm - The DMPlex object
1569 . numPoints - The number of input points for the join
1570 - points - The input points
1571 
1572   Output Parameters:
1573 + numCoveredPoints - The number of points in the join
1574 - coveredPoints - The points in the join
1575 
1576   Fortran Notes:
1577   Since it returns an array, this routine is only available in Fortran 90, and you must
1578   include petsc.h90 in your code.
1579 
1580   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1581 
1582   Level: intermediate
1583 
1584 .keywords: mesh
1585 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1586 @*/
1587 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1588 {
1589   DM_Plex       *mesh = (DM_Plex*) dm->data;
1590   PetscInt      *offsets, **closures;
1591   PetscInt      *join[2];
1592   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
1593   PetscInt       p, d, c, m;
1594   PetscErrorCode ierr;
1595 
1596   PetscFunctionBegin;
1597   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1598   PetscValidPointer(points, 2);
1599   PetscValidPointer(numCoveredPoints, 3);
1600   PetscValidPointer(coveredPoints, 4);
1601 
1602   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1603   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1604   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
1605   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1606   maxSize = PetscPowInt(mesh->maxSupportSize,depth+1);
1607   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1608   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1609 
1610   for (p = 0; p < numPoints; ++p) {
1611     PetscInt closureSize;
1612 
1613     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
1614 
1615     offsets[p*(depth+2)+0] = 0;
1616     for (d = 0; d < depth+1; ++d) {
1617       PetscInt pStart, pEnd, i;
1618 
1619       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1620       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1621         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1622           offsets[p*(depth+2)+d+1] = i;
1623           break;
1624         }
1625       }
1626       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1627     }
1628     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);
1629   }
1630   for (d = 0; d < depth+1; ++d) {
1631     PetscInt dof;
1632 
1633     /* Copy in support of first point */
1634     dof = offsets[d+1] - offsets[d];
1635     for (joinSize = 0; joinSize < dof; ++joinSize) {
1636       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1637     }
1638     /* Check each successive cone */
1639     for (p = 1; p < numPoints && joinSize; ++p) {
1640       PetscInt newJoinSize = 0;
1641 
1642       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
1643       for (c = 0; c < dof; ++c) {
1644         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
1645 
1646         for (m = 0; m < joinSize; ++m) {
1647           if (point == join[i][m]) {
1648             join[1-i][newJoinSize++] = point;
1649             break;
1650           }
1651         }
1652       }
1653       joinSize = newJoinSize;
1654       i        = 1-i;
1655     }
1656     if (joinSize) break;
1657   }
1658   *numCoveredPoints = joinSize;
1659   *coveredPoints    = join[i];
1660   for (p = 0; p < numPoints; ++p) {
1661     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
1662   }
1663   ierr = PetscFree(closures);CHKERRQ(ierr);
1664   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1665   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1666   PetscFunctionReturn(0);
1667 }
1668 
1669 #undef __FUNCT__
1670 #define __FUNCT__ "DMPlexGetMeet"
1671 /*@C
1672   DMPlexGetMeet - Get an array for the meet of the set of points
1673 
1674   Not Collective
1675 
1676   Input Parameters:
1677 + dm - The DMPlex object
1678 . numPoints - The number of input points for the meet
1679 - points - The input points
1680 
1681   Output Parameters:
1682 + numCoveredPoints - The number of points in the meet
1683 - coveredPoints - The points in the meet
1684 
1685   Level: intermediate
1686 
1687   Note: Currently, this is restricted to a single level meet
1688 
1689   Fortran Notes:
1690   Since it returns an array, this routine is only available in Fortran 90, and you must
1691   include petsc.h90 in your code.
1692 
1693   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1694 
1695 .keywords: mesh
1696 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1697 @*/
1698 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1699 {
1700   DM_Plex       *mesh = (DM_Plex*) dm->data;
1701   PetscInt      *meet[2];
1702   PetscInt       meetSize, i = 0;
1703   PetscInt       dof, off, p, c, m;
1704   PetscErrorCode ierr;
1705 
1706   PetscFunctionBegin;
1707   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1708   PetscValidPointer(points, 2);
1709   PetscValidPointer(numCoveringPoints, 3);
1710   PetscValidPointer(coveringPoints, 4);
1711   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1712   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1713   /* Copy in cone of first point */
1714   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
1715   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
1716   for (meetSize = 0; meetSize < dof; ++meetSize) {
1717     meet[i][meetSize] = mesh->cones[off+meetSize];
1718   }
1719   /* Check each successive cone */
1720   for (p = 1; p < numPoints; ++p) {
1721     PetscInt newMeetSize = 0;
1722 
1723     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
1724     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
1725     for (c = 0; c < dof; ++c) {
1726       const PetscInt point = mesh->cones[off+c];
1727 
1728       for (m = 0; m < meetSize; ++m) {
1729         if (point == meet[i][m]) {
1730           meet[1-i][newMeetSize++] = point;
1731           break;
1732         }
1733       }
1734     }
1735     meetSize = newMeetSize;
1736     i        = 1-i;
1737   }
1738   *numCoveringPoints = meetSize;
1739   *coveringPoints    = meet[i];
1740   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1741   PetscFunctionReturn(0);
1742 }
1743 
1744 #undef __FUNCT__
1745 #define __FUNCT__ "DMPlexRestoreMeet"
1746 /*@C
1747   DMPlexRestoreMeet - Restore an array for the meet of the set of points
1748 
1749   Not Collective
1750 
1751   Input Parameters:
1752 + dm - The DMPlex object
1753 . numPoints - The number of input points for the meet
1754 - points - The input points
1755 
1756   Output Parameters:
1757 + numCoveredPoints - The number of points in the meet
1758 - coveredPoints - The points in the meet
1759 
1760   Level: intermediate
1761 
1762   Fortran Notes:
1763   Since it returns an array, this routine is only available in Fortran 90, and you must
1764   include petsc.h90 in your code.
1765 
1766   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1767 
1768 .keywords: mesh
1769 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
1770 @*/
1771 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1772 {
1773   PetscErrorCode ierr;
1774 
1775   PetscFunctionBegin;
1776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1777   PetscValidPointer(coveredPoints, 4);
1778   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1779   PetscFunctionReturn(0);
1780 }
1781 
1782 #undef __FUNCT__
1783 #define __FUNCT__ "DMPlexGetFullMeet"
1784 /*@C
1785   DMPlexGetFullMeet - Get an array for the meet of the set of points
1786 
1787   Not Collective
1788 
1789   Input Parameters:
1790 + dm - The DMPlex object
1791 . numPoints - The number of input points for the meet
1792 - points - The input points
1793 
1794   Output Parameters:
1795 + numCoveredPoints - The number of points in the meet
1796 - coveredPoints - The points in the meet
1797 
1798   Level: intermediate
1799 
1800   Fortran Notes:
1801   Since it returns an array, this routine is only available in Fortran 90, and you must
1802   include petsc.h90 in your code.
1803 
1804   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1805 
1806 .keywords: mesh
1807 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
1808 @*/
1809 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1810 {
1811   DM_Plex       *mesh = (DM_Plex*) dm->data;
1812   PetscInt      *offsets, **closures;
1813   PetscInt      *meet[2];
1814   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
1815   PetscInt       p, h, c, m;
1816   PetscErrorCode ierr;
1817 
1818   PetscFunctionBegin;
1819   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1820   PetscValidPointer(points, 2);
1821   PetscValidPointer(numCoveredPoints, 3);
1822   PetscValidPointer(coveredPoints, 4);
1823 
1824   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
1825   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1826   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1827   maxSize = PetscPowInt(mesh->maxConeSize,height+1);
1828   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1829   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1830 
1831   for (p = 0; p < numPoints; ++p) {
1832     PetscInt closureSize;
1833 
1834     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
1835 
1836     offsets[p*(height+2)+0] = 0;
1837     for (h = 0; h < height+1; ++h) {
1838       PetscInt pStart, pEnd, i;
1839 
1840       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
1841       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
1842         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1843           offsets[p*(height+2)+h+1] = i;
1844           break;
1845         }
1846       }
1847       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
1848     }
1849     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);
1850   }
1851   for (h = 0; h < height+1; ++h) {
1852     PetscInt dof;
1853 
1854     /* Copy in cone of first point */
1855     dof = offsets[h+1] - offsets[h];
1856     for (meetSize = 0; meetSize < dof; ++meetSize) {
1857       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
1858     }
1859     /* Check each successive cone */
1860     for (p = 1; p < numPoints && meetSize; ++p) {
1861       PetscInt newMeetSize = 0;
1862 
1863       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
1864       for (c = 0; c < dof; ++c) {
1865         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
1866 
1867         for (m = 0; m < meetSize; ++m) {
1868           if (point == meet[i][m]) {
1869             meet[1-i][newMeetSize++] = point;
1870             break;
1871           }
1872         }
1873       }
1874       meetSize = newMeetSize;
1875       i        = 1-i;
1876     }
1877     if (meetSize) break;
1878   }
1879   *numCoveredPoints = meetSize;
1880   *coveredPoints    = meet[i];
1881   for (p = 0; p < numPoints; ++p) {
1882     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
1883   }
1884   ierr = PetscFree(closures);CHKERRQ(ierr);
1885   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1886   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1887   PetscFunctionReturn(0);
1888 }
1889 
1890 #undef __FUNCT__
1891 #define __FUNCT__ "DMPlexGetNumFaceVertices"
1892 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
1893 {
1894   MPI_Comm       comm;
1895   PetscErrorCode ierr;
1896 
1897   PetscFunctionBegin;
1898   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1899   PetscValidPointer(numFaceVertices,3);
1900   switch (cellDim) {
1901   case 0:
1902     *numFaceVertices = 0;
1903     break;
1904   case 1:
1905     *numFaceVertices = 1;
1906     break;
1907   case 2:
1908     switch (numCorners) {
1909     case 3: /* triangle */
1910       *numFaceVertices = 2; /* Edge has 2 vertices */
1911       break;
1912     case 4: /* quadrilateral */
1913       *numFaceVertices = 2; /* Edge has 2 vertices */
1914       break;
1915     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
1916       *numFaceVertices = 3; /* Edge has 3 vertices */
1917       break;
1918     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
1919       *numFaceVertices = 3; /* Edge has 3 vertices */
1920       break;
1921     default:
1922       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
1923     }
1924     break;
1925   case 3:
1926     switch (numCorners) {
1927     case 4: /* tetradehdron */
1928       *numFaceVertices = 3; /* Face has 3 vertices */
1929       break;
1930     case 6: /* tet cohesive cells */
1931       *numFaceVertices = 4; /* Face has 4 vertices */
1932       break;
1933     case 8: /* hexahedron */
1934       *numFaceVertices = 4; /* Face has 4 vertices */
1935       break;
1936     case 9: /* tet cohesive Lagrange cells */
1937       *numFaceVertices = 6; /* Face has 6 vertices */
1938       break;
1939     case 10: /* quadratic tetrahedron */
1940       *numFaceVertices = 6; /* Face has 6 vertices */
1941       break;
1942     case 12: /* hex cohesive Lagrange cells */
1943       *numFaceVertices = 6; /* Face has 6 vertices */
1944       break;
1945     case 18: /* quadratic tet cohesive Lagrange cells */
1946       *numFaceVertices = 6; /* Face has 6 vertices */
1947       break;
1948     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
1949       *numFaceVertices = 9; /* Face has 9 vertices */
1950       break;
1951     default:
1952       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
1953     }
1954     break;
1955   default:
1956     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
1957   }
1958   PetscFunctionReturn(0);
1959 }
1960 
1961 #undef __FUNCT__
1962 #define __FUNCT__ "DMPlexOrient"
1963 /* Trys to give the mesh a consistent orientation */
1964 PetscErrorCode DMPlexOrient(DM dm)
1965 {
1966   PetscBT        seenCells, flippedCells, seenFaces;
1967   PetscInt      *faceFIFO, fTop, fBottom;
1968   PetscInt       dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO;
1969   PetscErrorCode ierr;
1970 
1971   PetscFunctionBegin;
1972   /* Truth Table
1973      mismatch    flips   do action   mismatch   flipA ^ flipB   action
1974          F       0 flips     no         F             F           F
1975          F       1 flip      yes        F             T           T
1976          F       2 flips     no         T             F           T
1977          T       0 flips     yes        T             T           F
1978          T       1 flip      no
1979          T       2 flips     yes
1980   */
1981   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1982   ierr = DMPlexGetVTKCellHeight(dm, &h);CHKERRQ(ierr);
1983   ierr = DMPlexGetHeightStratum(dm, h,   &cStart, &cEnd);CHKERRQ(ierr);
1984   ierr = DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);CHKERRQ(ierr);
1985   ierr = PetscBTCreate(cEnd - cStart, &seenCells);CHKERRQ(ierr);
1986   ierr = PetscBTMemzero(cEnd - cStart, seenCells);CHKERRQ(ierr);
1987   ierr = PetscBTCreate(cEnd - cStart, &flippedCells);CHKERRQ(ierr);
1988   ierr = PetscBTMemzero(cEnd - cStart, flippedCells);CHKERRQ(ierr);
1989   ierr = PetscBTCreate(fEnd - fStart, &seenFaces);CHKERRQ(ierr);
1990   ierr = PetscBTMemzero(fEnd - fStart, seenFaces);CHKERRQ(ierr);
1991   ierr = PetscMalloc((fEnd - fStart) * sizeof(PetscInt), &faceFIFO);CHKERRQ(ierr);
1992   fTop = fBottom = 0;
1993   /* Initialize FIFO with first cell */
1994   if (cEnd > cStart) {
1995     const PetscInt *cone;
1996     PetscInt        coneSize;
1997 
1998     ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
1999     ierr = DMPlexGetCone(dm, cStart, &cone);CHKERRQ(ierr);
2000     for (c = 0; c < coneSize; ++c) {
2001       faceFIFO[fBottom++] = cone[c];
2002       ierr = PetscBTSet(seenFaces, cone[c]-fStart);CHKERRQ(ierr);
2003     }
2004   }
2005   /* Consider each face in FIFO */
2006   while (fTop < fBottom) {
2007     const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
2008     PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
2009     PetscInt        seenA, flippedA, seenB, flippedB, mismatch;
2010 
2011     face = faceFIFO[fTop++];
2012     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
2013     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
2014     if (supportSize < 2) continue;
2015     if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
2016     seenA    = PetscBTLookup(seenCells,    support[0]-cStart);
2017     flippedA = PetscBTLookup(flippedCells, support[0]-cStart) ? 1 : 0;
2018     seenB    = PetscBTLookup(seenCells,    support[1]-cStart);
2019     flippedB = PetscBTLookup(flippedCells, support[1]-cStart) ? 1 : 0;
2020 
2021     ierr = DMPlexGetConeSize(dm, support[0], &coneSizeA);CHKERRQ(ierr);
2022     ierr = DMPlexGetConeSize(dm, support[1], &coneSizeB);CHKERRQ(ierr);
2023     ierr = DMPlexGetCone(dm, support[0], &coneA);CHKERRQ(ierr);
2024     ierr = DMPlexGetCone(dm, support[1], &coneB);CHKERRQ(ierr);
2025     ierr = DMPlexGetConeOrientation(dm, support[0], &coneOA);CHKERRQ(ierr);
2026     ierr = DMPlexGetConeOrientation(dm, support[1], &coneOB);CHKERRQ(ierr);
2027     for (c = 0; c < coneSizeA; ++c) {
2028       if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
2029         faceFIFO[fBottom++] = coneA[c];
2030         ierr = PetscBTSet(seenFaces, coneA[c]-fStart);CHKERRQ(ierr);
2031       }
2032       if (coneA[c] == face) posA = c;
2033       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2034     }
2035     if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
2036     for (c = 0; c < coneSizeB; ++c) {
2037       if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
2038         faceFIFO[fBottom++] = coneB[c];
2039         ierr = PetscBTSet(seenFaces, coneB[c]-fStart);CHKERRQ(ierr);
2040       }
2041       if (coneB[c] == face) posB = c;
2042       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2043     }
2044     if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);
2045 
2046     if (dim == 1) {
2047       mismatch = posA == posB;
2048     } else {
2049       mismatch = coneOA[posA] == coneOB[posB];
2050     }
2051 
2052     if (mismatch ^ (flippedA ^ flippedB)) {
2053       if (seenA && seenB) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %d and %d do not match: Fault mesh is non-orientable", support[0], support[1]);
2054       if (!seenA && !flippedA) {
2055         ierr = PetscBTSet(flippedCells, support[0]-cStart);CHKERRQ(ierr);
2056       } else if (!seenB && !flippedB) {
2057         ierr = PetscBTSet(flippedCells, support[1]-cStart);CHKERRQ(ierr);
2058       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2059     } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2060     ierr = PetscBTSet(seenCells, support[0]-cStart);CHKERRQ(ierr);
2061     ierr = PetscBTSet(seenCells, support[1]-cStart);CHKERRQ(ierr);
2062   }
2063 
2064   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, NULL);CHKERRQ(ierr);
2065   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2066   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2067   for (c = cStart; c < cEnd; ++c) {
2068     const PetscInt *cone, *coneO, *support;
2069     PetscInt        coneSize, supportSize, faceSize, cp, sp;
2070 
2071     if (!PetscBTLookup(flippedCells, c-cStart)) continue;
2072     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
2073     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2074     ierr = DMPlexGetConeOrientation(dm, c, &coneO);CHKERRQ(ierr);
2075     for (cp = 0; cp < coneSize; ++cp) {
2076       const PetscInt rcp = coneSize-cp-1;
2077 
2078       ierr = DMPlexGetConeSize(dm, cone[rcp], &faceSize);CHKERRQ(ierr);
2079       revcone[cp]  = cone[rcp];
2080       revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp];
2081     }
2082     ierr = DMPlexSetCone(dm, c, revcone);CHKERRQ(ierr);
2083     ierr = DMPlexSetConeOrientation(dm, c, revconeO);CHKERRQ(ierr);
2084     /* Reverse orientations of support */
2085     faceSize = coneSize;
2086     ierr = DMPlexGetSupportSize(dm, c, &supportSize);CHKERRQ(ierr);
2087     ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
2088     for (sp = 0; sp < supportSize; ++sp) {
2089       ierr = DMPlexGetConeSize(dm, support[sp], &coneSize);CHKERRQ(ierr);
2090       ierr = DMPlexGetCone(dm, support[sp], &cone);CHKERRQ(ierr);
2091       ierr = DMPlexGetConeOrientation(dm, support[sp], &coneO);CHKERRQ(ierr);
2092       for (cp = 0; cp < coneSize; ++cp) {
2093         if (cone[cp] != c) continue;
2094         ierr = DMPlexInsertConeOrientation(dm, support[sp], cp, coneO[cp] >= 0 ? -(faceSize-coneO[cp]) : faceSize+coneO[cp]);CHKERRQ(ierr);
2095       }
2096     }
2097   }
2098   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2099   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2100   ierr = PetscBTDestroy(&seenCells);CHKERRQ(ierr);
2101   ierr = PetscBTDestroy(&flippedCells);CHKERRQ(ierr);
2102   ierr = PetscBTDestroy(&seenFaces);CHKERRQ(ierr);
2103   ierr = PetscFree(faceFIFO);CHKERRQ(ierr);
2104   PetscFunctionReturn(0);
2105 }
2106 
2107 #undef __FUNCT__
2108 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Internal"
2109 static PetscErrorCode DMPlexGetAdjacencySingleLevel_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
2110 {
2111   const PetscInt *support = NULL;
2112   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
2113   PetscErrorCode  ierr;
2114 
2115   PetscFunctionBegin;
2116   if (useClosure) {
2117     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
2118     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
2119     for (s = 0; s < supportSize; ++s) {
2120       const PetscInt *cone = NULL;
2121       PetscInt        coneSize, c, q;
2122 
2123       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2124       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
2125       for (c = 0; c < coneSize; ++c) {
2126         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2127           if (cone[c] == adj[q]) break;
2128         }
2129         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2130       }
2131     }
2132   } else {
2133     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2134     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
2135     for (s = 0; s < supportSize; ++s) {
2136       const PetscInt *cone = NULL;
2137       PetscInt        coneSize, c, q;
2138 
2139       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2140       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2141       for (c = 0; c < coneSize; ++c) {
2142         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2143           if (cone[c] == adj[q]) break;
2144         }
2145         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2146       }
2147     }
2148   }
2149   *adjSize = numAdj;
2150   PetscFunctionReturn(0);
2151 }
2152 
2153 #undef __FUNCT__
2154 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2155 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2156 {
2157   const PetscInt maxFaceCases = 30;
2158   PetscInt       numFaceCases = 0;
2159   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2160   PetscInt      *off, *adj;
2161   PetscInt      *neighborCells, *tmpClosure;
2162   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2163   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2164   PetscErrorCode ierr;
2165 
2166   PetscFunctionBegin;
2167   /* For parallel partitioning, I think you have to communicate supports */
2168   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2169   cellDim = dim - cellHeight;
2170   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2171   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2172   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2173   if (cEnd - cStart == 0) {
2174     if (numVertices) *numVertices = 0;
2175     if (offsets)   *offsets   = NULL;
2176     if (adjacency) *adjacency = NULL;
2177     PetscFunctionReturn(0);
2178   }
2179   numCells  = cEnd - cStart;
2180   faceDepth = depth - cellHeight;
2181   /* Setup face recognition */
2182   if (faceDepth == 1) {
2183     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 */
2184 
2185     for (c = cStart; c < cEnd; ++c) {
2186       PetscInt corners;
2187 
2188       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2189       if (!cornersSeen[corners]) {
2190         PetscInt nFV;
2191 
2192         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2193         cornersSeen[corners] = 1;
2194 
2195         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2196 
2197         numFaceVertices[numFaceCases++] = nFV;
2198       }
2199     }
2200   }
2201   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth+1),PetscPowInt(maxSupportSize,depth+1));
2202   maxNeighbors = PetscPowInt(maxConeSize,depth+1)*PetscPowInt(maxSupportSize,depth+1);
2203   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2204   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2205   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2206   /* Count neighboring cells */
2207   for (cell = cStart; cell < cEnd; ++cell) {
2208     PetscInt numNeighbors = maxNeighbors, n;
2209 
2210     ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2211     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2212     for (n = 0; n < numNeighbors; ++n) {
2213       PetscInt        cellPair[2];
2214       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2215       PetscInt        meetSize = 0;
2216       const PetscInt *meet    = NULL;
2217 
2218       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2219       if (cellPair[0] == cellPair[1]) continue;
2220       if (!found) {
2221         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2222         if (meetSize) {
2223           PetscInt f;
2224 
2225           for (f = 0; f < numFaceCases; ++f) {
2226             if (numFaceVertices[f] == meetSize) {
2227               found = PETSC_TRUE;
2228               break;
2229             }
2230           }
2231         }
2232         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2233       }
2234       if (found) ++off[cell-cStart+1];
2235     }
2236   }
2237   /* Prefix sum */
2238   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2239 
2240   if (adjacency) {
2241     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2242     /* Get neighboring cells */
2243     for (cell = cStart; cell < cEnd; ++cell) {
2244       PetscInt numNeighbors = maxNeighbors, n;
2245       PetscInt cellOffset   = 0;
2246 
2247       ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2248       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2249       for (n = 0; n < numNeighbors; ++n) {
2250         PetscInt        cellPair[2];
2251         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2252         PetscInt        meetSize = 0;
2253         const PetscInt *meet    = NULL;
2254 
2255         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2256         if (cellPair[0] == cellPair[1]) continue;
2257         if (!found) {
2258           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2259           if (meetSize) {
2260             PetscInt f;
2261 
2262             for (f = 0; f < numFaceCases; ++f) {
2263               if (numFaceVertices[f] == meetSize) {
2264                 found = PETSC_TRUE;
2265                 break;
2266               }
2267             }
2268           }
2269           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2270         }
2271         if (found) {
2272           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2273           ++cellOffset;
2274         }
2275       }
2276     }
2277   }
2278   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2279   if (numVertices) *numVertices = numCells;
2280   if (offsets)   *offsets   = off;
2281   if (adjacency) *adjacency = adj;
2282   PetscFunctionReturn(0);
2283 }
2284 
2285 #if defined(PETSC_HAVE_CHACO)
2286 #if defined(PETSC_HAVE_UNISTD_H)
2287 #include <unistd.h>
2288 #endif
2289 /* Chaco does not have an include file */
2290 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2291                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2292                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2293                        int mesh_dims[3], double *goal, int global_method, int local_method,
2294                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2295 
2296 extern int FREE_GRAPH;
2297 
2298 #undef __FUNCT__
2299 #define __FUNCT__ "DMPlexPartition_Chaco"
2300 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2301 {
2302   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2303   MPI_Comm       comm;
2304   int            nvtxs          = numVertices; /* number of vertices in full graph */
2305   int           *vwgts          = NULL;   /* weights for all vertices */
2306   float         *ewgts          = NULL;   /* weights for all edges */
2307   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2308   char          *outassignname  = NULL;   /*  name of assignment output file */
2309   char          *outfilename    = NULL;   /* output file name */
2310   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2311   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2312   int            mesh_dims[3];            /* dimensions of mesh of processors */
2313   double        *goal          = NULL;    /* desired set sizes for each set */
2314   int            global_method = 1;       /* global partitioning algorithm */
2315   int            local_method  = 1;       /* local partitioning algorithm */
2316   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2317   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2318   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2319   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2320   long           seed          = 123636512; /* for random graph mutations */
2321   short int     *assignment;              /* Output partition */
2322   int            fd_stdout, fd_pipe[2];
2323   PetscInt      *points;
2324   PetscMPIInt    commSize;
2325   int            i, v, p;
2326   PetscErrorCode ierr;
2327 
2328   PetscFunctionBegin;
2329   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2330   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2331   if (!numVertices) {
2332     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2333     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2334     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2335     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2336     PetscFunctionReturn(0);
2337   }
2338   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2339   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2340 
2341   if (global_method == INERTIAL_METHOD) {
2342     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2343     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2344   }
2345   mesh_dims[0] = commSize;
2346   mesh_dims[1] = 1;
2347   mesh_dims[2] = 1;
2348   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2349   /* Chaco outputs to stdout. We redirect this to a buffer. */
2350   /* TODO: check error codes for UNIX calls */
2351 #if defined(PETSC_HAVE_UNISTD_H)
2352   {
2353     int piperet;
2354     piperet = pipe(fd_pipe);
2355     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2356     fd_stdout = dup(1);
2357     close(1);
2358     dup2(fd_pipe[1], 1);
2359   }
2360 #endif
2361   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2362                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2363                    vmax, ndims, eigtol, seed);
2364 #if defined(PETSC_HAVE_UNISTD_H)
2365   {
2366     char msgLog[10000];
2367     int  count;
2368 
2369     fflush(stdout);
2370     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2371     if (count < 0) count = 0;
2372     msgLog[count] = 0;
2373     close(1);
2374     dup2(fd_stdout, 1);
2375     close(fd_stdout);
2376     close(fd_pipe[0]);
2377     close(fd_pipe[1]);
2378     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2379   }
2380 #endif
2381   /* Convert to PetscSection+IS */
2382   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2383   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2384   for (v = 0; v < nvtxs; ++v) {
2385     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2386   }
2387   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2388   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2389   for (p = 0, i = 0; p < commSize; ++p) {
2390     for (v = 0; v < nvtxs; ++v) {
2391       if (assignment[v] == p) points[i++] = v;
2392     }
2393   }
2394   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2395   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2396   if (global_method == INERTIAL_METHOD) {
2397     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2398   }
2399   ierr = PetscFree(assignment);CHKERRQ(ierr);
2400   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2401   PetscFunctionReturn(0);
2402 }
2403 #endif
2404 
2405 #if defined(PETSC_HAVE_PARMETIS)
2406 #include <parmetis.h>
2407 
2408 #undef __FUNCT__
2409 #define __FUNCT__ "DMPlexPartition_ParMetis"
2410 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2411 {
2412   MPI_Comm       comm;
2413   PetscInt       nvtxs      = numVertices; // The number of vertices in full graph
2414   PetscInt      *vtxdist;                  // Distribution of vertices across processes
2415   PetscInt      *xadj       = start;       // Start of edge list for each vertex
2416   PetscInt      *adjncy     = adjacency;   // Edge lists for all vertices
2417   PetscInt      *vwgt       = NULL;        // Vertex weights
2418   PetscInt      *adjwgt     = NULL;        // Edge weights
2419   PetscInt       wgtflag    = 0;           // Indicates which weights are present
2420   PetscInt       numflag    = 0;           // Indicates initial offset (0 or 1)
2421   PetscInt       ncon       = 1;           // The number of weights per vertex
2422   PetscInt       nparts;                   // The number of partitions
2423   PetscReal     *tpwgts;                   // The fraction of vertex weights assigned to each partition
2424   PetscReal     *ubvec;                    // The balance intolerance for vertex weights
2425   PetscInt       options[5];               // Options
2426   // Outputs
2427   PetscInt       edgeCut;                  // The number of edges cut by the partition
2428   PetscInt      *assignment, *points;
2429   PetscMPIInt    commSize, rank, p, v, i;
2430   PetscErrorCode ierr;
2431 
2432   PetscFunctionBegin;
2433   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
2434   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2435   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2436   nparts = commSize;
2437   options[0] = 0; /* Use all defaults */
2438   /* Calculate vertex distribution */
2439   ierr = PetscMalloc4(nparts+1,PetscInt,&vtxdist,nparts*ncon,PetscReal,&tpwgts,ncon,PetscReal,&ubvec,nvtxs,PetscInt,&assignment);CHKERRQ(ierr);
2440   vtxdist[0] = 0;
2441   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
2442   for (p = 2; p <= nparts; ++p) {
2443     vtxdist[p] += vtxdist[p-1];
2444   }
2445   /* Calculate weights */
2446   for (p = 0; p < nparts; ++p) {
2447     tpwgts[p] = 1.0/nparts;
2448   }
2449   ubvec[0] = 1.05;
2450 
2451   if (nparts == 1) {
2452     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));
2453   } else {
2454     if (vtxdist[1] == vtxdist[nparts]) {
2455       if (!rank) {
2456         PetscStackPush("METIS_PartGraphKway");
2457         ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment);
2458         PetscStackPop;
2459         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
2460       }
2461     } else {
2462       PetscStackPush("ParMETIS_V3_PartKway");
2463       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm);
2464       PetscStackPop;
2465       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
2466     }
2467   }
2468   /* Convert to PetscSection+IS */
2469   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2470   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2471   for (v = 0; v < nvtxs; ++v) {
2472     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2473   }
2474   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2475   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2476   for (p = 0, i = 0; p < commSize; ++p) {
2477     for (v = 0; v < nvtxs; ++v) {
2478       if (assignment[v] == p) points[i++] = v;
2479     }
2480   }
2481   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2482   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2483   ierr = PetscFree4(vtxdist,tpwgts,ubvec,assignment);CHKERRQ(ierr);
2484   PetscFunctionReturn(0);
2485 }
2486 #endif
2487 
2488 #undef __FUNCT__
2489 #define __FUNCT__ "DMPlexEnlargePartition"
2490 /* Expand the partition by BFS on the adjacency graph */
2491 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2492 {
2493   PetscHashI      h;
2494   const PetscInt *points;
2495   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2496   PetscInt        pStart, pEnd, part, q;
2497   PetscErrorCode  ierr;
2498 
2499   PetscFunctionBegin;
2500   PetscHashICreate(h);
2501   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2502   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2503   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2504   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2505   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2506   for (part = pStart; part < pEnd; ++part) {
2507     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2508 
2509     PetscHashIClear(h);
2510     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2511     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2512     /* Add all existing points to h */
2513     for (p = 0; p < numPoints; ++p) {
2514       const PetscInt point = points[off+p];
2515       PetscHashIAdd(h, point, 1);
2516     }
2517     PetscHashISize(h, nP);
2518     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2519     /* Add all points in next BFS level */
2520     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2521     for (p = 0; p < numPoints; ++p) {
2522       const PetscInt point = points[off+p];
2523       PetscInt       s     = start[point], e = start[point+1], a;
2524 
2525       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2526     }
2527     PetscHashISize(h, numNewPoints);
2528     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2529     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2530     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2531     totPoints += numNewPoints;
2532   }
2533   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2534   PetscHashIDestroy(h);
2535   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2536   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2537   for (part = pStart, q = 0; part < pEnd; ++part) {
2538     PetscInt numPoints, p;
2539 
2540     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2541     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2542     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2543   }
2544   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2545   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2546   PetscFunctionReturn(0);
2547 }
2548 
2549 #undef __FUNCT__
2550 #define __FUNCT__ "DMPlexCreatePartition"
2551 /*
2552   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2553 
2554   Collective on DM
2555 
2556   Input Parameters:
2557   + dm - The DM
2558   . height - The height for points in the partition
2559   - enlarge - Expand each partition with neighbors
2560 
2561   Output Parameters:
2562   + partSection - The PetscSection giving the division of points by partition
2563   . partition - The list of points by partition
2564   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2565   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2566 
2567   Level: developer
2568 
2569 .seealso DMPlexDistribute()
2570 */
2571 PetscErrorCode DMPlexCreatePartition(DM dm, const char name[], PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2572 {
2573   char           partname[1024];
2574   PetscBool      isChaco = PETSC_FALSE, isMetis = PETSC_FALSE, flg;
2575   PetscMPIInt    size;
2576   PetscErrorCode ierr;
2577 
2578   PetscFunctionBegin;
2579   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2580 
2581   *origPartSection = NULL;
2582   *origPartition   = NULL;
2583   if (size == 1) {
2584     PetscInt *points;
2585     PetscInt  cStart, cEnd, c;
2586 
2587     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2588     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2589     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2590     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2591     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2592     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2593     for (c = cStart; c < cEnd; ++c) points[c] = c;
2594     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2595     PetscFunctionReturn(0);
2596   }
2597   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_partitioner", partname, 1024, &flg);CHKERRQ(ierr);
2598   if (flg) name = partname;
2599   if (name) {
2600     ierr = PetscStrcmp(name, "chaco", &isChaco);CHKERRQ(ierr);
2601     ierr = PetscStrcmp(name, "metis", &isMetis);CHKERRQ(ierr);
2602   }
2603   if (height == 0) {
2604     PetscInt  numVertices;
2605     PetscInt *start     = NULL;
2606     PetscInt *adjacency = NULL;
2607 
2608     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2609     if (!name || isChaco) {
2610 #if defined(PETSC_HAVE_CHACO)
2611       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2612 #else
2613       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
2614 #endif
2615     } else if (isMetis) {
2616 #if defined(PETSC_HAVE_PARMETIS)
2617       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2618 #endif
2619     } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Unknown mesh partitioning package %s", name);
2620     if (enlarge) {
2621       *origPartSection = *partSection;
2622       *origPartition   = *partition;
2623 
2624       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2625     }
2626     ierr = PetscFree(start);CHKERRQ(ierr);
2627     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2628 # if 0
2629   } else if (height == 1) {
2630     /* Build the dual graph for faces and partition the hypergraph */
2631     PetscInt numEdges;
2632 
2633     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2634     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2635     destroyCSR(numEdges, start, adjacency);
2636 #endif
2637   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2638   PetscFunctionReturn(0);
2639 }
2640 
2641 #undef __FUNCT__
2642 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2643 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2644 {
2645   /* const PetscInt  height = 0; */
2646   const PetscInt *partArray;
2647   PetscInt       *allPoints, *packPoints;
2648   PetscInt        rStart, rEnd, rank, pStart, pEnd, newSize;
2649   PetscErrorCode  ierr;
2650   PetscBT         bt;
2651   PetscSegBuffer  segpack,segpart;
2652 
2653   PetscFunctionBegin;
2654   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2655   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2656   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2657   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2658   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
2659   ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr);
2660   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr);
2661   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr);
2662   for (rank = rStart; rank < rEnd; ++rank) {
2663     PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;
2664 
2665     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2666     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2667     for (p = 0; p < numPoints; ++p) {
2668       PetscInt  point   = partArray[offset+p], closureSize, c;
2669       PetscInt *closure = NULL;
2670 
2671       /* TODO Include support for height > 0 case */
2672       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2673       for (c=0; c<closureSize; c++) {
2674         PetscInt cpoint = closure[c*2];
2675         if (!PetscBTLookupSet(bt,cpoint-pStart)) {
2676           PetscInt *PETSC_RESTRICT pt;
2677           partSize++;
2678           ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr);
2679           *pt = cpoint;
2680         }
2681       }
2682       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2683     }
2684     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2685     ierr = PetscSegBufferGetInts(segpack,partSize,&placePoints);CHKERRQ(ierr);
2686     ierr = PetscSegBufferExtractTo(segpart,placePoints);CHKERRQ(ierr);
2687     ierr = PetscSortInt(partSize,placePoints);CHKERRQ(ierr);
2688     for (p=0; p<partSize; p++) {ierr = PetscBTClear(bt,placePoints[p]-pStart);CHKERRQ(ierr);}
2689   }
2690   ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);
2691   ierr = PetscSegBufferDestroy(&segpart);CHKERRQ(ierr);
2692 
2693   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2694   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2695   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2696 
2697   ierr = PetscSegBufferExtractInPlace(segpack,&packPoints);CHKERRQ(ierr);
2698   for (rank = rStart; rank < rEnd; ++rank) {
2699     PetscInt numPoints, offset;
2700 
2701     ierr = PetscSectionGetDof(*section, rank, &numPoints);CHKERRQ(ierr);
2702     ierr = PetscSectionGetOffset(*section, rank, &offset);CHKERRQ(ierr);
2703     ierr = PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));CHKERRQ(ierr);
2704     packPoints += numPoints;
2705   }
2706 
2707   ierr = PetscSegBufferDestroy(&segpack);CHKERRQ(ierr);
2708   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2709   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2710   PetscFunctionReturn(0);
2711 }
2712 
2713 #undef __FUNCT__
2714 #define __FUNCT__ "DMPlexDistributeField"
2715 /*
2716   Input Parameters:
2717 . originalSection
2718 , originalVec
2719 
2720   Output Parameters:
2721 . newSection
2722 . newVec
2723 */
2724 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2725 {
2726   PetscSF        fieldSF;
2727   PetscInt      *remoteOffsets, fieldSize;
2728   PetscScalar   *originalValues, *newValues;
2729   PetscErrorCode ierr;
2730 
2731   PetscFunctionBegin;
2732   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
2733 
2734   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
2735   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
2736   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
2737 
2738   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
2739   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
2740   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2741   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2742   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2743   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2744   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
2745   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
2746   PetscFunctionReturn(0);
2747 }
2748 
2749 #undef __FUNCT__
2750 #define __FUNCT__ "DMPlexDistribute"
2751 /*@C
2752   DMPlexDistribute - Distributes the mesh and any associated sections.
2753 
2754   Not Collective
2755 
2756   Input Parameter:
2757 + dm  - The original DMPlex object
2758 . partitioner - The partitioning package, or NULL for the default
2759 - overlap - The overlap of partitions, 0 is the default
2760 
2761   Output Parameter:
2762 . parallelMesh - The distributed DMPlex object, or NULL
2763 
2764   Note: If the mesh was not distributed, the return value is NULL
2765 
2766   Level: intermediate
2767 
2768 .keywords: mesh, elements
2769 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2770 @*/
2771 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
2772 {
2773   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2774   MPI_Comm               comm;
2775   const PetscInt         height = 0;
2776   PetscInt               dim, numRemoteRanks;
2777   IS                     origCellPart,        cellPart,        part;
2778   PetscSection           origCellPartSection, cellPartSection, partSection;
2779   PetscSFNode           *remoteRanks;
2780   PetscSF                partSF, pointSF, coneSF;
2781   ISLocalToGlobalMapping renumbering;
2782   PetscSection           originalConeSection, newConeSection;
2783   PetscInt              *remoteOffsets;
2784   PetscInt              *cones, *newCones, newConesSize;
2785   PetscBool              flg;
2786   PetscMPIInt            rank, numProcs, p;
2787   PetscErrorCode         ierr;
2788 
2789   PetscFunctionBegin;
2790   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2791   PetscValidPointer(dmParallel,4);
2792 
2793   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2794   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2795   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2796   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
2797 
2798   *dmParallel = NULL;
2799   if (numProcs == 1) PetscFunctionReturn(0);
2800 
2801   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2802   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2803   ierr = PetscLogEventBegin(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
2804   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2805   ierr = DMPlexCreatePartition(dm, partitioner, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
2806   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2807   if (!rank) numRemoteRanks = numProcs;
2808   else       numRemoteRanks = 0;
2809   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
2810   for (p = 0; p < numRemoteRanks; ++p) {
2811     remoteRanks[p].rank  = p;
2812     remoteRanks[p].index = 0;
2813   }
2814   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
2815   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
2816   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
2817   if (flg) {
2818     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
2819     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2820     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
2821     if (origCellPart) {
2822       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
2823       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2824       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
2825     }
2826     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
2827   }
2828   /* Close the partition over the mesh */
2829   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
2830   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
2831   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
2832   /* Create new mesh */
2833   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
2834   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
2835   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
2836   pmesh = (DM_Plex*) (*dmParallel)->data;
2837   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
2838   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
2839   if (flg) {
2840     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
2841     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2842     ierr = ISView(part, NULL);CHKERRQ(ierr);
2843     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
2844     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
2845     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
2846   }
2847   ierr = PetscLogEventEnd(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
2848   /* Distribute cone section */
2849   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
2850   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
2851   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
2852   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
2853   {
2854     PetscInt pStart, pEnd, p;
2855 
2856     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
2857     for (p = pStart; p < pEnd; ++p) {
2858       PetscInt coneSize;
2859       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
2860       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
2861     }
2862   }
2863   /* Communicate and renumber cones */
2864   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
2865   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2866   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
2867   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2868   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2869   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
2870   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
2871   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
2872   if (flg) {
2873     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
2874     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2875     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
2876     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2877     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
2878   }
2879   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
2880   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
2881   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2882   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2883   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
2884   /* Create supports and stratify sieve */
2885   {
2886     PetscInt pStart, pEnd;
2887 
2888     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2889     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2890   }
2891   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
2892   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
2893   /* Distribute Coordinates */
2894   {
2895     PetscSection originalCoordSection, newCoordSection;
2896     Vec          originalCoordinates, newCoordinates;
2897     const char  *name;
2898 
2899     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
2900     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
2901     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
2902     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
2903     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
2904     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
2905 
2906     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
2907     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
2908     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
2909   }
2910   /* Distribute labels */
2911   ierr = PetscLogEventBegin(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
2912   {
2913     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
2914     PetscInt numLabels = 0, l;
2915 
2916     /* Bcast number of labels */
2917     while (next) {
2918       ++numLabels; next = next->next;
2919     }
2920     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2921     next = mesh->labels;
2922     for (l = 0; l < numLabels; ++l) {
2923       DMLabel         newLabel;
2924       const PetscInt *partArray;
2925       char           *name;
2926       PetscInt       *stratumSizes = NULL, *points = NULL;
2927       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
2928       PetscInt        nameSize, s, p;
2929       PetscBool       isdepth;
2930       size_t          len = 0;
2931 
2932       /* Bcast name (could filter for no points) */
2933       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
2934       nameSize = len;
2935       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2936       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
2937       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
2938       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
2939       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
2940       if (isdepth) {            /* skip because "depth" is not distributed */
2941         ierr = PetscFree(name);CHKERRQ(ierr);
2942         if (!rank) next = next->next;
2943         continue;
2944       }
2945       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
2946       newLabel->name = name;
2947       /* Bcast numStrata (could filter for no points in stratum) */
2948       if (!rank) newLabel->numStrata = next->numStrata;
2949       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2950       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
2951                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
2952                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
2953       /* Bcast stratumValues (could filter for no points in stratum) */
2954       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
2955       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2956       /* Find size on each process and Scatter */
2957       if (!rank) {
2958         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
2959         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
2960         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
2961         for (s = 0; s < next->numStrata; ++s) {
2962           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2963             const PetscInt point = next->points[p];
2964             PetscInt       proc;
2965 
2966             for (proc = 0; proc < numProcs; ++proc) {
2967               PetscInt dof, off, pPart;
2968 
2969               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2970               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2971               for (pPart = off; pPart < off+dof; ++pPart) {
2972                 if (partArray[pPart] == point) {
2973                   ++stratumSizes[proc*next->numStrata+s];
2974                   break;
2975                 }
2976               }
2977             }
2978           }
2979         }
2980         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
2981       }
2982       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2983       /* Calculate stratumOffsets */
2984       newLabel->stratumOffsets[0] = 0;
2985       for (s = 0; s < newLabel->numStrata; ++s) {
2986         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
2987       }
2988       /* Pack points and Scatter */
2989       if (!rank) {
2990         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
2991         displs[0] = 0;
2992         for (p = 0; p < numProcs; ++p) {
2993           sendcnts[p] = 0;
2994           for (s = 0; s < next->numStrata; ++s) {
2995             sendcnts[p] += stratumSizes[p*next->numStrata+s];
2996           }
2997           offsets[p]  = displs[p];
2998           displs[p+1] = displs[p] + sendcnts[p];
2999         }
3000         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3001         for (s = 0; s < next->numStrata; ++s) {
3002           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3003             const PetscInt point = next->points[p];
3004             PetscInt       proc;
3005 
3006             for (proc = 0; proc < numProcs; ++proc) {
3007               PetscInt dof, off, pPart;
3008 
3009               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3010               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3011               for (pPart = off; pPart < off+dof; ++pPart) {
3012                 if (partArray[pPart] == point) {
3013                   points[offsets[proc]++] = point;
3014                   break;
3015                 }
3016               }
3017             }
3018           }
3019         }
3020       }
3021       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3022       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3023       ierr = PetscFree(points);CHKERRQ(ierr);
3024       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3025       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3026       /* Renumber points */
3027       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3028       /* Sort points */
3029       for (s = 0; s < newLabel->numStrata; ++s) {
3030         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3031       }
3032       /* Insert into list */
3033       if (newNext) newNext->next = newLabel;
3034       else pmesh->labels = newLabel;
3035       newNext = newLabel;
3036       if (!rank) next = next->next;
3037     }
3038   }
3039   ierr = PetscLogEventEnd(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
3040   /* Cleanup Partition */
3041   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3042   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3043   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3044   ierr = ISDestroy(&part);CHKERRQ(ierr);
3045   /* Create point SF for parallel mesh */
3046   ierr = PetscLogEventBegin(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
3047   {
3048     const PetscInt *leaves;
3049     PetscSFNode    *remotePoints, *rowners, *lowners;
3050     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3051     PetscInt        pStart, pEnd;
3052 
3053     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3054     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3055     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3056     for (p=0; p<numRoots; p++) {
3057       rowners[p].rank  = -1;
3058       rowners[p].index = -1;
3059     }
3060     if (origCellPart) {
3061       /* Make sure cells in the original partition are not assigned to other procs */
3062       const PetscInt *origCells;
3063 
3064       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3065       for (p = 0; p < numProcs; ++p) {
3066         PetscInt dof, off, d;
3067 
3068         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3069         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3070         for (d = off; d < off+dof; ++d) {
3071           rowners[origCells[d]].rank = p;
3072         }
3073       }
3074       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3075     }
3076     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3077     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3078 
3079     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3080     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3081     for (p = 0; p < numLeaves; ++p) {
3082       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3083         lowners[p].rank  = rank;
3084         lowners[p].index = leaves ? leaves[p] : p;
3085       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3086         lowners[p].rank  = -2;
3087         lowners[p].index = -2;
3088       }
3089     }
3090     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3091       rowners[p].rank  = -3;
3092       rowners[p].index = -3;
3093     }
3094     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3095     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3096     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3097     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3098     for (p = 0; p < numLeaves; ++p) {
3099       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3100       if (lowners[p].rank != rank) ++numGhostPoints;
3101     }
3102     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3103     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3104     for (p = 0, gp = 0; p < numLeaves; ++p) {
3105       if (lowners[p].rank != rank) {
3106         ghostPoints[gp]        = leaves ? leaves[p] : p;
3107         remotePoints[gp].rank  = lowners[p].rank;
3108         remotePoints[gp].index = lowners[p].index;
3109         ++gp;
3110       }
3111     }
3112     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3113     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3114     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3115   }
3116   ierr = PetscLogEventEnd(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
3117   /* Cleanup */
3118   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3119   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3120   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3121   PetscFunctionReturn(0);
3122 }
3123 
3124 #undef __FUNCT__
3125 #define __FUNCT__ "DMPlexInvertCell"
3126 /*@C
3127   DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched.
3128 
3129   Input Parameters:
3130 + numCorners - The number of vertices in a cell
3131 - cone - The incoming cone
3132 
3133   Output Parameter:
3134 . cone - The inverted cone (in-place)
3135 
3136   Level: developer
3137 
3138 .seealso: DMPlexGenerate()
3139 @*/
3140 PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[])
3141 {
3142   int tmpc;
3143 
3144   PetscFunctionBegin;
3145   if (dim != 3) PetscFunctionReturn(0);
3146   switch (numCorners) {
3147   case 4:
3148     tmpc    = cone[0];
3149     cone[0] = cone[1];
3150     cone[1] = tmpc;
3151     break;
3152   case 8:
3153     tmpc    = cone[1];
3154     cone[1] = cone[3];
3155     cone[3] = tmpc;
3156     break;
3157   default: break;
3158   }
3159   PetscFunctionReturn(0);
3160 }
3161 
3162 #undef __FUNCT__
3163 #define __FUNCT__ "DMPlexInvertCells_Internal"
3164 /* This is to fix the tetrahedron orientation from TetGen */
3165 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[])
3166 {
3167   PetscInt       bound = numCells*numCorners, coff;
3168   PetscErrorCode ierr;
3169 
3170   PetscFunctionBegin;
3171   for (coff = 0; coff < bound; coff += numCorners) {
3172     ierr = DMPlexInvertCell(dim, numCorners, &cells[coff]);CHKERRQ(ierr);
3173   }
3174   PetscFunctionReturn(0);
3175 }
3176 
3177 #if defined(PETSC_HAVE_TRIANGLE)
3178 #include <triangle.h>
3179 
3180 #undef __FUNCT__
3181 #define __FUNCT__ "InitInput_Triangle"
3182 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3183 {
3184   PetscFunctionBegin;
3185   inputCtx->numberofpoints             = 0;
3186   inputCtx->numberofpointattributes    = 0;
3187   inputCtx->pointlist                  = NULL;
3188   inputCtx->pointattributelist         = NULL;
3189   inputCtx->pointmarkerlist            = NULL;
3190   inputCtx->numberofsegments           = 0;
3191   inputCtx->segmentlist                = NULL;
3192   inputCtx->segmentmarkerlist          = NULL;
3193   inputCtx->numberoftriangleattributes = 0;
3194   inputCtx->trianglelist               = NULL;
3195   inputCtx->numberofholes              = 0;
3196   inputCtx->holelist                   = NULL;
3197   inputCtx->numberofregions            = 0;
3198   inputCtx->regionlist                 = NULL;
3199   PetscFunctionReturn(0);
3200 }
3201 
3202 #undef __FUNCT__
3203 #define __FUNCT__ "InitOutput_Triangle"
3204 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3205 {
3206   PetscFunctionBegin;
3207   outputCtx->numberofpoints        = 0;
3208   outputCtx->pointlist             = NULL;
3209   outputCtx->pointattributelist    = NULL;
3210   outputCtx->pointmarkerlist       = NULL;
3211   outputCtx->numberoftriangles     = 0;
3212   outputCtx->trianglelist          = NULL;
3213   outputCtx->triangleattributelist = NULL;
3214   outputCtx->neighborlist          = NULL;
3215   outputCtx->segmentlist           = NULL;
3216   outputCtx->segmentmarkerlist     = NULL;
3217   outputCtx->numberofedges         = 0;
3218   outputCtx->edgelist              = NULL;
3219   outputCtx->edgemarkerlist        = NULL;
3220   PetscFunctionReturn(0);
3221 }
3222 
3223 #undef __FUNCT__
3224 #define __FUNCT__ "FiniOutput_Triangle"
3225 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3226 {
3227   PetscFunctionBegin;
3228   free(outputCtx->pointmarkerlist);
3229   free(outputCtx->edgelist);
3230   free(outputCtx->edgemarkerlist);
3231   free(outputCtx->trianglelist);
3232   free(outputCtx->neighborlist);
3233   PetscFunctionReturn(0);
3234 }
3235 
3236 #undef __FUNCT__
3237 #define __FUNCT__ "DMPlexGenerate_Triangle"
3238 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3239 {
3240   MPI_Comm             comm;
3241   PetscInt             dim              = 2;
3242   const PetscBool      createConvexHull = PETSC_FALSE;
3243   const PetscBool      constrained      = PETSC_FALSE;
3244   struct triangulateio in;
3245   struct triangulateio out;
3246   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3247   PetscMPIInt          rank;
3248   PetscErrorCode       ierr;
3249 
3250   PetscFunctionBegin;
3251   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3252   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3253   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3254   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3255   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3256 
3257   in.numberofpoints = vEnd - vStart;
3258   if (in.numberofpoints > 0) {
3259     PetscSection coordSection;
3260     Vec          coordinates;
3261     PetscScalar *array;
3262 
3263     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3264     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3265     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3266     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3267     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3268     for (v = vStart; v < vEnd; ++v) {
3269       const PetscInt idx = v - vStart;
3270       PetscInt       off, d;
3271 
3272       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3273       for (d = 0; d < dim; ++d) {
3274         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3275       }
3276       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3277     }
3278     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3279   }
3280   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3281   in.numberofsegments = eEnd - eStart;
3282   if (in.numberofsegments > 0) {
3283     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3284     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3285     for (e = eStart; e < eEnd; ++e) {
3286       const PetscInt  idx = e - eStart;
3287       const PetscInt *cone;
3288 
3289       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3290 
3291       in.segmentlist[idx*2+0] = cone[0] - vStart;
3292       in.segmentlist[idx*2+1] = cone[1] - vStart;
3293 
3294       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3295     }
3296   }
3297 #if 0 /* Do not currently support holes */
3298   PetscReal *holeCoords;
3299   PetscInt   h, d;
3300 
3301   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3302   if (in.numberofholes > 0) {
3303     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3304     for (h = 0; h < in.numberofholes; ++h) {
3305       for (d = 0; d < dim; ++d) {
3306         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3307       }
3308     }
3309   }
3310 #endif
3311   if (!rank) {
3312     char args[32];
3313 
3314     /* Take away 'Q' for verbose output */
3315     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3316     if (createConvexHull) {
3317       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3318     }
3319     if (constrained) {
3320       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3321     }
3322     triangulate(args, &in, &out, NULL);
3323   }
3324   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3325   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3326   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3327   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3328   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3329 
3330   {
3331     const PetscInt numCorners  = 3;
3332     const PetscInt numCells    = out.numberoftriangles;
3333     const PetscInt numVertices = out.numberofpoints;
3334     const int     *cells      = out.trianglelist;
3335     const double  *meshCoords = out.pointlist;
3336 
3337     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3338     /* Set labels */
3339     for (v = 0; v < numVertices; ++v) {
3340       if (out.pointmarkerlist[v]) {
3341         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3342       }
3343     }
3344     if (interpolate) {
3345       for (e = 0; e < out.numberofedges; e++) {
3346         if (out.edgemarkerlist[e]) {
3347           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3348           const PetscInt *edges;
3349           PetscInt        numEdges;
3350 
3351           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3352           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3353           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3354           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3355         }
3356       }
3357     }
3358     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3359   }
3360 #if 0 /* Do not currently support holes */
3361   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3362 #endif
3363   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3364   PetscFunctionReturn(0);
3365 }
3366 
3367 #undef __FUNCT__
3368 #define __FUNCT__ "DMPlexRefine_Triangle"
3369 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3370 {
3371   MPI_Comm             comm;
3372   PetscInt             dim  = 2;
3373   struct triangulateio in;
3374   struct triangulateio out;
3375   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3376   PetscMPIInt          rank;
3377   PetscErrorCode       ierr;
3378 
3379   PetscFunctionBegin;
3380   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3381   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3382   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3383   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3384   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3385   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3386   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3387 
3388   in.numberofpoints = vEnd - vStart;
3389   if (in.numberofpoints > 0) {
3390     PetscSection coordSection;
3391     Vec          coordinates;
3392     PetscScalar *array;
3393 
3394     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3395     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3396     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3397     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3398     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3399     for (v = vStart; v < vEnd; ++v) {
3400       const PetscInt idx = v - vStart;
3401       PetscInt       off, d;
3402 
3403       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3404       for (d = 0; d < dim; ++d) {
3405         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3406       }
3407       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3408     }
3409     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3410   }
3411   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3412 
3413   in.numberofcorners   = 3;
3414   in.numberoftriangles = cEnd - cStart;
3415 
3416   in.trianglearealist  = (double*) maxVolumes;
3417   if (in.numberoftriangles > 0) {
3418     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3419     for (c = cStart; c < cEnd; ++c) {
3420       const PetscInt idx      = c - cStart;
3421       PetscInt      *closure = NULL;
3422       PetscInt       closureSize;
3423 
3424       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3425       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3426       for (v = 0; v < 3; ++v) {
3427         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3428       }
3429       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3430     }
3431   }
3432   /* TODO: Segment markers are missing on input */
3433 #if 0 /* Do not currently support holes */
3434   PetscReal *holeCoords;
3435   PetscInt   h, d;
3436 
3437   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3438   if (in.numberofholes > 0) {
3439     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3440     for (h = 0; h < in.numberofholes; ++h) {
3441       for (d = 0; d < dim; ++d) {
3442         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3443       }
3444     }
3445   }
3446 #endif
3447   if (!rank) {
3448     char args[32];
3449 
3450     /* Take away 'Q' for verbose output */
3451     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3452     triangulate(args, &in, &out, NULL);
3453   }
3454   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3455   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3456   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3457   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3458   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3459 
3460   {
3461     const PetscInt numCorners  = 3;
3462     const PetscInt numCells    = out.numberoftriangles;
3463     const PetscInt numVertices = out.numberofpoints;
3464     const int     *cells      = out.trianglelist;
3465     const double  *meshCoords = out.pointlist;
3466     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3467 
3468     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3469     /* Set labels */
3470     for (v = 0; v < numVertices; ++v) {
3471       if (out.pointmarkerlist[v]) {
3472         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3473       }
3474     }
3475     if (interpolate) {
3476       PetscInt e;
3477 
3478       for (e = 0; e < out.numberofedges; e++) {
3479         if (out.edgemarkerlist[e]) {
3480           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3481           const PetscInt *edges;
3482           PetscInt        numEdges;
3483 
3484           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3485           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3486           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3487           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3488         }
3489       }
3490     }
3491     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3492   }
3493 #if 0 /* Do not currently support holes */
3494   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3495 #endif
3496   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3497   PetscFunctionReturn(0);
3498 }
3499 #endif
3500 
3501 #if defined(PETSC_HAVE_TETGEN)
3502 #include <tetgen.h>
3503 #undef __FUNCT__
3504 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3505 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3506 {
3507   MPI_Comm       comm;
3508   const PetscInt dim  = 3;
3509   ::tetgenio     in;
3510   ::tetgenio     out;
3511   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3512   PetscMPIInt    rank;
3513   PetscErrorCode ierr;
3514 
3515   PetscFunctionBegin;
3516   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3517   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3518   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3519   in.numberofpoints = vEnd - vStart;
3520   if (in.numberofpoints > 0) {
3521     PetscSection coordSection;
3522     Vec          coordinates;
3523     PetscScalar *array;
3524 
3525     in.pointlist       = new double[in.numberofpoints*dim];
3526     in.pointmarkerlist = new int[in.numberofpoints];
3527 
3528     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3529     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3530     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3531     for (v = vStart; v < vEnd; ++v) {
3532       const PetscInt idx = v - vStart;
3533       PetscInt       off, d;
3534 
3535       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3536       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3537       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3538     }
3539     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3540   }
3541   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3542 
3543   in.numberoffacets = fEnd - fStart;
3544   if (in.numberoffacets > 0) {
3545     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3546     in.facetmarkerlist = new int[in.numberoffacets];
3547     for (f = fStart; f < fEnd; ++f) {
3548       const PetscInt idx     = f - fStart;
3549       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3550 
3551       in.facetlist[idx].numberofpolygons = 1;
3552       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3553       in.facetlist[idx].numberofholes    = 0;
3554       in.facetlist[idx].holelist         = NULL;
3555 
3556       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3557       for (p = 0; p < numPoints*2; p += 2) {
3558         const PetscInt point = points[p];
3559         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3560       }
3561 
3562       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3563       poly->numberofvertices = numVertices;
3564       poly->vertexlist       = new int[poly->numberofvertices];
3565       for (v = 0; v < numVertices; ++v) {
3566         const PetscInt vIdx = points[v] - vStart;
3567         poly->vertexlist[v] = vIdx;
3568       }
3569       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3570       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3571     }
3572   }
3573   if (!rank) {
3574     char args[32];
3575 
3576     /* Take away 'Q' for verbose output */
3577     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3578     ::tetrahedralize(args, &in, &out);
3579   }
3580   {
3581     const PetscInt numCorners  = 4;
3582     const PetscInt numCells    = out.numberoftetrahedra;
3583     const PetscInt numVertices = out.numberofpoints;
3584     const double   *meshCoords = out.pointlist;
3585     int            *cells      = out.tetrahedronlist;
3586 
3587     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3588     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3589     /* Set labels */
3590     for (v = 0; v < numVertices; ++v) {
3591       if (out.pointmarkerlist[v]) {
3592         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3593       }
3594     }
3595     if (interpolate) {
3596       PetscInt e;
3597 
3598       for (e = 0; e < out.numberofedges; e++) {
3599         if (out.edgemarkerlist[e]) {
3600           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3601           const PetscInt *edges;
3602           PetscInt        numEdges;
3603 
3604           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3605           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3606           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3607           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3608         }
3609       }
3610       for (f = 0; f < out.numberoftrifaces; f++) {
3611         if (out.trifacemarkerlist[f]) {
3612           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3613           const PetscInt *faces;
3614           PetscInt        numFaces;
3615 
3616           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3617           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3618           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3619           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3620         }
3621       }
3622     }
3623     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3624   }
3625   PetscFunctionReturn(0);
3626 }
3627 
3628 #undef __FUNCT__
3629 #define __FUNCT__ "DMPlexRefine_Tetgen"
3630 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3631 {
3632   MPI_Comm       comm;
3633   const PetscInt dim  = 3;
3634   ::tetgenio     in;
3635   ::tetgenio     out;
3636   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3637   PetscMPIInt    rank;
3638   PetscErrorCode ierr;
3639 
3640   PetscFunctionBegin;
3641   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3642   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3643   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3644   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3645   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3646 
3647   in.numberofpoints = vEnd - vStart;
3648   if (in.numberofpoints > 0) {
3649     PetscSection coordSection;
3650     Vec          coordinates;
3651     PetscScalar *array;
3652 
3653     in.pointlist       = new double[in.numberofpoints*dim];
3654     in.pointmarkerlist = new int[in.numberofpoints];
3655 
3656     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3657     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3658     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3659     for (v = vStart; v < vEnd; ++v) {
3660       const PetscInt idx = v - vStart;
3661       PetscInt       off, d;
3662 
3663       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3664       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3665       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3666     }
3667     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3668   }
3669   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3670 
3671   in.numberofcorners       = 4;
3672   in.numberoftetrahedra    = cEnd - cStart;
3673   in.tetrahedronvolumelist = (double*) maxVolumes;
3674   if (in.numberoftetrahedra > 0) {
3675     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3676     for (c = cStart; c < cEnd; ++c) {
3677       const PetscInt idx      = c - cStart;
3678       PetscInt      *closure = NULL;
3679       PetscInt       closureSize;
3680 
3681       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3682       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3683       for (v = 0; v < 4; ++v) {
3684         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3685       }
3686       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3687     }
3688   }
3689   /* TODO: Put in boundary faces with markers */
3690   if (!rank) {
3691     char args[32];
3692 
3693     /* Take away 'Q' for verbose output */
3694     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3695     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3696     ::tetrahedralize(args, &in, &out);
3697   }
3698   in.tetrahedronvolumelist = NULL;
3699 
3700   {
3701     const PetscInt numCorners  = 4;
3702     const PetscInt numCells    = out.numberoftetrahedra;
3703     const PetscInt numVertices = out.numberofpoints;
3704     const double   *meshCoords = out.pointlist;
3705     int            *cells      = out.tetrahedronlist;
3706 
3707     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3708 
3709     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3710     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3711     /* Set labels */
3712     for (v = 0; v < numVertices; ++v) {
3713       if (out.pointmarkerlist[v]) {
3714         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3715       }
3716     }
3717     if (interpolate) {
3718       PetscInt e, f;
3719 
3720       for (e = 0; e < out.numberofedges; e++) {
3721         if (out.edgemarkerlist[e]) {
3722           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3723           const PetscInt *edges;
3724           PetscInt        numEdges;
3725 
3726           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3727           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3728           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3729           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3730         }
3731       }
3732       for (f = 0; f < out.numberoftrifaces; f++) {
3733         if (out.trifacemarkerlist[f]) {
3734           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3735           const PetscInt *faces;
3736           PetscInt        numFaces;
3737 
3738           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3739           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3740           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3741           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3742         }
3743       }
3744     }
3745     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3746   }
3747   PetscFunctionReturn(0);
3748 }
3749 #endif
3750 
3751 #if defined(PETSC_HAVE_CTETGEN)
3752 #include "ctetgen.h"
3753 
3754 #undef __FUNCT__
3755 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3756 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3757 {
3758   MPI_Comm       comm;
3759   const PetscInt dim  = 3;
3760   PLC           *in, *out;
3761   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3762   PetscMPIInt    rank;
3763   PetscErrorCode ierr;
3764 
3765   PetscFunctionBegin;
3766   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3767   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3768   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3769   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3770   ierr = PLCCreate(&in);CHKERRQ(ierr);
3771   ierr = PLCCreate(&out);CHKERRQ(ierr);
3772 
3773   in->numberofpoints = vEnd - vStart;
3774   if (in->numberofpoints > 0) {
3775     PetscSection coordSection;
3776     Vec          coordinates;
3777     PetscScalar *array;
3778 
3779     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3780     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3781     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3782     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3783     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3784     for (v = vStart; v < vEnd; ++v) {
3785       const PetscInt idx = v - vStart;
3786       PetscInt       off, d, m;
3787 
3788       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3789       for (d = 0; d < dim; ++d) {
3790         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3791       }
3792       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3793 
3794       in->pointmarkerlist[idx] = (int) m;
3795     }
3796     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3797   }
3798   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3799 
3800   in->numberoffacets = fEnd - fStart;
3801   if (in->numberoffacets > 0) {
3802     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
3803     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
3804     for (f = fStart; f < fEnd; ++f) {
3805       const PetscInt idx     = f - fStart;
3806       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3807       polygon       *poly;
3808 
3809       in->facetlist[idx].numberofpolygons = 1;
3810 
3811       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3812 
3813       in->facetlist[idx].numberofholes    = 0;
3814       in->facetlist[idx].holelist         = NULL;
3815 
3816       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3817       for (p = 0; p < numPoints*2; p += 2) {
3818         const PetscInt point = points[p];
3819         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3820       }
3821 
3822       poly                   = in->facetlist[idx].polygonlist;
3823       poly->numberofvertices = numVertices;
3824       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
3825       for (v = 0; v < numVertices; ++v) {
3826         const PetscInt vIdx = points[v] - vStart;
3827         poly->vertexlist[v] = vIdx;
3828       }
3829       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3830       in->facetmarkerlist[idx] = (int) m;
3831       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3832     }
3833   }
3834   if (!rank) {
3835     TetGenOpts t;
3836 
3837     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3838     t.in        = boundary; /* Should go away */
3839     t.plc       = 1;
3840     t.quality   = 1;
3841     t.edgesout  = 1;
3842     t.zeroindex = 1;
3843     t.quiet     = 1;
3844     t.verbose   = verbose;
3845     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3846     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3847   }
3848   {
3849     const PetscInt numCorners  = 4;
3850     const PetscInt numCells    = out->numberoftetrahedra;
3851     const PetscInt numVertices = out->numberofpoints;
3852     const double   *meshCoords = out->pointlist;
3853     int            *cells      = out->tetrahedronlist;
3854 
3855     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3856     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3857     /* Set labels */
3858     for (v = 0; v < numVertices; ++v) {
3859       if (out->pointmarkerlist[v]) {
3860         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3861       }
3862     }
3863     if (interpolate) {
3864       PetscInt e;
3865 
3866       for (e = 0; e < out->numberofedges; e++) {
3867         if (out->edgemarkerlist[e]) {
3868           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3869           const PetscInt *edges;
3870           PetscInt        numEdges;
3871 
3872           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3873           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3874           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3875           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3876         }
3877       }
3878       for (f = 0; f < out->numberoftrifaces; f++) {
3879         if (out->trifacemarkerlist[f]) {
3880           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3881           const PetscInt *faces;
3882           PetscInt        numFaces;
3883 
3884           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3885           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3886           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3887           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3888         }
3889       }
3890     }
3891     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3892   }
3893 
3894   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3895   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3896   PetscFunctionReturn(0);
3897 }
3898 
3899 #undef __FUNCT__
3900 #define __FUNCT__ "DMPlexRefine_CTetgen"
3901 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3902 {
3903   MPI_Comm       comm;
3904   const PetscInt dim  = 3;
3905   PLC           *in, *out;
3906   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3907   PetscMPIInt    rank;
3908   PetscErrorCode ierr;
3909 
3910   PetscFunctionBegin;
3911   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3912   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3913   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3914   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3915   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3916   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3917   ierr = PLCCreate(&in);CHKERRQ(ierr);
3918   ierr = PLCCreate(&out);CHKERRQ(ierr);
3919 
3920   in->numberofpoints = vEnd - vStart;
3921   if (in->numberofpoints > 0) {
3922     PetscSection coordSection;
3923     Vec          coordinates;
3924     PetscScalar *array;
3925 
3926     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3927     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3928     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3929     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3930     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3931     for (v = vStart; v < vEnd; ++v) {
3932       const PetscInt idx = v - vStart;
3933       PetscInt       off, d, m;
3934 
3935       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3936       for (d = 0; d < dim; ++d) {
3937         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3938       }
3939       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
3940 
3941       in->pointmarkerlist[idx] = (int) m;
3942     }
3943     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3944   }
3945   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3946 
3947   in->numberofcorners       = 4;
3948   in->numberoftetrahedra    = cEnd - cStart;
3949   in->tetrahedronvolumelist = maxVolumes;
3950   if (in->numberoftetrahedra > 0) {
3951     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
3952     for (c = cStart; c < cEnd; ++c) {
3953       const PetscInt idx      = c - cStart;
3954       PetscInt      *closure = NULL;
3955       PetscInt       closureSize;
3956 
3957       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3958       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3959       for (v = 0; v < 4; ++v) {
3960         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3961       }
3962       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3963     }
3964   }
3965   if (!rank) {
3966     TetGenOpts t;
3967 
3968     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3969 
3970     t.in        = dm; /* Should go away */
3971     t.refine    = 1;
3972     t.varvolume = 1;
3973     t.quality   = 1;
3974     t.edgesout  = 1;
3975     t.zeroindex = 1;
3976     t.quiet     = 1;
3977     t.verbose   = verbose; /* Change this */
3978 
3979     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
3980     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3981   }
3982   {
3983     const PetscInt numCorners  = 4;
3984     const PetscInt numCells    = out->numberoftetrahedra;
3985     const PetscInt numVertices = out->numberofpoints;
3986     const double   *meshCoords = out->pointlist;
3987     int            *cells      = out->tetrahedronlist;
3988     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3989 
3990     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3991     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3992     /* Set labels */
3993     for (v = 0; v < numVertices; ++v) {
3994       if (out->pointmarkerlist[v]) {
3995         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3996       }
3997     }
3998     if (interpolate) {
3999       PetscInt e, f;
4000 
4001       for (e = 0; e < out->numberofedges; e++) {
4002         if (out->edgemarkerlist[e]) {
4003           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4004           const PetscInt *edges;
4005           PetscInt        numEdges;
4006 
4007           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4008           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4009           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
4010           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4011         }
4012       }
4013       for (f = 0; f < out->numberoftrifaces; f++) {
4014         if (out->trifacemarkerlist[f]) {
4015           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4016           const PetscInt *faces;
4017           PetscInt        numFaces;
4018 
4019           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4020           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4021           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
4022           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4023         }
4024       }
4025     }
4026     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4027   }
4028   ierr = PLCDestroy(&in);CHKERRQ(ierr);
4029   ierr = PLCDestroy(&out);CHKERRQ(ierr);
4030   PetscFunctionReturn(0);
4031 }
4032 #endif
4033 
4034 #undef __FUNCT__
4035 #define __FUNCT__ "DMPlexGenerate"
4036 /*@C
4037   DMPlexGenerate - Generates a mesh.
4038 
4039   Not Collective
4040 
4041   Input Parameters:
4042 + boundary - The DMPlex boundary object
4043 . name - The mesh generation package name
4044 - interpolate - Flag to create intermediate mesh elements
4045 
4046   Output Parameter:
4047 . mesh - The DMPlex object
4048 
4049   Level: intermediate
4050 
4051 .keywords: mesh, elements
4052 .seealso: DMPlexCreate(), DMRefine()
4053 @*/
4054 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
4055 {
4056   PetscInt       dim;
4057   char           genname[1024];
4058   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4059   PetscErrorCode ierr;
4060 
4061   PetscFunctionBegin;
4062   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
4063   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
4064   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
4065   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4066   if (flg) name = genname;
4067   if (name) {
4068     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4069     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4070     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4071   }
4072   switch (dim) {
4073   case 1:
4074     if (!name || isTriangle) {
4075 #if defined(PETSC_HAVE_TRIANGLE)
4076       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
4077 #else
4078       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4079 #endif
4080     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4081     break;
4082   case 2:
4083     if (!name || isCTetgen) {
4084 #if defined(PETSC_HAVE_CTETGEN)
4085       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4086 #else
4087       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4088 #endif
4089     } else if (isTetgen) {
4090 #if defined(PETSC_HAVE_TETGEN)
4091       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4092 #else
4093       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4094 #endif
4095     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4096     break;
4097   default:
4098     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4099   }
4100   PetscFunctionReturn(0);
4101 }
4102 
4103 typedef PetscInt CellRefiner;
4104 
4105 #undef __FUNCT__
4106 #define __FUNCT__ "GetDepthStart_Private"
4107 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
4108 {
4109   PetscFunctionBegin;
4110   if (cStart) *cStart = 0;
4111   if (vStart) *vStart = depthSize[depth];
4112   if (fStart) *fStart = depthSize[depth] + depthSize[0];
4113   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4114   PetscFunctionReturn(0);
4115 }
4116 
4117 #undef __FUNCT__
4118 #define __FUNCT__ "GetDepthEnd_Private"
4119 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
4120 {
4121   PetscFunctionBegin;
4122   if (cEnd) *cEnd = depthSize[depth];
4123   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
4124   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4125   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
4126   PetscFunctionReturn(0);
4127 }
4128 
4129 #undef __FUNCT__
4130 #define __FUNCT__ "CellRefinerGetSizes"
4131 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
4132 {
4133   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
4134   PetscErrorCode ierr;
4135 
4136   PetscFunctionBegin;
4137   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4138   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4139   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4140   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4141   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4142   switch (refiner) {
4143   case 1:
4144     /* Simplicial 2D */
4145     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
4146     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
4147     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
4148     break;
4149   case 3:
4150     /* Hybrid 2D */
4151     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4152     cMax = PetscMin(cEnd, cMax);
4153     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4154     fMax         = PetscMin(fEnd, fMax);
4155     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
4156     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 */
4157     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
4158     break;
4159   case 2:
4160     /* Hex 2D */
4161     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
4162     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
4163     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
4164     break;
4165   default:
4166     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4167   }
4168   PetscFunctionReturn(0);
4169 }
4170 
4171 #undef __FUNCT__
4172 #define __FUNCT__ "CellRefinerSetConeSizes"
4173 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4174 {
4175   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
4176   PetscErrorCode ierr;
4177 
4178   PetscFunctionBegin;
4179   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4180   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4181   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4182   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4183   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4184   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4185   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4186   switch (refiner) {
4187   case 1:
4188     /* Simplicial 2D */
4189     /* All cells have 3 faces */
4190     for (c = cStart; c < cEnd; ++c) {
4191       for (r = 0; r < 4; ++r) {
4192         const PetscInt newp = (c - cStart)*4 + r;
4193 
4194         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4195       }
4196     }
4197     /* Split faces have 2 vertices and the same cells as the parent */
4198     for (f = fStart; f < fEnd; ++f) {
4199       for (r = 0; r < 2; ++r) {
4200         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4201         PetscInt       size;
4202 
4203         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4204         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4205         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4206       }
4207     }
4208     /* Interior faces have 2 vertices and 2 cells */
4209     for (c = cStart; c < cEnd; ++c) {
4210       for (r = 0; r < 3; ++r) {
4211         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4212 
4213         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4214         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4215       }
4216     }
4217     /* Old vertices have identical supports */
4218     for (v = vStart; v < vEnd; ++v) {
4219       const PetscInt newp = vStartNew + (v - vStart);
4220       PetscInt       size;
4221 
4222       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4223       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4224     }
4225     /* Face vertices have 2 + cells*2 supports */
4226     for (f = fStart; f < fEnd; ++f) {
4227       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4228       PetscInt       size;
4229 
4230       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4231       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
4232     }
4233     break;
4234   case 2:
4235     /* Hex 2D */
4236     /* All cells have 4 faces */
4237     for (c = cStart; c < cEnd; ++c) {
4238       for (r = 0; r < 4; ++r) {
4239         const PetscInt newp = (c - cStart)*4 + r;
4240 
4241         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4242       }
4243     }
4244     /* Split faces have 2 vertices and the same cells as the parent */
4245     for (f = fStart; f < fEnd; ++f) {
4246       for (r = 0; r < 2; ++r) {
4247         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4248         PetscInt       size;
4249 
4250         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4251         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4252         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4253       }
4254     }
4255     /* Interior faces have 2 vertices and 2 cells */
4256     for (c = cStart; c < cEnd; ++c) {
4257       for (r = 0; r < 4; ++r) {
4258         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4259 
4260         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4261         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4262       }
4263     }
4264     /* Old vertices have identical supports */
4265     for (v = vStart; v < vEnd; ++v) {
4266       const PetscInt newp = vStartNew + (v - vStart);
4267       PetscInt       size;
4268 
4269       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4270       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4271     }
4272     /* Face vertices have 2 + cells supports */
4273     for (f = fStart; f < fEnd; ++f) {
4274       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4275       PetscInt       size;
4276 
4277       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4278       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
4279     }
4280     /* Cell vertices have 4 supports */
4281     for (c = cStart; c < cEnd; ++c) {
4282       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4283 
4284       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
4285     }
4286     break;
4287   case 3:
4288     /* Hybrid 2D */
4289     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4290     cMax = PetscMin(cEnd, cMax);
4291     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4292     fMax = PetscMin(fEnd, fMax);
4293     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4294     /* Interior cells have 3 faces */
4295     for (c = cStart; c < cMax; ++c) {
4296       for (r = 0; r < 4; ++r) {
4297         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
4298 
4299         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4300       }
4301     }
4302     /* Hybrid cells have 4 faces */
4303     for (c = cMax; c < cEnd; ++c) {
4304       for (r = 0; r < 2; ++r) {
4305         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
4306 
4307         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4308       }
4309     }
4310     /* Interior split faces have 2 vertices and the same cells as the parent */
4311     for (f = fStart; f < fMax; ++f) {
4312       for (r = 0; r < 2; ++r) {
4313         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4314         PetscInt       size;
4315 
4316         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4317         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4318         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4319       }
4320     }
4321     /* Interior cell faces have 2 vertices and 2 cells */
4322     for (c = cStart; c < cMax; ++c) {
4323       for (r = 0; r < 3; ++r) {
4324         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4325 
4326         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4327         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4328       }
4329     }
4330     /* Hybrid faces have 2 vertices and the same cells */
4331     for (f = fMax; f < fEnd; ++f) {
4332       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4333       PetscInt       size;
4334 
4335       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4336       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4337       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4338     }
4339     /* Hybrid cell faces have 2 vertices and 2 cells */
4340     for (c = cMax; c < cEnd; ++c) {
4341       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4342 
4343       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4344       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4345     }
4346     /* Old vertices have identical supports */
4347     for (v = vStart; v < vEnd; ++v) {
4348       const PetscInt newp = vStartNew + (v - vStart);
4349       PetscInt       size;
4350 
4351       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4352       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4353     }
4354     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4355     for (f = fStart; f < fMax; ++f) {
4356       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4357       const PetscInt *support;
4358       PetscInt       size, newSize = 2, s;
4359 
4360       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4361       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4362       for (s = 0; s < size; ++s) {
4363         if (support[s] >= cMax) newSize += 1;
4364         else newSize += 2;
4365       }
4366       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
4367     }
4368     break;
4369   default:
4370     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4371   }
4372   PetscFunctionReturn(0);
4373 }
4374 
4375 #undef __FUNCT__
4376 #define __FUNCT__ "CellRefinerSetCones"
4377 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4378 {
4379   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;
4380   PetscInt       maxSupportSize, *supportRef;
4381   PetscErrorCode ierr;
4382 
4383   PetscFunctionBegin;
4384   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4385   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4386   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4387   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4388   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4389   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4390   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4391   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
4392   switch (refiner) {
4393   case 1:
4394     /* Simplicial 2D */
4395     /*
4396      2
4397      |\
4398      | \
4399      |  \
4400      |   \
4401      | C  \
4402      |     \
4403      |      \
4404      2---1---1
4405      |\  D  / \
4406      | 2   0   \
4407      |A \ /  B  \
4408      0---0-------1
4409      */
4410     /* All cells have 3 faces */
4411     for (c = cStart; c < cEnd; ++c) {
4412       const PetscInt  newp = cStartNew + (c - cStart)*4;
4413       const PetscInt *cone, *ornt;
4414       PetscInt        coneNew[3], orntNew[3];
4415 
4416       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4417       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4418       /* A triangle */
4419       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4420       orntNew[0] = ornt[0];
4421       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4422       orntNew[1] = -2;
4423       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4424       orntNew[2] = ornt[2];
4425       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4426       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4427 #if 1
4428       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);
4429       for (p = 0; p < 3; ++p) {
4430         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);
4431       }
4432 #endif
4433       /* B triangle */
4434       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4435       orntNew[0] = ornt[0];
4436       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4437       orntNew[1] = ornt[1];
4438       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4439       orntNew[2] = -2;
4440       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4441       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4442 #if 1
4443       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);
4444       for (p = 0; p < 3; ++p) {
4445         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);
4446       }
4447 #endif
4448       /* C triangle */
4449       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4450       orntNew[0] = -2;
4451       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4452       orntNew[1] = ornt[1];
4453       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4454       orntNew[2] = ornt[2];
4455       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4456       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4457 #if 1
4458       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);
4459       for (p = 0; p < 3; ++p) {
4460         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);
4461       }
4462 #endif
4463       /* D triangle */
4464       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4465       orntNew[0] = 0;
4466       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4467       orntNew[1] = 0;
4468       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4469       orntNew[2] = 0;
4470       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4471       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4472 #if 1
4473       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);
4474       for (p = 0; p < 3; ++p) {
4475         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);
4476       }
4477 #endif
4478     }
4479     /* Split faces have 2 vertices and the same cells as the parent */
4480     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4481     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4482     for (f = fStart; f < fEnd; ++f) {
4483       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4484 
4485       for (r = 0; r < 2; ++r) {
4486         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4487         const PetscInt *cone, *support;
4488         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4489 
4490         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4491         coneNew[0]       = vStartNew + (cone[0] - vStart);
4492         coneNew[1]       = vStartNew + (cone[1] - vStart);
4493         coneNew[(r+1)%2] = newv;
4494         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4495 #if 1
4496         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4497         for (p = 0; p < 2; ++p) {
4498           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);
4499         }
4500 #endif
4501         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4502         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4503         for (s = 0; s < supportSize; ++s) {
4504           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4505           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4506           for (c = 0; c < coneSize; ++c) {
4507             if (cone[c] == f) break;
4508           }
4509           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4510         }
4511         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4512 #if 1
4513         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4514         for (p = 0; p < supportSize; ++p) {
4515           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);
4516         }
4517 #endif
4518       }
4519     }
4520     /* Interior faces have 2 vertices and 2 cells */
4521     for (c = cStart; c < cEnd; ++c) {
4522       const PetscInt *cone;
4523 
4524       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4525       for (r = 0; r < 3; ++r) {
4526         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4527         PetscInt       coneNew[2];
4528         PetscInt       supportNew[2];
4529 
4530         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4531         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4532         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4533 #if 1
4534         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4535         for (p = 0; p < 2; ++p) {
4536           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);
4537         }
4538 #endif
4539         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4540         supportNew[1] = (c - cStart)*4 + 3;
4541         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4542 #if 1
4543         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4544         for (p = 0; p < 2; ++p) {
4545           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);
4546         }
4547 #endif
4548       }
4549     }
4550     /* Old vertices have identical supports */
4551     for (v = vStart; v < vEnd; ++v) {
4552       const PetscInt  newp = vStartNew + (v - vStart);
4553       const PetscInt *support, *cone;
4554       PetscInt        size, s;
4555 
4556       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4557       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4558       for (s = 0; s < size; ++s) {
4559         PetscInt r = 0;
4560 
4561         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4562         if (cone[1] == v) r = 1;
4563         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4564       }
4565       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4566 #if 1
4567       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4568       for (p = 0; p < size; ++p) {
4569         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);
4570       }
4571 #endif
4572     }
4573     /* Face vertices have 2 + cells*2 supports */
4574     for (f = fStart; f < fEnd; ++f) {
4575       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4576       const PetscInt *cone, *support;
4577       PetscInt        size, s;
4578 
4579       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4580       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4581       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4582       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4583       for (s = 0; s < size; ++s) {
4584         PetscInt r = 0;
4585 
4586         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4587         if      (cone[1] == f) r = 1;
4588         else if (cone[2] == f) r = 2;
4589         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4590         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4591       }
4592       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4593 #if 1
4594       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4595       for (p = 0; p < 2+size*2; ++p) {
4596         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);
4597       }
4598 #endif
4599     }
4600     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4601     break;
4602   case 2:
4603     /* Hex 2D */
4604     /*
4605      3---------2---------2
4606      |         |         |
4607      |    D    2    C    |
4608      |         |         |
4609      3----3----0----1----1
4610      |         |         |
4611      |    A    0    B    |
4612      |         |         |
4613      0---------0---------1
4614      */
4615     /* All cells have 4 faces */
4616     for (c = cStart; c < cEnd; ++c) {
4617       const PetscInt  newp = (c - cStart)*4;
4618       const PetscInt *cone, *ornt;
4619       PetscInt        coneNew[4], orntNew[4];
4620 
4621       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4622       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4623       /* A quad */
4624       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4625       orntNew[0] = ornt[0];
4626       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4627       orntNew[1] = 0;
4628       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4629       orntNew[2] = -2;
4630       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4631       orntNew[3] = ornt[3];
4632       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4633       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4634 #if 1
4635       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);
4636       for (p = 0; p < 4; ++p) {
4637         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);
4638       }
4639 #endif
4640       /* B quad */
4641       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4642       orntNew[0] = ornt[0];
4643       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4644       orntNew[1] = ornt[1];
4645       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4646       orntNew[2] = 0;
4647       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4648       orntNew[3] = -2;
4649       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4650       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4651 #if 1
4652       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);
4653       for (p = 0; p < 4; ++p) {
4654         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);
4655       }
4656 #endif
4657       /* C quad */
4658       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4659       orntNew[0] = -2;
4660       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4661       orntNew[1] = ornt[1];
4662       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4663       orntNew[2] = ornt[2];
4664       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4665       orntNew[3] = 0;
4666       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4667       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4668 #if 1
4669       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);
4670       for (p = 0; p < 4; ++p) {
4671         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);
4672       }
4673 #endif
4674       /* D quad */
4675       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4676       orntNew[0] = 0;
4677       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4678       orntNew[1] = -2;
4679       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4680       orntNew[2] = ornt[2];
4681       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
4682       orntNew[3] = ornt[3];
4683       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4684       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4685 #if 1
4686       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);
4687       for (p = 0; p < 4; ++p) {
4688         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);
4689       }
4690 #endif
4691     }
4692     /* Split faces have 2 vertices and the same cells as the parent */
4693     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4694     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4695     for (f = fStart; f < fEnd; ++f) {
4696       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4697 
4698       for (r = 0; r < 2; ++r) {
4699         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4700         const PetscInt *cone, *support;
4701         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4702 
4703         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4704         coneNew[0]       = vStartNew + (cone[0] - vStart);
4705         coneNew[1]       = vStartNew + (cone[1] - vStart);
4706         coneNew[(r+1)%2] = newv;
4707         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4708 #if 1
4709         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4710         for (p = 0; p < 2; ++p) {
4711           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);
4712         }
4713 #endif
4714         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4715         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4716         for (s = 0; s < supportSize; ++s) {
4717           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4718           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4719           for (c = 0; c < coneSize; ++c) {
4720             if (cone[c] == f) break;
4721           }
4722           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
4723         }
4724         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4725 #if 1
4726         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4727         for (p = 0; p < supportSize; ++p) {
4728           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);
4729         }
4730 #endif
4731       }
4732     }
4733     /* Interior faces have 2 vertices and 2 cells */
4734     for (c = cStart; c < cEnd; ++c) {
4735       const PetscInt *cone;
4736       PetscInt        coneNew[2], supportNew[2];
4737 
4738       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4739       for (r = 0; r < 4; ++r) {
4740         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4741 
4742         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
4743         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
4744         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4745 #if 1
4746         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4747         for (p = 0; p < 2; ++p) {
4748           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);
4749         }
4750 #endif
4751         supportNew[0] = (c - cStart)*4 + r;
4752         supportNew[1] = (c - cStart)*4 + (r+1)%4;
4753         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4754 #if 1
4755         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4756         for (p = 0; p < 2; ++p) {
4757           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);
4758         }
4759 #endif
4760       }
4761     }
4762     /* Old vertices have identical supports */
4763     for (v = vStart; v < vEnd; ++v) {
4764       const PetscInt  newp = vStartNew + (v - vStart);
4765       const PetscInt *support, *cone;
4766       PetscInt        size, s;
4767 
4768       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4769       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4770       for (s = 0; s < size; ++s) {
4771         PetscInt r = 0;
4772 
4773         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4774         if (cone[1] == v) r = 1;
4775         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4776       }
4777       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4778 #if 1
4779       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4780       for (p = 0; p < size; ++p) {
4781         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);
4782       }
4783 #endif
4784     }
4785     /* Face vertices have 2 + cells supports */
4786     for (f = fStart; f < fEnd; ++f) {
4787       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4788       const PetscInt *cone, *support;
4789       PetscInt        size, s;
4790 
4791       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4792       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4793       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4794       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4795       for (s = 0; s < size; ++s) {
4796         PetscInt r = 0;
4797 
4798         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4799         if      (cone[1] == f) r = 1;
4800         else if (cone[2] == f) r = 2;
4801         else if (cone[3] == f) r = 3;
4802         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
4803       }
4804       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4805 #if 1
4806       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4807       for (p = 0; p < 2+size; ++p) {
4808         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);
4809       }
4810 #endif
4811     }
4812     /* Cell vertices have 4 supports */
4813     for (c = cStart; c < cEnd; ++c) {
4814       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4815       PetscInt       supportNew[4];
4816 
4817       for (r = 0; r < 4; ++r) {
4818         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4819       }
4820       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4821     }
4822     break;
4823   case 3:
4824     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4825     cMax = PetscMin(cEnd, cMax);
4826     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4827     fMax = PetscMin(fEnd, fMax);
4828     /* Interior cells have 3 faces */
4829     for (c = cStart; c < cMax; ++c) {
4830       const PetscInt  newp = cStartNew + (c - cStart)*4;
4831       const PetscInt *cone, *ornt;
4832       PetscInt        coneNew[3], orntNew[3];
4833 
4834       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4835       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4836       /* A triangle */
4837       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4838       orntNew[0] = ornt[0];
4839       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4840       orntNew[1] = -2;
4841       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4842       orntNew[2] = ornt[2];
4843       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4844       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4845 #if 1
4846       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);
4847       for (p = 0; p < 3; ++p) {
4848         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);
4849       }
4850 #endif
4851       /* B triangle */
4852       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4853       orntNew[0] = ornt[0];
4854       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4855       orntNew[1] = ornt[1];
4856       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4857       orntNew[2] = -2;
4858       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4859       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4860 #if 1
4861       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);
4862       for (p = 0; p < 3; ++p) {
4863         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);
4864       }
4865 #endif
4866       /* C triangle */
4867       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4868       orntNew[0] = -2;
4869       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4870       orntNew[1] = ornt[1];
4871       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4872       orntNew[2] = ornt[2];
4873       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4874       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4875 #if 1
4876       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);
4877       for (p = 0; p < 3; ++p) {
4878         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);
4879       }
4880 #endif
4881       /* D triangle */
4882       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4883       orntNew[0] = 0;
4884       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4885       orntNew[1] = 0;
4886       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4887       orntNew[2] = 0;
4888       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4889       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4890 #if 1
4891       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);
4892       for (p = 0; p < 3; ++p) {
4893         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);
4894       }
4895 #endif
4896     }
4897     /*
4898      2----3----3
4899      |         |
4900      |    B    |
4901      |         |
4902      0----4--- 1
4903      |         |
4904      |    A    |
4905      |         |
4906      0----2----1
4907      */
4908     /* Hybrid cells have 4 faces */
4909     for (c = cMax; c < cEnd; ++c) {
4910       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
4911       const PetscInt *cone, *ornt;
4912       PetscInt        coneNew[4], orntNew[4];
4913 
4914       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4915       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4916       /* A quad */
4917       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4918       orntNew[0] = ornt[0];
4919       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4920       orntNew[1] = ornt[1];
4921       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
4922       orntNew[2] = 0;
4923       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4924       orntNew[3] = 0;
4925       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4926       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4927 #if 1
4928       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);
4929       for (p = 0; p < 4; ++p) {
4930         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);
4931       }
4932 #endif
4933       /* B quad */
4934       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4935       orntNew[0] = ornt[0];
4936       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4937       orntNew[1] = ornt[1];
4938       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4939       orntNew[2] = 0;
4940       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
4941       orntNew[3] = 0;
4942       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4943       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4944 #if 1
4945       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);
4946       for (p = 0; p < 4; ++p) {
4947         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);
4948       }
4949 #endif
4950     }
4951     /* Interior split faces have 2 vertices and the same cells as the parent */
4952     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4953     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4954     for (f = fStart; f < fMax; ++f) {
4955       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4956 
4957       for (r = 0; r < 2; ++r) {
4958         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4959         const PetscInt *cone, *support;
4960         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4961 
4962         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4963         coneNew[0]       = vStartNew + (cone[0] - vStart);
4964         coneNew[1]       = vStartNew + (cone[1] - vStart);
4965         coneNew[(r+1)%2] = newv;
4966         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4967 #if 1
4968         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4969         for (p = 0; p < 2; ++p) {
4970           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);
4971         }
4972 #endif
4973         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4974         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4975         for (s = 0; s < supportSize; ++s) {
4976           if (support[s] >= cMax) {
4977             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4978           } else {
4979             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4980             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4981             for (c = 0; c < coneSize; ++c) {
4982               if (cone[c] == f) break;
4983             }
4984             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4985           }
4986         }
4987         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4988 #if 1
4989         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4990         for (p = 0; p < supportSize; ++p) {
4991           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);
4992         }
4993 #endif
4994       }
4995     }
4996     /* Interior cell faces have 2 vertices and 2 cells */
4997     for (c = cStart; c < cMax; ++c) {
4998       const PetscInt *cone;
4999 
5000       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5001       for (r = 0; r < 3; ++r) {
5002         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5003         PetscInt       coneNew[2];
5004         PetscInt       supportNew[2];
5005 
5006         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5007         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5008         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5009 #if 1
5010         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5011         for (p = 0; p < 2; ++p) {
5012           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);
5013         }
5014 #endif
5015         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5016         supportNew[1] = (c - cStart)*4 + 3;
5017         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5018 #if 1
5019         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5020         for (p = 0; p < 2; ++p) {
5021           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);
5022         }
5023 #endif
5024       }
5025     }
5026     /* Interior hybrid faces have 2 vertices and the same cells */
5027     for (f = fMax; f < fEnd; ++f) {
5028       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5029       const PetscInt *cone;
5030       const PetscInt *support;
5031       PetscInt        coneNew[2];
5032       PetscInt        supportNew[2];
5033       PetscInt        size, s, r;
5034 
5035       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5036       coneNew[0] = vStartNew + (cone[0] - vStart);
5037       coneNew[1] = vStartNew + (cone[1] - vStart);
5038       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5039 #if 1
5040       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5041       for (p = 0; p < 2; ++p) {
5042         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);
5043       }
5044 #endif
5045       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5046       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5047       for (s = 0; s < size; ++s) {
5048         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5049         for (r = 0; r < 2; ++r) {
5050           if (cone[r+2] == f) break;
5051         }
5052         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
5053       }
5054       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5055 #if 1
5056       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5057       for (p = 0; p < size; ++p) {
5058         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);
5059       }
5060 #endif
5061     }
5062     /* Cell hybrid faces have 2 vertices and 2 cells */
5063     for (c = cMax; c < cEnd; ++c) {
5064       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5065       const PetscInt *cone;
5066       PetscInt        coneNew[2];
5067       PetscInt        supportNew[2];
5068 
5069       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5070       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
5071       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
5072       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5073 #if 1
5074       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5075       for (p = 0; p < 2; ++p) {
5076         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);
5077       }
5078 #endif
5079       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
5080       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
5081       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5082 #if 1
5083       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5084       for (p = 0; p < 2; ++p) {
5085         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);
5086       }
5087 #endif
5088     }
5089     /* Old vertices have identical supports */
5090     for (v = vStart; v < vEnd; ++v) {
5091       const PetscInt  newp = vStartNew + (v - vStart);
5092       const PetscInt *support, *cone;
5093       PetscInt        size, s;
5094 
5095       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5096       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5097       for (s = 0; s < size; ++s) {
5098         if (support[s] >= fMax) {
5099           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
5100         } else {
5101           PetscInt r = 0;
5102 
5103           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5104           if (cone[1] == v) r = 1;
5105           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5106         }
5107       }
5108       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5109 #if 1
5110       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5111       for (p = 0; p < size; ++p) {
5112         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);
5113       }
5114 #endif
5115     }
5116     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5117     for (f = fStart; f < fMax; ++f) {
5118       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5119       const PetscInt *cone, *support;
5120       PetscInt        size, newSize = 2, s;
5121 
5122       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5123       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5124       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5125       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5126       for (s = 0; s < size; ++s) {
5127         PetscInt r = 0;
5128 
5129         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5130         if (support[s] >= cMax) {
5131           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
5132 
5133           newSize += 1;
5134         } else {
5135           if      (cone[1] == f) r = 1;
5136           else if (cone[2] == f) r = 2;
5137           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5138           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
5139 
5140           newSize += 2;
5141         }
5142       }
5143       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5144 #if 1
5145       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5146       for (p = 0; p < newSize; ++p) {
5147         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);
5148       }
5149 #endif
5150     }
5151     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5152     break;
5153   default:
5154     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5155   }
5156   PetscFunctionReturn(0);
5157 }
5158 
5159 #undef __FUNCT__
5160 #define __FUNCT__ "CellRefinerSetCoordinates"
5161 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5162 {
5163   PetscSection   coordSection, coordSectionNew;
5164   Vec            coordinates, coordinatesNew;
5165   PetscScalar   *coords, *coordsNew;
5166   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
5167   PetscErrorCode ierr;
5168 
5169   PetscFunctionBegin;
5170   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5171   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5172   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5173   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5174   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5175   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
5176   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5177   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5178   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5179   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5180   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5181   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
5182   if (fMax < 0) fMax = fEnd;
5183   switch (refiner) {
5184   case 1:
5185   case 2:
5186   case 3:
5187     /* Simplicial and Hex 2D */
5188     /* All vertices have the dim coordinates */
5189     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5190       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5191       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5192     }
5193     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5194     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5195     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5196     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5197     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5198     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5199     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5200     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5201     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5202     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5203     /* Old vertices have the same coordinates */
5204     for (v = vStart; v < vEnd; ++v) {
5205       const PetscInt newv = vStartNew + (v - vStart);
5206       PetscInt       off, offnew, d;
5207 
5208       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5209       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5210       for (d = 0; d < dim; ++d) {
5211         coordsNew[offnew+d] = coords[off+d];
5212       }
5213     }
5214     /* Face vertices have the average of endpoint coordinates */
5215     for (f = fStart; f < fMax; ++f) {
5216       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5217       const PetscInt *cone;
5218       PetscInt        coneSize, offA, offB, offnew, d;
5219 
5220       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5221       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5222       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5223       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5224       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5225       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5226       for (d = 0; d < dim; ++d) {
5227         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5228       }
5229     }
5230     /* Just Hex 2D */
5231     if (refiner == 2) {
5232       /* Cell vertices have the average of corner coordinates */
5233       for (c = cStart; c < cEnd; ++c) {
5234         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5235         PetscInt      *cone = NULL;
5236         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5237 
5238         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5239         for (p = 0; p < closureSize*2; p += 2) {
5240           const PetscInt point = cone[p];
5241           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5242         }
5243         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5244         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5245         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5246         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5247         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5248         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5249         for (d = 0; d < dim; ++d) {
5250           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5251         }
5252         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5253       }
5254     }
5255     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5256     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5257     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5258     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5259     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5260     break;
5261   default:
5262     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5263   }
5264   PetscFunctionReturn(0);
5265 }
5266 
5267 #undef __FUNCT__
5268 #define __FUNCT__ "DMPlexCreateProcessSF"
5269 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5270 {
5271   PetscInt           numRoots, numLeaves, l;
5272   const PetscInt    *localPoints;
5273   const PetscSFNode *remotePoints;
5274   PetscInt          *localPointsNew;
5275   PetscSFNode       *remotePointsNew;
5276   PetscInt          *ranks, *ranksNew;
5277   PetscErrorCode     ierr;
5278 
5279   PetscFunctionBegin;
5280   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5281   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5282   for (l = 0; l < numLeaves; ++l) {
5283     ranks[l] = remotePoints[l].rank;
5284   }
5285   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5286   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
5287   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5288   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5289   for (l = 0; l < numLeaves; ++l) {
5290     ranksNew[l]              = ranks[l];
5291     localPointsNew[l]        = l;
5292     remotePointsNew[l].index = 0;
5293     remotePointsNew[l].rank  = ranksNew[l];
5294   }
5295   ierr = PetscFree(ranks);CHKERRQ(ierr);
5296   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5297   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5298   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5299   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5300   PetscFunctionReturn(0);
5301 }
5302 
5303 #undef __FUNCT__
5304 #define __FUNCT__ "CellRefinerCreateSF"
5305 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5306 {
5307   PetscSF            sf, sfNew, sfProcess;
5308   IS                 processRanks;
5309   MPI_Datatype       depthType;
5310   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5311   const PetscInt    *localPoints, *neighbors;
5312   const PetscSFNode *remotePoints;
5313   PetscInt          *localPointsNew;
5314   PetscSFNode       *remotePointsNew;
5315   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5316   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5317   PetscErrorCode     ierr;
5318 
5319   PetscFunctionBegin;
5320   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5321   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5322   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5323   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5324   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5325   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5326   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5327   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5328   switch (refiner) {
5329   case 3:
5330     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5331     cMax = PetscMin(cEnd, cMax);
5332     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5333     fMax = PetscMin(fEnd, fMax);
5334   }
5335   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5336   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5337   /* Caculate size of new SF */
5338   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5339   if (numRoots < 0) PetscFunctionReturn(0);
5340   for (l = 0; l < numLeaves; ++l) {
5341     const PetscInt p = localPoints[l];
5342 
5343     switch (refiner) {
5344     case 1:
5345       /* Simplicial 2D */
5346       if ((p >= vStart) && (p < vEnd)) {
5347         /* Old vertices stay the same */
5348         ++numLeavesNew;
5349       } else if ((p >= fStart) && (p < fEnd)) {
5350         /* Old faces add new faces and vertex */
5351         numLeavesNew += 1 + 2;
5352       } else if ((p >= cStart) && (p < cEnd)) {
5353         /* Old cells add new cells and interior faces */
5354         numLeavesNew += 4 + 3;
5355       }
5356       break;
5357     case 2:
5358       /* Hex 2D */
5359       if ((p >= vStart) && (p < vEnd)) {
5360         /* Old vertices stay the same */
5361         ++numLeavesNew;
5362       } else if ((p >= fStart) && (p < fEnd)) {
5363         /* Old faces add new faces and vertex */
5364         numLeavesNew += 1 + 2;
5365       } else if ((p >= cStart) && (p < cEnd)) {
5366         /* Old cells add new cells and interior faces */
5367         numLeavesNew += 4 + 4;
5368       }
5369       break;
5370     default:
5371       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5372     }
5373   }
5374   /* Communicate depthSizes for each remote rank */
5375   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5376   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5377   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
5378   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);
5379   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5380   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5381   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5382   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5383   for (n = 0; n < numNeighbors; ++n) {
5384     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5385   }
5386   depthSizeOld[depth]   = cMax;
5387   depthSizeOld[0]       = vMax;
5388   depthSizeOld[depth-1] = fMax;
5389   depthSizeOld[1]       = eMax;
5390 
5391   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5392   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5393 
5394   depthSizeOld[depth]   = cEnd - cStart;
5395   depthSizeOld[0]       = vEnd - vStart;
5396   depthSizeOld[depth-1] = fEnd - fStart;
5397   depthSizeOld[1]       = eEnd - eStart;
5398 
5399   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5400   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5401   for (n = 0; n < numNeighbors; ++n) {
5402     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5403   }
5404   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5405   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5406   /* Calculate new point SF */
5407   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5408   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5409   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5410   for (l = 0, m = 0; l < numLeaves; ++l) {
5411     PetscInt    p     = localPoints[l];
5412     PetscInt    rp    = remotePoints[l].index, n;
5413     PetscMPIInt rrank = remotePoints[l].rank;
5414 
5415     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5416     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5417     switch (refiner) {
5418     case 1:
5419       /* Simplicial 2D */
5420       if ((p >= vStart) && (p < vEnd)) {
5421         /* Old vertices stay the same */
5422         localPointsNew[m]        = vStartNew     + (p  - vStart);
5423         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5424         remotePointsNew[m].rank  = rrank;
5425         ++m;
5426       } else if ((p >= fStart) && (p < fEnd)) {
5427         /* Old faces add new faces and vertex */
5428         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5429         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5430         remotePointsNew[m].rank  = rrank;
5431         ++m;
5432         for (r = 0; r < 2; ++r, ++m) {
5433           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5434           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5435           remotePointsNew[m].rank  = rrank;
5436         }
5437       } else if ((p >= cStart) && (p < cEnd)) {
5438         /* Old cells add new cells and interior faces */
5439         for (r = 0; r < 4; ++r, ++m) {
5440           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5441           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5442           remotePointsNew[m].rank  = rrank;
5443         }
5444         for (r = 0; r < 3; ++r, ++m) {
5445           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5446           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5447           remotePointsNew[m].rank  = rrank;
5448         }
5449       }
5450       break;
5451     case 2:
5452       /* Hex 2D */
5453       if ((p >= vStart) && (p < vEnd)) {
5454         /* Old vertices stay the same */
5455         localPointsNew[m]        = vStartNew     + (p  - vStart);
5456         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5457         remotePointsNew[m].rank  = rrank;
5458         ++m;
5459       } else if ((p >= fStart) && (p < fEnd)) {
5460         /* Old faces add new faces and vertex */
5461         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5462         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5463         remotePointsNew[m].rank  = rrank;
5464         ++m;
5465         for (r = 0; r < 2; ++r, ++m) {
5466           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5467           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5468           remotePointsNew[m].rank  = rrank;
5469         }
5470       } else if ((p >= cStart) && (p < cEnd)) {
5471         /* Old cells add new cells and interior faces */
5472         for (r = 0; r < 4; ++r, ++m) {
5473           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5474           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5475           remotePointsNew[m].rank  = rrank;
5476         }
5477         for (r = 0; r < 4; ++r, ++m) {
5478           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5479           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5480           remotePointsNew[m].rank  = rrank;
5481         }
5482       }
5483       break;
5484     case 3:
5485       /* Hybrid simplicial 2D */
5486       if ((p >= vStart) && (p < vEnd)) {
5487         /* Old vertices stay the same */
5488         localPointsNew[m]        = vStartNew     + (p  - vStart);
5489         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5490         remotePointsNew[m].rank  = rrank;
5491         ++m;
5492       } else if ((p >= fStart) && (p < fMax)) {
5493         /* Old interior faces add new faces and vertex */
5494         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5495         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5496         remotePointsNew[m].rank  = rrank;
5497         ++m;
5498         for (r = 0; r < 2; ++r, ++m) {
5499           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5500           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5501           remotePointsNew[m].rank  = rrank;
5502         }
5503       } else if ((p >= fMax) && (p < fEnd)) {
5504         /* Old hybrid faces stay the same */
5505         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5506         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5507         remotePointsNew[m].rank  = rrank;
5508         ++m;
5509       } else if ((p >= cStart) && (p < cMax)) {
5510         /* Old interior cells add new cells and interior faces */
5511         for (r = 0; r < 4; ++r, ++m) {
5512           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5513           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5514           remotePointsNew[m].rank  = rrank;
5515         }
5516         for (r = 0; r < 3; ++r, ++m) {
5517           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5518           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5519           remotePointsNew[m].rank  = rrank;
5520         }
5521       } else if ((p >= cStart) && (p < cMax)) {
5522         /* Old hybrid cells add new cells and hybrid face */
5523         for (r = 0; r < 2; ++r, ++m) {
5524           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5525           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5526           remotePointsNew[m].rank  = rrank;
5527         }
5528         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5529         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]);
5530         remotePointsNew[m].rank  = rrank;
5531         ++m;
5532       }
5533       break;
5534     default:
5535       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5536     }
5537   }
5538   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5539   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5540   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5541   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5542   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5543   PetscFunctionReturn(0);
5544 }
5545 
5546 #undef __FUNCT__
5547 #define __FUNCT__ "CellRefinerCreateLabels"
5548 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5549 {
5550   PetscInt       numLabels, l;
5551   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
5552   PetscErrorCode ierr;
5553 
5554   PetscFunctionBegin;
5555   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5556   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5557   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5558   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5559 
5560   cStartNew = 0;
5561   vStartNew = depthSize[2];
5562   fStartNew = depthSize[2] + depthSize[0];
5563 
5564   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5565   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5566   switch (refiner) {
5567   case 3:
5568     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5569     cMax = PetscMin(cEnd, cMax);
5570     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5571     fMax = PetscMin(fEnd, fMax);
5572   }
5573   for (l = 0; l < numLabels; ++l) {
5574     DMLabel         label, labelNew;
5575     const char     *lname;
5576     PetscBool       isDepth;
5577     IS              valueIS;
5578     const PetscInt *values;
5579     PetscInt        numValues, val;
5580 
5581     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5582     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5583     if (isDepth) continue;
5584     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5585     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5586     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5587     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5588     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5589     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5590     for (val = 0; val < numValues; ++val) {
5591       IS              pointIS;
5592       const PetscInt *points;
5593       PetscInt        numPoints, n;
5594 
5595       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5596       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5597       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5598       for (n = 0; n < numPoints; ++n) {
5599         const PetscInt p = points[n];
5600         switch (refiner) {
5601         case 1:
5602           /* Simplicial 2D */
5603           if ((p >= vStart) && (p < vEnd)) {
5604             /* Old vertices stay the same */
5605             newp = vStartNew + (p - vStart);
5606             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5607           } else if ((p >= fStart) && (p < fEnd)) {
5608             /* Old faces add new faces and vertex */
5609             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5610             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5611             for (r = 0; r < 2; ++r) {
5612               newp = fStartNew + (p - fStart)*2 + r;
5613               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5614             }
5615           } else if ((p >= cStart) && (p < cEnd)) {
5616             /* Old cells add new cells and interior faces */
5617             for (r = 0; r < 4; ++r) {
5618               newp = cStartNew + (p - cStart)*4 + r;
5619               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5620             }
5621             for (r = 0; r < 3; ++r) {
5622               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5623               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5624             }
5625           }
5626           break;
5627         case 2:
5628           /* Hex 2D */
5629           if ((p >= vStart) && (p < vEnd)) {
5630             /* Old vertices stay the same */
5631             newp = vStartNew + (p - vStart);
5632             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5633           } else if ((p >= fStart) && (p < fEnd)) {
5634             /* Old faces add new faces and vertex */
5635             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5636             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5637             for (r = 0; r < 2; ++r) {
5638               newp = fStartNew + (p - fStart)*2 + r;
5639               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5640             }
5641           } else if ((p >= cStart) && (p < cEnd)) {
5642             /* Old cells add new cells and interior faces and vertex */
5643             for (r = 0; r < 4; ++r) {
5644               newp = cStartNew + (p - cStart)*4 + r;
5645               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5646             }
5647             for (r = 0; r < 4; ++r) {
5648               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5649               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5650             }
5651             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5652             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5653           }
5654           break;
5655         case 3:
5656           /* Hybrid simplicial 2D */
5657           if ((p >= vStart) && (p < vEnd)) {
5658             /* Old vertices stay the same */
5659             newp = vStartNew + (p - vStart);
5660             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5661           } else if ((p >= fStart) && (p < fMax)) {
5662             /* Old interior faces add new faces and vertex */
5663             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5664             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5665             for (r = 0; r < 2; ++r) {
5666               newp = fStartNew + (p - fStart)*2 + r;
5667               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5668             }
5669           } else if ((p >= fMax) && (p < fEnd)) {
5670             /* Old hybrid faces stay the same */
5671             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5672             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5673           } else if ((p >= cStart) && (p < cMax)) {
5674             /* Old interior cells add new cells and interior faces */
5675             for (r = 0; r < 4; ++r) {
5676               newp = cStartNew + (p - cStart)*4 + r;
5677               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5678             }
5679             for (r = 0; r < 3; ++r) {
5680               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5681               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5682             }
5683           } else if ((p >= cMax) && (p < cEnd)) {
5684             /* Old hybrid cells add new cells and hybrid face */
5685             for (r = 0; r < 2; ++r) {
5686               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5687               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5688             }
5689             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5690             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5691           }
5692           break;
5693         default:
5694           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5695         }
5696       }
5697       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
5698       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5699     }
5700     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
5701     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
5702     if (0) {
5703       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
5704       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5705       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5706     }
5707   }
5708   PetscFunctionReturn(0);
5709 }
5710 
5711 #undef __FUNCT__
5712 #define __FUNCT__ "DMPlexRefine_Uniform"
5713 /* This will only work for interpolated meshes */
5714 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5715 {
5716   DM             rdm;
5717   PetscInt      *depthSize;
5718   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
5719   PetscErrorCode ierr;
5720 
5721   PetscFunctionBegin;
5722   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
5723   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
5724   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5725   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
5726   /* Calculate number of new points of each depth */
5727   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5728   if (depth != dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be fully interpolated for uniform refinement");
5729   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
5730   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
5731   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
5732   /* Step 1: Set chart */
5733   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5734   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
5735   /* Step 2: Set cone/support sizes */
5736   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5737   /* Step 3: Setup refined DM */
5738   ierr = DMSetUp(rdm);CHKERRQ(ierr);
5739   /* Step 4: Set cones and supports */
5740   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5741   /* Step 5: Stratify */
5742   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
5743   /* Step 6: Set coordinates for vertices */
5744   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5745   /* Step 7: Create pointSF */
5746   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5747   /* Step 8: Create labels */
5748   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5749   ierr = PetscFree(depthSize);CHKERRQ(ierr);
5750 
5751   *dmRefined = rdm;
5752   PetscFunctionReturn(0);
5753 }
5754 
5755 #undef __FUNCT__
5756 #define __FUNCT__ "DMPlexSetRefinementUniform"
5757 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
5758 {
5759   DM_Plex *mesh = (DM_Plex*) dm->data;
5760 
5761   PetscFunctionBegin;
5762   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5763   mesh->refinementUniform = refinementUniform;
5764   PetscFunctionReturn(0);
5765 }
5766 
5767 #undef __FUNCT__
5768 #define __FUNCT__ "DMPlexGetRefinementUniform"
5769 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
5770 {
5771   DM_Plex *mesh = (DM_Plex*) dm->data;
5772 
5773   PetscFunctionBegin;
5774   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5775   PetscValidPointer(refinementUniform,  2);
5776   *refinementUniform = mesh->refinementUniform;
5777   PetscFunctionReturn(0);
5778 }
5779 
5780 #undef __FUNCT__
5781 #define __FUNCT__ "DMPlexSetRefinementLimit"
5782 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
5783 {
5784   DM_Plex *mesh = (DM_Plex*) dm->data;
5785 
5786   PetscFunctionBegin;
5787   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5788   mesh->refinementLimit = refinementLimit;
5789   PetscFunctionReturn(0);
5790 }
5791 
5792 #undef __FUNCT__
5793 #define __FUNCT__ "DMPlexGetRefinementLimit"
5794 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
5795 {
5796   DM_Plex *mesh = (DM_Plex*) dm->data;
5797 
5798   PetscFunctionBegin;
5799   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5800   PetscValidPointer(refinementLimit,  2);
5801   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
5802   *refinementLimit = mesh->refinementLimit;
5803   PetscFunctionReturn(0);
5804 }
5805 
5806 #undef __FUNCT__
5807 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
5808 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
5809 {
5810   PetscInt       dim, cStart, coneSize, cMax;
5811   PetscErrorCode ierr;
5812 
5813   PetscFunctionBegin;
5814   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5815   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
5816   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
5817   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5818   switch (dim) {
5819   case 2:
5820     switch (coneSize) {
5821     case 3:
5822       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
5823       else *cellRefiner = 1; /* Triangular */
5824       break;
5825     case 4:
5826       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
5827       else *cellRefiner = 2; /* Quadrilateral */
5828       break;
5829     default:
5830       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
5831     }
5832     break;
5833   default:
5834     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
5835   }
5836   PetscFunctionReturn(0);
5837 }
5838 
5839 #undef __FUNCT__
5840 #define __FUNCT__ "DMRefine_Plex"
5841 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
5842 {
5843   PetscReal      refinementLimit;
5844   PetscInt       dim, cStart, cEnd;
5845   char           genname[1024], *name = NULL;
5846   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5847   PetscErrorCode ierr;
5848 
5849   PetscFunctionBegin;
5850   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
5851   if (isUniform) {
5852     CellRefiner cellRefiner;
5853 
5854     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
5855     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
5856     PetscFunctionReturn(0);
5857   }
5858   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
5859   if (refinementLimit == 0.0) PetscFunctionReturn(0);
5860   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5861   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5862   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5863   if (flg) name = genname;
5864   if (name) {
5865     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5866     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5867     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5868   }
5869   switch (dim) {
5870   case 2:
5871     if (!name || isTriangle) {
5872 #if defined(PETSC_HAVE_TRIANGLE)
5873       double  *maxVolumes;
5874       PetscInt c;
5875 
5876       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5877       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5878       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5879       ierr = PetscFree(maxVolumes);CHKERRQ(ierr);
5880 #else
5881       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
5882 #endif
5883     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5884     break;
5885   case 3:
5886     if (!name || isCTetgen) {
5887 #if defined(PETSC_HAVE_CTETGEN)
5888       PetscReal *maxVolumes;
5889       PetscInt   c;
5890 
5891       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
5892       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5893       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5894 #else
5895       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5896 #endif
5897     } else if (isTetgen) {
5898 #if defined(PETSC_HAVE_TETGEN)
5899       double  *maxVolumes;
5900       PetscInt c;
5901 
5902       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5903       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5904       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5905 #else
5906       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5907 #endif
5908     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5909     break;
5910   default:
5911     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
5912   }
5913   PetscFunctionReturn(0);
5914 }
5915 
5916 #undef __FUNCT__
5917 #define __FUNCT__ "DMPlexGetDepthLabel"
5918 /*@
5919   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
5920 
5921   Not Collective
5922 
5923   Input Parameter:
5924 . dm    - The DMPlex object
5925 
5926   Output Parameter:
5927 . depthLabel - The DMLabel recording point depth
5928 
5929   Level: developer
5930 
5931 .keywords: mesh, points
5932 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
5933 @*/
5934 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5935 {
5936   DM_Plex       *mesh = (DM_Plex*) dm->data;
5937   PetscErrorCode ierr;
5938 
5939   PetscFunctionBegin;
5940   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5941   PetscValidPointer(depthLabel, 2);
5942   if (!mesh->depthLabel) {
5943     ierr = DMPlexGetLabel(dm, "depth", &mesh->depthLabel);CHKERRQ(ierr);
5944   }
5945   *depthLabel = mesh->depthLabel;
5946   PetscFunctionReturn(0);
5947 }
5948 
5949 #undef __FUNCT__
5950 #define __FUNCT__ "DMPlexGetDepth"
5951 /*@
5952   DMPlexGetDepth - Get the depth of the DAG representing this mesh
5953 
5954   Not Collective
5955 
5956   Input Parameter:
5957 . dm    - The DMPlex object
5958 
5959   Output Parameter:
5960 . depth - The number of strata (breadth first levels) in the DAG
5961 
5962   Level: developer
5963 
5964 .keywords: mesh, points
5965 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
5966 @*/
5967 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5968 {
5969   DMLabel        label;
5970   PetscInt       d = 0;
5971   PetscErrorCode ierr;
5972 
5973   PetscFunctionBegin;
5974   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5975   PetscValidPointer(depth, 2);
5976   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
5977   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
5978   *depth = d-1;
5979   PetscFunctionReturn(0);
5980 }
5981 
5982 #undef __FUNCT__
5983 #define __FUNCT__ "DMPlexGetDepthStratum"
5984 /*@
5985   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
5986 
5987   Not Collective
5988 
5989   Input Parameters:
5990 + dm           - The DMPlex object
5991 - stratumValue - The requested depth
5992 
5993   Output Parameters:
5994 + start - The first point at this depth
5995 - end   - One beyond the last point at this depth
5996 
5997   Level: developer
5998 
5999 .keywords: mesh, points
6000 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
6001 @*/
6002 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
6003 {
6004   DMLabel        label;
6005   PetscInt       depth;
6006   PetscErrorCode ierr;
6007 
6008   PetscFunctionBegin;
6009   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6010   if (stratumValue < 0) {
6011     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6012     PetscFunctionReturn(0);
6013   } else {
6014     PetscInt pStart, pEnd;
6015 
6016     if (start) *start = 0;
6017     if (end)   *end   = 0;
6018     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6019     if (pStart == pEnd) PetscFunctionReturn(0);
6020   }
6021   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
6022   if (!label) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6023   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6024   depth = stratumValue;
6025   if ((depth < 0) || (depth >= label->numStrata)) {
6026     if (start) *start = 0;
6027     if (end)   *end   = 0;
6028   } else {
6029     if (start) *start = label->points[label->stratumOffsets[depth]];
6030     if (end)   *end   = label->points[label->stratumOffsets[depth]+label->stratumSizes[depth]-1]+1;
6031   }
6032   PetscFunctionReturn(0);
6033 }
6034 
6035 #undef __FUNCT__
6036 #define __FUNCT__ "DMPlexGetHeightStratum"
6037 /*@
6038   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
6039 
6040   Not Collective
6041 
6042   Input Parameters:
6043 + dm           - The DMPlex object
6044 - stratumValue - The requested height
6045 
6046   Output Parameters:
6047 + start - The first point at this height
6048 - end   - One beyond the last point at this height
6049 
6050   Level: developer
6051 
6052 .keywords: mesh, points
6053 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
6054 @*/
6055 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
6056 {
6057   DMLabel        label;
6058   PetscInt       depth;
6059   PetscErrorCode ierr;
6060 
6061   PetscFunctionBegin;
6062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6063   if (stratumValue < 0) {
6064     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6065   } else {
6066     PetscInt pStart, pEnd;
6067 
6068     if (start) *start = 0;
6069     if (end)   *end   = 0;
6070     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6071     if (pStart == pEnd) PetscFunctionReturn(0);
6072   }
6073   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
6074   if (!label) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6075   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6076   depth = label->stratumValues[label->numStrata-1] - stratumValue;
6077   if ((depth < 0) || (depth >= label->numStrata)) {
6078     if (start) *start = 0;
6079     if (end)   *end   = 0;
6080   } else {
6081     if (start) *start = label->points[label->stratumOffsets[depth]];
6082     if (end)   *end   = label->points[label->stratumOffsets[depth]+label->stratumSizes[depth]-1]+1;
6083   }
6084   PetscFunctionReturn(0);
6085 }
6086 
6087 #undef __FUNCT__
6088 #define __FUNCT__ "DMPlexCreateSectionInitial"
6089 /* Set the number of dof on each point and separate by fields */
6090 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
6091 {
6092   PetscInt      *numDofTot;
6093   PetscInt       pStart = 0, pEnd = 0;
6094   PetscInt       p, d, f;
6095   PetscErrorCode ierr;
6096 
6097   PetscFunctionBegin;
6098   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
6099   for (d = 0; d <= dim; ++d) {
6100     numDofTot[d] = 0;
6101     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
6102   }
6103   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
6104   if (numFields > 0) {
6105     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
6106     if (numComp) {
6107       for (f = 0; f < numFields; ++f) {
6108         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
6109       }
6110     }
6111   }
6112   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6113   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
6114   for (d = 0; d <= dim; ++d) {
6115     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
6116     for (p = pStart; p < pEnd; ++p) {
6117       for (f = 0; f < numFields; ++f) {
6118         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
6119       }
6120       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
6121     }
6122   }
6123   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
6124   PetscFunctionReturn(0);
6125 }
6126 
6127 #undef __FUNCT__
6128 #define __FUNCT__ "DMPlexCreateSectionBCDof"
6129 /* Set the number of dof on each point and separate by fields
6130    If constDof is PETSC_DETERMINE, constrain every dof on the point
6131 */
6132 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
6133 {
6134   PetscInt       numFields;
6135   PetscInt       bc;
6136   PetscErrorCode ierr;
6137 
6138   PetscFunctionBegin;
6139   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6140   for (bc = 0; bc < numBC; ++bc) {
6141     PetscInt        field = 0;
6142     const PetscInt *idx;
6143     PetscInt        n, i;
6144 
6145     if (numFields) field = bcField[bc];
6146     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
6147     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6148     for (i = 0; i < n; ++i) {
6149       const PetscInt p        = idx[i];
6150       PetscInt       numConst = constDof;
6151 
6152       /* Constrain every dof on the point */
6153       if (numConst < 0) {
6154         if (numFields) {
6155           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
6156         } else {
6157           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
6158         }
6159       }
6160       if (numFields) {
6161         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
6162       }
6163       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
6164     }
6165     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6166   }
6167   PetscFunctionReturn(0);
6168 }
6169 
6170 #undef __FUNCT__
6171 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
6172 /* Set the constrained indices on each point and separate by fields */
6173 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
6174 {
6175   PetscInt      *maxConstraints;
6176   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
6177   PetscErrorCode ierr;
6178 
6179   PetscFunctionBegin;
6180   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6181   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6182   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
6183   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
6184   for (p = pStart; p < pEnd; ++p) {
6185     PetscInt cdof;
6186 
6187     if (numFields) {
6188       for (f = 0; f < numFields; ++f) {
6189         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
6190         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6191       }
6192     } else {
6193       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6194       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6195     }
6196   }
6197   for (f = 0; f < numFields; ++f) {
6198     maxConstraints[numFields] += maxConstraints[f];
6199   }
6200   if (maxConstraints[numFields]) {
6201     PetscInt *indices;
6202 
6203     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6204     for (p = pStart; p < pEnd; ++p) {
6205       PetscInt cdof, d;
6206 
6207       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6208       if (cdof) {
6209         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
6210         if (numFields) {
6211           PetscInt numConst = 0, foff = 0;
6212 
6213           for (f = 0; f < numFields; ++f) {
6214             PetscInt cfdof, fdof;
6215 
6216             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6217             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
6218             /* Change constraint numbering from absolute local dof number to field relative local dof number */
6219             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
6220             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
6221             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
6222             numConst += cfdof;
6223             foff     += fdof;
6224           }
6225           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6226         } else {
6227           for (d = 0; d < cdof; ++d) indices[d] = d;
6228         }
6229         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6230       }
6231     }
6232     ierr = PetscFree(indices);CHKERRQ(ierr);
6233   }
6234   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
6235   PetscFunctionReturn(0);
6236 }
6237 
6238 #undef __FUNCT__
6239 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
6240 /* Set the constrained field indices on each point */
6241 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6242 {
6243   const PetscInt *points, *indices;
6244   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6245   PetscErrorCode  ierr;
6246 
6247   PetscFunctionBegin;
6248   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6249   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
6250 
6251   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
6252   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
6253   if (!constraintIndices) {
6254     PetscInt *idx, i;
6255 
6256     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6257     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
6258     for (i = 0; i < maxDof; ++i) idx[i] = i;
6259     for (p = 0; p < numPoints; ++p) {
6260       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
6261     }
6262     ierr = PetscFree(idx);CHKERRQ(ierr);
6263   } else {
6264     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
6265     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
6266     for (p = 0; p < numPoints; ++p) {
6267       PetscInt fcdof;
6268 
6269       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
6270       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);
6271       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
6272     }
6273     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
6274   }
6275   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
6276   PetscFunctionReturn(0);
6277 }
6278 
6279 #undef __FUNCT__
6280 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
6281 /* Set the constrained indices on each point and separate by fields */
6282 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6283 {
6284   PetscInt      *indices;
6285   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
6286   PetscErrorCode ierr;
6287 
6288   PetscFunctionBegin;
6289   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6290   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6291   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6292   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6293   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6294   for (p = pStart; p < pEnd; ++p) {
6295     PetscInt cdof, d;
6296 
6297     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6298     if (cdof) {
6299       PetscInt numConst = 0, foff = 0;
6300 
6301       for (f = 0; f < numFields; ++f) {
6302         const PetscInt *fcind;
6303         PetscInt        fdof, fcdof;
6304 
6305         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6306         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
6307         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
6308         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6309         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6310         foff     += fdof;
6311         numConst += fcdof;
6312       }
6313       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6314       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6315     }
6316   }
6317   ierr = PetscFree(indices);CHKERRQ(ierr);
6318   PetscFunctionReturn(0);
6319 }
6320 
6321 #undef __FUNCT__
6322 #define __FUNCT__ "DMPlexCreateSection"
6323 /*@C
6324   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
6325 
6326   Not Collective
6327 
6328   Input Parameters:
6329 + dm        - The DMPlex object
6330 . dim       - The spatial dimension of the problem
6331 . numFields - The number of fields in the problem
6332 . numComp   - An array of size numFields that holds the number of components for each field
6333 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6334 . numBC     - The number of boundary conditions
6335 . bcField   - An array of size numBC giving the field number for each boundry condition
6336 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
6337 
6338   Output Parameter:
6339 . section - The PetscSection object
6340 
6341   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
6342   nubmer of dof for field 0 on each edge.
6343 
6344   Level: developer
6345 
6346   Fortran Notes:
6347   A Fortran 90 version is available as DMPlexCreateSectionF90()
6348 
6349 .keywords: mesh, elements
6350 .seealso: DMPlexCreate(), PetscSectionCreate()
6351 @*/
6352 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6353 {
6354   PetscErrorCode ierr;
6355 
6356   PetscFunctionBegin;
6357   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
6358   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
6359   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
6360   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
6361   {
6362     PetscBool view = PETSC_FALSE;
6363 
6364     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
6365     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
6366   }
6367   PetscFunctionReturn(0);
6368 }
6369 
6370 #undef __FUNCT__
6371 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
6372 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6373 {
6374   PetscSection   section;
6375   PetscErrorCode ierr;
6376 
6377   PetscFunctionBegin;
6378   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
6379   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6380   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
6381   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6382   PetscFunctionReturn(0);
6383 }
6384 
6385 #undef __FUNCT__
6386 #define __FUNCT__ "DMPlexGetCoordinateSection"
6387 /*@
6388   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6389 
6390   Not Collective
6391 
6392   Input Parameter:
6393 . dm - The DMPlex object
6394 
6395   Output Parameter:
6396 . section - The PetscSection object
6397 
6398   Level: intermediate
6399 
6400 .keywords: mesh, coordinates
6401 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6402 @*/
6403 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6404 {
6405   DM             cdm;
6406   PetscErrorCode ierr;
6407 
6408   PetscFunctionBegin;
6409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6410   PetscValidPointer(section, 2);
6411   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6412   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
6413   PetscFunctionReturn(0);
6414 }
6415 
6416 #undef __FUNCT__
6417 #define __FUNCT__ "DMPlexSetCoordinateSection"
6418 /*@
6419   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
6420 
6421   Not Collective
6422 
6423   Input Parameters:
6424 + dm      - The DMPlex object
6425 - section - The PetscSection object
6426 
6427   Level: intermediate
6428 
6429 .keywords: mesh, coordinates
6430 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6431 @*/
6432 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6433 {
6434   DM             cdm;
6435   PetscErrorCode ierr;
6436 
6437   PetscFunctionBegin;
6438   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6439   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
6440   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6441   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
6442   PetscFunctionReturn(0);
6443 }
6444 
6445 #undef __FUNCT__
6446 #define __FUNCT__ "DMPlexGetConeSection"
6447 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6448 {
6449   DM_Plex *mesh = (DM_Plex*) dm->data;
6450 
6451   PetscFunctionBegin;
6452   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6453   if (section) *section = mesh->coneSection;
6454   PetscFunctionReturn(0);
6455 }
6456 
6457 #undef __FUNCT__
6458 #define __FUNCT__ "DMPlexGetCones"
6459 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6460 {
6461   DM_Plex *mesh = (DM_Plex*) dm->data;
6462 
6463   PetscFunctionBegin;
6464   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6465   if (cones) *cones = mesh->cones;
6466   PetscFunctionReturn(0);
6467 }
6468 
6469 #undef __FUNCT__
6470 #define __FUNCT__ "DMPlexGetConeOrientations"
6471 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6472 {
6473   DM_Plex *mesh = (DM_Plex*) dm->data;
6474 
6475   PetscFunctionBegin;
6476   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6477   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6478   PetscFunctionReturn(0);
6479 }
6480 
6481 /******************************** FEM Support **********************************/
6482 
6483 #undef __FUNCT__
6484 #define __FUNCT__ "DMPlexVecGetClosure"
6485 /*@C
6486   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6487 
6488   Not collective
6489 
6490   Input Parameters:
6491 + dm - The DM
6492 . section - The section describing the layout in v, or NULL to use the default section
6493 . v - The local vector
6494 - point - The sieve point in the DM
6495 
6496   Output Parameters:
6497 + csize - The number of values in the closure, or NULL
6498 - values - The array of values, which is a borrowed array and should not be freed
6499 
6500   Fortran Notes:
6501   Since it returns an array, this routine is only available in Fortran 90, and you must
6502   include petsc.h90 in your code.
6503 
6504   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6505 
6506   Level: intermediate
6507 
6508 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6509 @*/
6510 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6511 {
6512   PetscScalar   *array, *vArray;
6513   PetscInt      *points = NULL;
6514   PetscInt       offsets[32];
6515   PetscInt       depth, numFields, size = 0, numPoints, pStart, pEnd, p, q, f;
6516   PetscErrorCode ierr;
6517 
6518   PetscFunctionBegin;
6519   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6520   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6521   if (!section) {
6522     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6523   }
6524   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6525   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6526   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6527   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6528   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6529   if (depth == 1 && numFields < 2) {
6530     const PetscInt *cone, *coneO;
6531 
6532     ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
6533     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
6534     ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
6535     if (!values || !*values) {
6536       if ((point >= pStart) && (point < pEnd)) {
6537         PetscInt dof;
6538         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6539         size += dof;
6540       }
6541       for (p = 0; p < numPoints; ++p) {
6542         const PetscInt cp = cone[p];
6543         PetscInt       dof;
6544 
6545         if ((cp < pStart) || (cp >= pEnd)) continue;
6546         ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
6547         size += dof;
6548       }
6549       if (!values) {
6550         if (csize) *csize = size;
6551         PetscFunctionReturn(0);
6552       }
6553       ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6554     } else {
6555       array = *values;
6556     }
6557     size = 0;
6558     ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6559     if ((point >= pStart) && (point < pEnd)) {
6560       PetscInt     dof, off, d;
6561       PetscScalar *varr;
6562       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6563       ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6564       varr = &vArray[off];
6565       for (d = 0; d < dof; ++d, ++offsets[0]) {
6566         array[offsets[0]] = varr[d];
6567       }
6568       size += dof;
6569     }
6570     for (p = 0; p < numPoints; ++p) {
6571       const PetscInt cp = cone[p];
6572       PetscInt       o  = coneO[p];
6573       PetscInt       dof, off, d;
6574       PetscScalar   *varr;
6575 
6576       if ((cp < pStart) || (cp >= pEnd)) continue;
6577       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
6578       ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
6579       varr = &vArray[off];
6580       if (o >= 0) {
6581         for (d = 0; d < dof; ++d, ++offsets[0]) {
6582           array[offsets[0]] = varr[d];
6583         }
6584       } else {
6585         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6586           array[offsets[0]] = varr[d];
6587         }
6588       }
6589       size += dof;
6590     }
6591     ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
6592     if (!*values) {
6593       if (csize) *csize = size;
6594       *values = array;
6595     } else {
6596       if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
6597       *csize = size;
6598     }
6599     PetscFunctionReturn(0);
6600   }
6601   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6602   /* Compress out points not in the section */
6603   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6604     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6605       points[q*2]   = points[p];
6606       points[q*2+1] = points[p+1];
6607       ++q;
6608     }
6609   }
6610   numPoints = q;
6611   if (!values || !*values) {
6612     for (p = 0, size = 0; p < numPoints*2; p += 2) {
6613       PetscInt dof, fdof;
6614 
6615       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6616       for (f = 0; f < numFields; ++f) {
6617         ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6618         offsets[f+1] += fdof;
6619       }
6620       size += dof;
6621     }
6622     if (!values) {
6623       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6624       if (csize) *csize = size;
6625       PetscFunctionReturn(0);
6626     }
6627     ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6628   } else {
6629     array = *values;
6630   }
6631   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6632   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
6633   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6634   for (p = 0; p < numPoints*2; p += 2) {
6635     PetscInt     o = points[p+1];
6636     PetscInt     dof, off, d;
6637     PetscScalar *varr;
6638 
6639     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6640     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
6641     varr = &vArray[off];
6642     if (numFields) {
6643       PetscInt fdof, foff, fcomp, f, c;
6644 
6645       for (f = 0, foff = 0; f < numFields; ++f) {
6646         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6647         if (o >= 0) {
6648           for (d = 0; d < fdof; ++d, ++offsets[f]) {
6649             array[offsets[f]] = varr[foff+d];
6650           }
6651         } else {
6652           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6653           for (d = fdof/fcomp-1; d >= 0; --d) {
6654             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
6655               array[offsets[f]] = varr[foff+d*fcomp+c];
6656             }
6657           }
6658         }
6659         foff += fdof;
6660       }
6661     } else {
6662       if (o >= 0) {
6663         for (d = 0; d < dof; ++d, ++offsets[0]) {
6664           array[offsets[0]] = varr[d];
6665         }
6666       } else {
6667         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6668           array[offsets[0]] = varr[d];
6669         }
6670       }
6671     }
6672   }
6673   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6674   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
6675   if (!*values) {
6676     if (csize) *csize = size;
6677     *values = array;
6678   } else {
6679     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
6680     *csize = size;
6681   }
6682   PetscFunctionReturn(0);
6683 }
6684 
6685 #undef __FUNCT__
6686 #define __FUNCT__ "DMPlexVecRestoreClosure"
6687 /*@C
6688   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6689 
6690   Not collective
6691 
6692   Input Parameters:
6693 + dm - The DM
6694 . section - The section describing the layout in v, or NULL to use the default section
6695 . v - The local vector
6696 . point - The sieve point in the DM
6697 . csize - The number of values in the closure, or NULL
6698 - values - The array of values, which is a borrowed array and should not be freed
6699 
6700   Fortran Notes:
6701   Since it returns an array, this routine is only available in Fortran 90, and you must
6702   include petsc.h90 in your code.
6703 
6704   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6705 
6706   Level: intermediate
6707 
6708 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6709 @*/
6710 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6711 {
6712   PetscInt       size = 0;
6713   PetscErrorCode ierr;
6714 
6715   PetscFunctionBegin;
6716   /* Should work without recalculating size */
6717   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
6718   PetscFunctionReturn(0);
6719 }
6720 
6721 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
6722 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
6723 
6724 #undef __FUNCT__
6725 #define __FUNCT__ "updatePoint_private"
6726 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6727 {
6728   PetscInt        cdof;   /* The number of constraints on this point */
6729   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6730   PetscScalar    *a;
6731   PetscInt        off, cind = 0, k;
6732   PetscErrorCode  ierr;
6733 
6734   PetscFunctionBegin;
6735   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6736   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6737   a    = &array[off];
6738   if (!cdof || setBC) {
6739     if (orientation >= 0) {
6740       for (k = 0; k < dof; ++k) {
6741         fuse(&a[k], values[k]);
6742       }
6743     } else {
6744       for (k = 0; k < dof; ++k) {
6745         fuse(&a[k], values[dof-k-1]);
6746       }
6747     }
6748   } else {
6749     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6750     if (orientation >= 0) {
6751       for (k = 0; k < dof; ++k) {
6752         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6753         fuse(&a[k], values[k]);
6754       }
6755     } else {
6756       for (k = 0; k < dof; ++k) {
6757         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6758         fuse(&a[k], values[dof-k-1]);
6759       }
6760     }
6761   }
6762   PetscFunctionReturn(0);
6763 }
6764 
6765 #undef __FUNCT__
6766 #define __FUNCT__ "updatePointBC_private"
6767 PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6768 {
6769   PetscInt        cdof;   /* The number of constraints on this point */
6770   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6771   PetscScalar    *a;
6772   PetscInt        off, cind = 0, k;
6773   PetscErrorCode  ierr;
6774 
6775   PetscFunctionBegin;
6776   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6777   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6778   a    = &array[off];
6779   if (cdof) {
6780     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6781     if (orientation >= 0) {
6782       for (k = 0; k < dof; ++k) {
6783         if ((cind < cdof) && (k == cdofs[cind])) {
6784           fuse(&a[k], values[k]);
6785           ++cind;
6786         }
6787       }
6788     } else {
6789       for (k = 0; k < dof; ++k) {
6790         if ((cind < cdof) && (k == cdofs[cind])) {
6791           fuse(&a[k], values[dof-k-1]);
6792           ++cind;
6793         }
6794       }
6795     }
6796   }
6797   PetscFunctionReturn(0);
6798 }
6799 
6800 #undef __FUNCT__
6801 #define __FUNCT__ "updatePointFields_private"
6802 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6803 {
6804   PetscScalar   *a;
6805   PetscInt       numFields, off, foff, f;
6806   PetscErrorCode ierr;
6807 
6808   PetscFunctionBegin;
6809   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6810   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6811   a    = &array[off];
6812   for (f = 0, foff = 0; f < numFields; ++f) {
6813     PetscInt        fdof, fcomp, fcdof;
6814     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6815     PetscInt        cind = 0, k, c;
6816 
6817     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6818     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6819     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6820     if (!fcdof || setBC) {
6821       if (orientation >= 0) {
6822         for (k = 0; k < fdof; ++k) {
6823           fuse(&a[foff+k], values[foffs[f]+k]);
6824         }
6825       } else {
6826         for (k = fdof/fcomp-1; k >= 0; --k) {
6827           for (c = 0; c < fcomp; ++c) {
6828             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6829           }
6830         }
6831       }
6832     } else {
6833       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6834       if (orientation >= 0) {
6835         for (k = 0; k < fdof; ++k) {
6836           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
6837           fuse(&a[foff+k], values[foffs[f]+k]);
6838         }
6839       } else {
6840         for (k = fdof/fcomp-1; k >= 0; --k) {
6841           for (c = 0; c < fcomp; ++c) {
6842             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
6843             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6844           }
6845         }
6846       }
6847     }
6848     foff     += fdof;
6849     foffs[f] += fdof;
6850   }
6851   PetscFunctionReturn(0);
6852 }
6853 
6854 #undef __FUNCT__
6855 #define __FUNCT__ "updatePointFieldsBC_private"
6856 PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6857 {
6858   PetscScalar   *a;
6859   PetscInt       numFields, off, foff, f;
6860   PetscErrorCode ierr;
6861 
6862   PetscFunctionBegin;
6863   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6864   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6865   a    = &array[off];
6866   for (f = 0, foff = 0; f < numFields; ++f) {
6867     PetscInt        fdof, fcomp, fcdof;
6868     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6869     PetscInt        cind = 0, k, c;
6870 
6871     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6872     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6873     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6874     if (fcdof) {
6875       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6876       if (orientation >= 0) {
6877         for (k = 0; k < fdof; ++k) {
6878           if ((cind < fcdof) && (k == fcdofs[cind])) {
6879             fuse(&a[foff+k], values[foffs[f]+k]);
6880             ++cind;
6881           }
6882         }
6883       } else {
6884         for (k = fdof/fcomp-1; k >= 0; --k) {
6885           for (c = 0; c < fcomp; ++c) {
6886             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
6887               fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6888               ++cind;
6889             }
6890           }
6891         }
6892       }
6893     }
6894     foff     += fdof;
6895     foffs[f] += fdof;
6896   }
6897   PetscFunctionReturn(0);
6898 }
6899 
6900 #undef __FUNCT__
6901 #define __FUNCT__ "DMPlexVecSetClosure"
6902 /*@C
6903   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6904 
6905   Not collective
6906 
6907   Input Parameters:
6908 + dm - The DM
6909 . section - The section describing the layout in v, or NULL to use the default section
6910 . v - The local vector
6911 . point - The sieve point in the DM
6912 . values - The array of values
6913 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6914 
6915   Fortran Notes:
6916   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6917 
6918   Level: intermediate
6919 
6920 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6921 @*/
6922 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6923 {
6924   PetscScalar   *array;
6925   PetscInt      *points = NULL;
6926   PetscInt       offsets[32];
6927   PetscInt       depth, numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
6928   PetscErrorCode ierr;
6929 
6930   PetscFunctionBegin;
6931   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6932   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6933   if (!section) {
6934     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6935   }
6936   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6937   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6938   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6939   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6940   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6941   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
6942     const PetscInt *cone, *coneO;
6943 
6944     ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
6945     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
6946     ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
6947     ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6948     for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6949       const PetscInt cp = !p ? point : cone[p-1];
6950       const PetscInt o  = !p ? 0     : coneO[p-1];
6951 
6952       if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
6953       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
6954       /* ADD_VALUES */
6955       {
6956         const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6957         PetscScalar    *a;
6958         PetscInt        cdof, coff, cind = 0, k;
6959 
6960         ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
6961         ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
6962         a    = &array[coff];
6963         if (!cdof) {
6964           if (o >= 0) {
6965             for (k = 0; k < dof; ++k) {
6966               a[k] += values[off+k];
6967             }
6968           } else {
6969             for (k = 0; k < dof; ++k) {
6970               a[k] += values[off+dof-k-1];
6971             }
6972           }
6973         } else {
6974           ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
6975           if (o >= 0) {
6976             for (k = 0; k < dof; ++k) {
6977               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6978               a[k] += values[off+k];
6979             }
6980           } else {
6981             for (k = 0; k < dof; ++k) {
6982               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6983               a[k] += values[off+dof-k-1];
6984             }
6985           }
6986         }
6987       }
6988     }
6989     ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6990     PetscFunctionReturn(0);
6991   }
6992   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6993   /* Compress out points not in the section */
6994   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6995     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6996       points[q*2]   = points[p];
6997       points[q*2+1] = points[p+1];
6998       ++q;
6999     }
7000   }
7001   numPoints = q;
7002   for (p = 0; p < numPoints*2; p += 2) {
7003     PetscInt fdof;
7004 
7005     for (f = 0; f < numFields; ++f) {
7006       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7007       offsets[f+1] += fdof;
7008     }
7009   }
7010   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7011   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
7012   if (numFields) {
7013     switch (mode) {
7014     case INSERT_VALUES:
7015       for (p = 0; p < numPoints*2; p += 2) {
7016         PetscInt o = points[p+1];
7017         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
7018       } break;
7019     case INSERT_ALL_VALUES:
7020       for (p = 0; p < numPoints*2; p += 2) {
7021         PetscInt o = points[p+1];
7022         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
7023       } break;
7024     case INSERT_BC_VALUES:
7025       for (p = 0; p < numPoints*2; p += 2) {
7026         PetscInt o = points[p+1];
7027         updatePointFieldsBC_private(section, points[p], offsets, insert,  o, values, array);
7028       } break;
7029     case ADD_VALUES:
7030       for (p = 0; p < numPoints*2; p += 2) {
7031         PetscInt o = points[p+1];
7032         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
7033       } break;
7034     case ADD_ALL_VALUES:
7035       for (p = 0; p < numPoints*2; p += 2) {
7036         PetscInt o = points[p+1];
7037         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
7038       } break;
7039     default:
7040       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7041     }
7042   } else {
7043     switch (mode) {
7044     case INSERT_VALUES:
7045       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7046         PetscInt o = points[p+1];
7047         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7048         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
7049       } break;
7050     case INSERT_ALL_VALUES:
7051       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7052         PetscInt o = points[p+1];
7053         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7054         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
7055       } break;
7056     case INSERT_BC_VALUES:
7057       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7058         PetscInt o = points[p+1];
7059         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7060         updatePointBC_private(section, points[p], dof, insert,  o, &values[off], array);
7061       } break;
7062     case ADD_VALUES:
7063       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7064         PetscInt o = points[p+1];
7065         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7066         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
7067       } break;
7068     case ADD_ALL_VALUES:
7069       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7070         PetscInt o = points[p+1];
7071         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7072         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
7073       } break;
7074     default:
7075       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7076     }
7077   }
7078   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7079   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
7080   PetscFunctionReturn(0);
7081 }
7082 
7083 #undef __FUNCT__
7084 #define __FUNCT__ "DMPlexPrintMatSetValues"
7085 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
7086 {
7087   PetscMPIInt    rank;
7088   PetscInt       i, j;
7089   PetscErrorCode ierr;
7090 
7091   PetscFunctionBegin;
7092   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
7093   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
7094   for (i = 0; i < numIndices; i++) {
7095     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
7096   }
7097   for (i = 0; i < numIndices; i++) {
7098     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
7099     for (j = 0; j < numIndices; j++) {
7100 #if defined(PETSC_USE_COMPLEX)
7101       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
7102 #else
7103       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
7104 #endif
7105     }
7106     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
7107   }
7108   PetscFunctionReturn(0);
7109 }
7110 
7111 #undef __FUNCT__
7112 #define __FUNCT__ "indicesPoint_private"
7113 /* . off - The global offset of this point */
7114 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
7115 {
7116   PetscInt        dof;    /* The number of unknowns on this point */
7117   PetscInt        cdof;   /* The number of constraints on this point */
7118   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7119   PetscInt        cind = 0, k;
7120   PetscErrorCode  ierr;
7121 
7122   PetscFunctionBegin;
7123   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
7124   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7125   if (!cdof || setBC) {
7126     if (orientation >= 0) {
7127       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
7128     } else {
7129       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
7130     }
7131   } else {
7132     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7133     if (orientation >= 0) {
7134       for (k = 0; k < dof; ++k) {
7135         if ((cind < cdof) && (k == cdofs[cind])) {
7136           /* Insert check for returning constrained indices */
7137           indices[*loff+k] = -(off+k+1);
7138           ++cind;
7139         } else {
7140           indices[*loff+k] = off+k-cind;
7141         }
7142       }
7143     } else {
7144       for (k = 0; k < dof; ++k) {
7145         if ((cind < cdof) && (k == cdofs[cind])) {
7146           /* Insert check for returning constrained indices */
7147           indices[*loff+dof-k-1] = -(off+k+1);
7148           ++cind;
7149         } else {
7150           indices[*loff+dof-k-1] = off+k-cind;
7151         }
7152       }
7153     }
7154   }
7155   *loff += dof;
7156   PetscFunctionReturn(0);
7157 }
7158 
7159 #undef __FUNCT__
7160 #define __FUNCT__ "indicesPointFields_private"
7161 /* . off - The global offset of this point */
7162 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
7163 {
7164   PetscInt       numFields, foff, f;
7165   PetscErrorCode ierr;
7166 
7167   PetscFunctionBegin;
7168   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7169   for (f = 0, foff = 0; f < numFields; ++f) {
7170     PetscInt        fdof, fcomp, cfdof;
7171     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7172     PetscInt        cind = 0, k, c;
7173 
7174     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7175     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7176     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
7177     if (!cfdof || setBC) {
7178       if (orientation >= 0) {
7179         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
7180       } else {
7181         for (k = fdof/fcomp-1; k >= 0; --k) {
7182           for (c = 0; c < fcomp; ++c) {
7183             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
7184           }
7185         }
7186       }
7187     } else {
7188       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7189       if (orientation >= 0) {
7190         for (k = 0; k < fdof; ++k) {
7191           if ((cind < cfdof) && (k == fcdofs[cind])) {
7192             indices[foffs[f]+k] = -(off+foff+k+1);
7193             ++cind;
7194           } else {
7195             indices[foffs[f]+k] = off+foff+k-cind;
7196           }
7197         }
7198       } else {
7199         for (k = fdof/fcomp-1; k >= 0; --k) {
7200           for (c = 0; c < fcomp; ++c) {
7201             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
7202               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
7203               ++cind;
7204             } else {
7205               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
7206             }
7207           }
7208         }
7209       }
7210     }
7211     foff     += fdof - cfdof;
7212     foffs[f] += fdof;
7213   }
7214   PetscFunctionReturn(0);
7215 }
7216 
7217 #undef __FUNCT__
7218 #define __FUNCT__ "DMPlexMatSetClosure"
7219 /*@C
7220   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
7221 
7222   Not collective
7223 
7224   Input Parameters:
7225 + dm - The DM
7226 . section - The section describing the layout in v
7227 . globalSection - The section describing the layout in v
7228 . A - The matrix
7229 . point - The sieve point in the DM
7230 . values - The array of values
7231 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7232 
7233   Fortran Notes:
7234   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
7235 
7236   Level: intermediate
7237 
7238 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
7239 @*/
7240 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7241 {
7242   DM_Plex       *mesh   = (DM_Plex*) dm->data;
7243   PetscInt      *points = NULL;
7244   PetscInt      *indices;
7245   PetscInt       offsets[32];
7246   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
7247   PetscErrorCode ierr;
7248 
7249   PetscFunctionBegin;
7250   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7251   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7252   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
7253   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7254   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7255   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7256   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7257   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7258   /* Compress out points not in the section */
7259   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7260   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7261     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7262       points[q*2]   = points[p];
7263       points[q*2+1] = points[p+1];
7264       ++q;
7265     }
7266   }
7267   numPoints = q;
7268   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
7269     PetscInt fdof;
7270 
7271     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7272     for (f = 0; f < numFields; ++f) {
7273       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7274       offsets[f+1] += fdof;
7275     }
7276     numIndices += dof;
7277   }
7278   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7279 
7280   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
7281   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7282   if (numFields) {
7283     for (p = 0; p < numPoints*2; p += 2) {
7284       PetscInt o = points[p+1];
7285       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7286       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
7287     }
7288   } else {
7289     for (p = 0, off = 0; p < numPoints*2; p += 2) {
7290       PetscInt o = points[p+1];
7291       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7292       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
7293     }
7294   }
7295   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
7296   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7297   if (ierr) {
7298     PetscMPIInt    rank;
7299     PetscErrorCode ierr2;
7300 
7301     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
7302     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7303     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
7304     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
7305     CHKERRQ(ierr);
7306   }
7307   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7308   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7309   PetscFunctionReturn(0);
7310 }
7311 
7312 #undef __FUNCT__
7313 #define __FUNCT__ "DMPlexGetHybridBounds"
7314 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
7315 {
7316   DM_Plex       *mesh = (DM_Plex*) dm->data;
7317   PetscInt       dim;
7318   PetscErrorCode ierr;
7319 
7320   PetscFunctionBegin;
7321   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7322   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7323   if (cMax) *cMax = mesh->hybridPointMax[dim];
7324   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
7325   if (eMax) *eMax = mesh->hybridPointMax[1];
7326   if (vMax) *vMax = mesh->hybridPointMax[0];
7327   PetscFunctionReturn(0);
7328 }
7329 
7330 #undef __FUNCT__
7331 #define __FUNCT__ "DMPlexSetHybridBounds"
7332 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
7333 {
7334   DM_Plex       *mesh = (DM_Plex*) dm->data;
7335   PetscInt       dim;
7336   PetscErrorCode ierr;
7337 
7338   PetscFunctionBegin;
7339   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7340   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7341   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
7342   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
7343   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
7344   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
7345   PetscFunctionReturn(0);
7346 }
7347 
7348 #undef __FUNCT__
7349 #define __FUNCT__ "DMPlexGetVTKCellHeight"
7350 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7351 {
7352   DM_Plex *mesh = (DM_Plex*) dm->data;
7353 
7354   PetscFunctionBegin;
7355   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7356   PetscValidPointer(cellHeight, 2);
7357   *cellHeight = mesh->vtkCellHeight;
7358   PetscFunctionReturn(0);
7359 }
7360 
7361 #undef __FUNCT__
7362 #define __FUNCT__ "DMPlexSetVTKCellHeight"
7363 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7364 {
7365   DM_Plex *mesh = (DM_Plex*) dm->data;
7366 
7367   PetscFunctionBegin;
7368   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7369   mesh->vtkCellHeight = cellHeight;
7370   PetscFunctionReturn(0);
7371 }
7372 
7373 #undef __FUNCT__
7374 #define __FUNCT__ "DMPlexCreateNumbering_Private"
7375 /* We can easily have a form that takes an IS instead */
7376 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
7377 {
7378   PetscSection   section, globalSection;
7379   PetscInt      *numbers, p;
7380   PetscErrorCode ierr;
7381 
7382   PetscFunctionBegin;
7383   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7384   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
7385   for (p = pStart; p < pEnd; ++p) {
7386     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
7387   }
7388   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
7389   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7390   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
7391   for (p = pStart; p < pEnd; ++p) {
7392     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
7393   }
7394   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
7395   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7396   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7397   PetscFunctionReturn(0);
7398 }
7399 
7400 #undef __FUNCT__
7401 #define __FUNCT__ "DMPlexGetCellNumbering"
7402 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
7403 {
7404   DM_Plex       *mesh = (DM_Plex*) dm->data;
7405   PetscInt       cellHeight, cStart, cEnd, cMax;
7406   PetscErrorCode ierr;
7407 
7408   PetscFunctionBegin;
7409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7410   if (!mesh->globalCellNumbers) {
7411     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
7412     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
7413     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7414     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7415     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
7416   }
7417   *globalCellNumbers = mesh->globalCellNumbers;
7418   PetscFunctionReturn(0);
7419 }
7420 
7421 #undef __FUNCT__
7422 #define __FUNCT__ "DMPlexGetVertexNumbering"
7423 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
7424 {
7425   DM_Plex       *mesh = (DM_Plex*) dm->data;
7426   PetscInt       vStart, vEnd, vMax;
7427   PetscErrorCode ierr;
7428 
7429   PetscFunctionBegin;
7430   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7431   if (!mesh->globalVertexNumbers) {
7432     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7433     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
7434     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
7435     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
7436   }
7437   *globalVertexNumbers = mesh->globalVertexNumbers;
7438   PetscFunctionReturn(0);
7439 }
7440 
7441 
7442 #undef __FUNCT__
7443 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
7444 /*@C
7445   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
7446   the local section and an SF describing the section point overlap.
7447 
7448   Input Parameters:
7449   + s - The PetscSection for the local field layout
7450   . sf - The SF describing parallel layout of the section points
7451   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
7452   . label - The label specifying the points
7453   - labelValue - The label stratum specifying the points
7454 
7455   Output Parameter:
7456   . gsection - The PetscSection for the global field layout
7457 
7458   Note: This gives negative sizes and offsets to points not owned by this process
7459 
7460   Level: developer
7461 
7462 .seealso: PetscSectionCreate()
7463 @*/
7464 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
7465 {
7466   PetscInt      *neg = NULL, *tmpOff = NULL;
7467   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
7468   PetscErrorCode ierr;
7469 
7470   PetscFunctionBegin;
7471   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
7472   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
7473   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
7474   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
7475   if (nroots >= 0) {
7476     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
7477     ierr = PetscMalloc(nroots * sizeof(PetscInt), &neg);CHKERRQ(ierr);
7478     ierr = PetscMemzero(neg, nroots * sizeof(PetscInt));CHKERRQ(ierr);
7479     if (nroots > pEnd-pStart) {
7480       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
7481       ierr = PetscMemzero(tmpOff, nroots * sizeof(PetscInt));CHKERRQ(ierr);
7482     } else {
7483       tmpOff = &(*gsection)->atlasDof[-pStart];
7484     }
7485   }
7486   /* Mark ghost points with negative dof */
7487   for (p = pStart; p < pEnd; ++p) {
7488     PetscInt value;
7489 
7490     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
7491     if (value != labelValue) continue;
7492     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
7493     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
7494     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
7495     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
7496     if (neg) neg[p] = -(dof+1);
7497   }
7498   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
7499   if (nroots >= 0) {
7500     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
7501     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
7502     if (nroots > pEnd-pStart) {
7503       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
7504     }
7505   }
7506   /* Calculate new sizes, get proccess offset, and calculate point offsets */
7507   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7508     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
7509     (*gsection)->atlasOff[p] = off;
7510     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
7511   }
7512   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
7513   globalOff -= off;
7514   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7515     (*gsection)->atlasOff[p] += globalOff;
7516     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
7517   }
7518   /* Put in negative offsets for ghost points */
7519   if (nroots >= 0) {
7520     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
7521     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
7522     if (nroots > pEnd-pStart) {
7523       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
7524     }
7525   }
7526   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
7527   ierr = PetscFree(neg);CHKERRQ(ierr);
7528   PetscFunctionReturn(0);
7529 }
7530