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