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