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