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