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