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