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