xref: /petsc/src/dm/impls/plex/plex.c (revision 8ebe8da968fe942b41f5fad884758883d9983c89)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/vecimpl.h>
4 #include <petsc-private/isimpl.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
8 
9 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 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     }
340   }
341   PetscFunctionReturn(0);
342 }
343 
344 #undef __FUNCT__
345 #define __FUNCT__ "DMView_Plex"
346 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
347 {
348   PetscBool      iascii, isbinary;
349   PetscErrorCode ierr;
350 
351   PetscFunctionBegin;
352   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
353   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
354   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
355   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
356   if (iascii) {
357     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
358 #if 0
359   } else if (isbinary) {
360     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
361 #endif
362   }
363   PetscFunctionReturn(0);
364 }
365 
366 #undef __FUNCT__
367 #define __FUNCT__ "DMDestroy_Plex"
368 PetscErrorCode DMDestroy_Plex(DM dm)
369 {
370   DM_Plex       *mesh = (DM_Plex*) dm->data;
371   DMLabel        next  = mesh->labels;
372   PetscErrorCode ierr;
373 
374   PetscFunctionBegin;
375   if (--mesh->refct > 0) PetscFunctionReturn(0);
376   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
377   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
378   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
379   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
380   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
381   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
382   while (next) {
383     DMLabel tmp = next->next;
384 
385     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
386     next = tmp;
387   }
388   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
389   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
390   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
391   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
392   ierr = PetscFree(mesh);CHKERRQ(ierr);
393   PetscFunctionReturn(0);
394 }
395 
396 #undef __FUNCT__
397 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
398 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
399 {
400   const PetscInt *support = NULL;
401   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
402   PetscErrorCode  ierr;
403 
404   PetscFunctionBegin;
405   if (useClosure) {
406     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
407     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
408     for (s = 0; s < supportSize; ++s) {
409       const PetscInt *cone = NULL;
410       PetscInt        coneSize, c, q;
411 
412       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
413       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
414       for (c = 0; c < coneSize; ++c) {
415         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
416           if (cone[c] == adj[q]) break;
417         }
418         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
419       }
420     }
421   } else {
422     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
423     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
424     for (s = 0; s < supportSize; ++s) {
425       const PetscInt *cone = NULL;
426       PetscInt        coneSize, c, q;
427 
428       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
429       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
430       for (c = 0; c < coneSize; ++c) {
431         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
432           if (cone[c] == adj[q]) break;
433         }
434         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
435       }
436     }
437   }
438   *adjSize = numAdj;
439   PetscFunctionReturn(0);
440 }
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "DMPlexGetAdjacency_Private"
444 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
445 {
446   const PetscInt *star  = tmpClosure;
447   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
448   PetscErrorCode  ierr;
449 
450   PetscFunctionBegin;
451   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
452   for (s = 2; s < starSize*2; s += 2) {
453     const PetscInt *closure = NULL;
454     PetscInt        closureSize, c, q;
455 
456     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
457     for (c = 0; c < closureSize*2; c += 2) {
458       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
459         if (closure[c] == adj[q]) break;
460       }
461       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
462     }
463     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
464   }
465   *adjSize = numAdj;
466   PetscFunctionReturn(0);
467 }
468 
469 #undef __FUNCT__
470 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
471 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
472 {
473   DM_Plex *mesh = (DM_Plex*) dm->data;
474 
475   PetscFunctionBegin;
476   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
477   mesh->preallocCenterDim = preallocCenterDim;
478   PetscFunctionReturn(0);
479 }
480 
481 #undef __FUNCT__
482 #define __FUNCT__ "DMPlexPreallocateOperator"
483 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
484 {
485   DM_Plex           *mesh = (DM_Plex*) dm->data;
486   MPI_Comm           comm;
487   PetscSF            sf, sfDof, sfAdj;
488   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
489   PetscInt           nleaves, l, p;
490   const PetscInt    *leaves;
491   const PetscSFNode *remotes;
492   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
493   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
494   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
495   PetscLayout        rLayout;
496   PetscInt           locRows, rStart, rEnd, r;
497   PetscMPIInt        size;
498   PetscBool          useClosure, debug = PETSC_FALSE;
499   PetscErrorCode     ierr;
500 
501   PetscFunctionBegin;
502   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
503   ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr);
504   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
505   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
506   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
507   /* Create dof SF based on point SF */
508   if (debug) {
509     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
510     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
511     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
512     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
513     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
514     ierr = PetscSFView(sf, NULL);CHKERRQ(ierr);
515   }
516   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
517   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
518   if (debug) {
519     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
520     ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr);
521   }
522   /* Create section for dof adjacency (dof ==> # adj dof) */
523   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
524   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
525   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
526   if (mesh->preallocCenterDim == dim) {
527     useClosure = PETSC_FALSE;
528   } else if (mesh->preallocCenterDim == 0) {
529     useClosure = PETSC_TRUE;
530   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
531 
532   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
533   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
534   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
535   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
536   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
537   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
538   /*   Fill in the ghost dofs on the interface */
539   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
540   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
541   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
542 
543   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
544   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
545 
546   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
547 
548   /*
549    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
550     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
551        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
552     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
553        Create sfAdj connecting rootSectionAdj and leafSectionAdj
554     3. Visit unowned points on interface, write adjacencies to adj
555        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
556     4. Visit owned points on interface, write adjacencies to rootAdj
557        Remove redundancy in rootAdj
558    ** The last two traversals use transitive closure
559     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
560        Allocate memory addressed by sectionAdj (cols)
561     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
562    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
563   */
564 
565   for (l = 0; l < nleaves; ++l) {
566     PetscInt dof, off, d, q;
567     PetscInt p = leaves[l], numAdj = maxAdjSize;
568 
569     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
570     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
571     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
572     for (q = 0; q < numAdj; ++q) {
573       const PetscInt padj = tmpAdj[q];
574       PetscInt ndof, ncdof;
575 
576       if ((padj < pStart) || (padj >= pEnd)) continue;
577       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
578       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
579       for (d = off; d < off+dof; ++d) {
580         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
581       }
582     }
583   }
584   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
585   if (debug) {
586     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
587     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
588   }
589   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
590   if (size > 1) {
591     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
592     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
593   }
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
596     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
597   }
598   /* Add in local adjacency sizes for owned dofs on interface (roots) */
599   for (p = pStart; p < pEnd; ++p) {
600     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
601 
602     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
603     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
604     if (!dof) continue;
605     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
606     if (adof <= 0) continue;
607     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
608     for (q = 0; q < numAdj; ++q) {
609       const PetscInt padj = tmpAdj[q];
610       PetscInt ndof, ncdof;
611 
612       if ((padj < pStart) || (padj >= pEnd)) continue;
613       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
614       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
615       for (d = off; d < off+dof; ++d) {
616         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
617       }
618     }
619   }
620   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
621   if (debug) {
622     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
623     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
624   }
625   /* Create adj SF based on dof SF */
626   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
627   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
628   if (debug) {
629     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
630     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
631   }
632   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
633   /* Create leaf adjacency */
634   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
635   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
636   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
637   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
638   for (l = 0; l < nleaves; ++l) {
639     PetscInt dof, off, d, q;
640     PetscInt p = leaves[l], numAdj = maxAdjSize;
641 
642     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
643     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
644     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
645     for (d = off; d < off+dof; ++d) {
646       PetscInt aoff, i = 0;
647 
648       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
649       for (q = 0; q < numAdj; ++q) {
650         const PetscInt padj = tmpAdj[q];
651         PetscInt ndof, ncdof, ngoff, nd;
652 
653         if ((padj < pStart) || (padj >= pEnd)) continue;
654         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
655         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
656         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
657         for (nd = 0; nd < ndof-ncdof; ++nd) {
658           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
659           ++i;
660         }
661       }
662     }
663   }
664   /* Debugging */
665   if (debug) {
666     IS tmp;
667     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
668     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
669     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
670   }
671   /* Gather adjacenct indices to root */
672   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
673   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
674   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
675   if (size > 1) {
676     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
677     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
678   }
679   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
680   ierr = PetscFree(adj);CHKERRQ(ierr);
681   /* Debugging */
682   if (debug) {
683     IS tmp;
684     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
685     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
686     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
687   }
688   /* Add in local adjacency indices for owned dofs on interface (roots) */
689   for (p = pStart; p < pEnd; ++p) {
690     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
691 
692     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
693     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
694     if (!dof) continue;
695     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
696     if (adof <= 0) continue;
697     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
698     for (d = off; d < off+dof; ++d) {
699       PetscInt adof, aoff, i;
700 
701       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
702       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
703       i    = adof-1;
704       for (q = 0; q < numAdj; ++q) {
705         const PetscInt padj = tmpAdj[q];
706         PetscInt ndof, ncdof, ngoff, nd;
707 
708         if ((padj < pStart) || (padj >= pEnd)) continue;
709         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
710         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
711         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
712         for (nd = 0; nd < ndof-ncdof; ++nd) {
713           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
714           --i;
715         }
716       }
717     }
718   }
719   /* Debugging */
720   if (debug) {
721     IS tmp;
722     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
723     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
724     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
725   }
726   /* Compress indices */
727   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
728   for (p = pStart; p < pEnd; ++p) {
729     PetscInt dof, cdof, off, d;
730     PetscInt adof, aoff;
731 
732     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
733     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
734     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
735     if (!dof) continue;
736     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
737     if (adof <= 0) continue;
738     for (d = off; d < off+dof-cdof; ++d) {
739       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
740       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
741       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
742       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
743     }
744   }
745   /* Debugging */
746   if (debug) {
747     IS tmp;
748     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
749     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
750     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
751     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
752     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
753   }
754   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
755   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
756   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
757   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
758   for (p = pStart; p < pEnd; ++p) {
759     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
760     PetscBool found  = PETSC_TRUE;
761 
762     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
763     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
764     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
765     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
766     for (d = 0; d < dof-cdof; ++d) {
767       PetscInt ldof, rdof;
768 
769       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
770       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
771       if (ldof > 0) {
772         /* We do not own this point */
773       } else if (rdof > 0) {
774         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
775       } else {
776         found = PETSC_FALSE;
777       }
778     }
779     if (found) continue;
780     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
781     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
782     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
783     for (q = 0; q < numAdj; ++q) {
784       const PetscInt padj = tmpAdj[q];
785       PetscInt ndof, ncdof, noff;
786 
787       if ((padj < pStart) || (padj >= pEnd)) continue;
788       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
789       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
790       ierr = PetscSectionGetOffset(section, padj, &noff);CHKERRQ(ierr);
791       for (d = goff; d < goff+dof-cdof; ++d) {
792         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
793       }
794     }
795   }
796   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
797   if (debug) {
798     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
799     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
800   }
801   /* Get adjacent indices */
802   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
803   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
804   for (p = pStart; p < pEnd; ++p) {
805     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
806     PetscBool found  = PETSC_TRUE;
807 
808     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
809     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
810     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
811     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
812     for (d = 0; d < dof-cdof; ++d) {
813       PetscInt ldof, rdof;
814 
815       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
816       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
817       if (ldof > 0) {
818         /* We do not own this point */
819       } else if (rdof > 0) {
820         PetscInt aoff, roff;
821 
822         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
823         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
824         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
825       } else {
826         found = PETSC_FALSE;
827       }
828     }
829     if (found) continue;
830     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
831     for (d = goff; d < goff+dof-cdof; ++d) {
832       PetscInt adof, aoff, i = 0;
833 
834       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
835       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
836       for (q = 0; q < numAdj; ++q) {
837         const PetscInt  padj = tmpAdj[q];
838         PetscInt        ndof, ncdof, ngoff, nd;
839         const PetscInt *ncind;
840 
841         /* Adjacent points may not be in the section chart */
842         if ((padj < pStart) || (padj >= pEnd)) continue;
843         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
844         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
845         ierr = PetscSectionGetConstraintIndices(section, padj, &ncind);CHKERRQ(ierr);
846         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
847         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
848           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
849         }
850       }
851       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
852     }
853   }
854   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
855   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
856   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
857   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
858   /* Debugging */
859   if (debug) {
860     IS tmp;
861     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
862     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
863     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
864   }
865   /* Create allocation vectors from adjacency graph */
866   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
867   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr);
868   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
869   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
870   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
871   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
872   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
873   /* Only loop over blocks of rows */
874   if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
875   for (r = rStart/bs; r < rEnd/bs; ++r) {
876     const PetscInt row = r*bs;
877     PetscInt       numCols, cStart, c;
878 
879     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
880     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
881     for (c = cStart; c < cStart+numCols; ++c) {
882       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
883         ++dnz[r-rStart];
884         if (cols[c] >= row) ++dnzu[r-rStart];
885       } else {
886         ++onz[r-rStart];
887         if (cols[c] >= row) ++onzu[r-rStart];
888       }
889     }
890   }
891   if (bs > 1) {
892     for (r = 0; r < locRows/bs; ++r) {
893       dnz[r]  /= bs;
894       onz[r]  /= bs;
895       dnzu[r] /= bs;
896       onzu[r] /= bs;
897     }
898   }
899   /* Set matrix pattern */
900   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
901   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
902   /* Fill matrix with zeros */
903   if (fillMatrix) {
904     PetscScalar *values;
905     PetscInt     maxRowLen = 0;
906 
907     for (r = rStart; r < rEnd; ++r) {
908       PetscInt len;
909 
910       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
911       maxRowLen = PetscMax(maxRowLen, len);
912     }
913     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
914     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
915     for (r = rStart; r < rEnd; ++r) {
916       PetscInt numCols, cStart;
917 
918       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
919       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
920       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
921     }
922     ierr = PetscFree(values);CHKERRQ(ierr);
923     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
924     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
925   }
926   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
927   ierr = PetscFree(cols);CHKERRQ(ierr);
928   PetscFunctionReturn(0);
929 }
930 
931 #if 0
932 #undef __FUNCT__
933 #define __FUNCT__ "DMPlexPreallocateOperator_2"
934 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
935 {
936   PetscInt       *tmpClosure,*tmpAdj,*visits;
937   PetscInt        c,cStart,cEnd,pStart,pEnd;
938   PetscErrorCode  ierr;
939 
940   PetscFunctionBegin;
941   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
942   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
943   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
944 
945   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
946 
947   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
948   npoints = pEnd - pStart;
949 
950   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
951   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
952   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
953   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
954   for (c=cStart; c<cEnd; c++) {
955     PetscInt *support = tmpClosure;
956     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
957     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
958   }
959   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
960   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
961   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
962   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
963 
964   ierr = PetscSFGetRanks();CHKERRQ(ierr);
965 
966 
967   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
968   for (c=cStart; c<cEnd; c++) {
969     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
970     /*
971      Depth-first walk of transitive closure.
972      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
973      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
974      */
975   }
976 
977   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
978   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
979   PetscFunctionReturn(0);
980 }
981 #endif
982 
983 #undef __FUNCT__
984 #define __FUNCT__ "DMCreateMatrix_Plex"
985 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
986 {
987   PetscSection   section, sectionGlobal;
988   PetscInt       bs = -1;
989   PetscInt       localSize;
990   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
991   PetscErrorCode ierr;
992 
993   PetscFunctionBegin;
994 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
995   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
996 #endif
997   if (!mtype) mtype = MATAIJ;
998   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
999   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1000   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
1001   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
1002   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
1003   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1004   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
1005   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
1006   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
1007   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
1008   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
1009   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
1010   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
1011   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
1012   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
1013   /* Check for symmetric storage */
1014   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
1015   if (isSymmetric) {
1016     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
1017   }
1018   if (!isShell) {
1019     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
1020     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
1021 
1022     if (bs < 0) {
1023       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
1024         PetscInt pStart, pEnd, p, dof, cdof;
1025 
1026         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1027         for (p = pStart; p < pEnd; ++p) {
1028           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
1029           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
1030           if (dof-cdof) {
1031             if (bs < 0) {
1032               bs = dof-cdof;
1033             } else if (bs != dof-cdof) {
1034               /* Layout does not admit a pointwise block size */
1035               bs = 1;
1036               break;
1037             }
1038           }
1039         }
1040         /* Must have same blocksize on all procs (some might have no points) */
1041         bsLocal = bs;
1042         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1043         bsLocal = bs < 0 ? bsMax : bs;
1044         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1045         if (bsMin != bsMax) {
1046           bs = 1;
1047         } else {
1048           bs = bsMax;
1049         }
1050       } else {
1051         bs = 1;
1052       }
1053     }
1054     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1055     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1056     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1057     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1058     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1059     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1060     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1061   }
1062   PetscFunctionReturn(0);
1063 }
1064 
1065 #undef __FUNCT__
1066 #define __FUNCT__ "DMPlexGetDimension"
1067 /*@
1068   DMPlexGetDimension - Return the topological mesh dimension
1069 
1070   Not collective
1071 
1072   Input Parameter:
1073 . mesh - The DMPlex
1074 
1075   Output Parameter:
1076 . dim - The topological mesh dimension
1077 
1078   Level: beginner
1079 
1080 .seealso: DMPlexCreate()
1081 @*/
1082 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1083 {
1084   DM_Plex *mesh = (DM_Plex*) dm->data;
1085 
1086   PetscFunctionBegin;
1087   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1088   PetscValidPointer(dim, 2);
1089   *dim = mesh->dim;
1090   PetscFunctionReturn(0);
1091 }
1092 
1093 #undef __FUNCT__
1094 #define __FUNCT__ "DMPlexSetDimension"
1095 /*@
1096   DMPlexSetDimension - Set the topological mesh dimension
1097 
1098   Collective on mesh
1099 
1100   Input Parameters:
1101 + mesh - The DMPlex
1102 - dim - The topological mesh dimension
1103 
1104   Level: beginner
1105 
1106 .seealso: DMPlexCreate()
1107 @*/
1108 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1109 {
1110   DM_Plex *mesh = (DM_Plex*) dm->data;
1111 
1112   PetscFunctionBegin;
1113   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1114   PetscValidLogicalCollectiveInt(dm, dim, 2);
1115   mesh->dim               = dim;
1116   mesh->preallocCenterDim = dim;
1117   PetscFunctionReturn(0);
1118 }
1119 
1120 #undef __FUNCT__
1121 #define __FUNCT__ "DMPlexGetChart"
1122 /*@
1123   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1124 
1125   Not collective
1126 
1127   Input Parameter:
1128 . mesh - The DMPlex
1129 
1130   Output Parameters:
1131 + pStart - The first mesh point
1132 - pEnd   - The upper bound for mesh points
1133 
1134   Level: beginner
1135 
1136 .seealso: DMPlexCreate(), DMPlexSetChart()
1137 @*/
1138 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1139 {
1140   DM_Plex       *mesh = (DM_Plex*) dm->data;
1141   PetscErrorCode ierr;
1142 
1143   PetscFunctionBegin;
1144   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1145   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1146   PetscFunctionReturn(0);
1147 }
1148 
1149 #undef __FUNCT__
1150 #define __FUNCT__ "DMPlexSetChart"
1151 /*@
1152   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1153 
1154   Not collective
1155 
1156   Input Parameters:
1157 + mesh - The DMPlex
1158 . pStart - The first mesh point
1159 - pEnd   - The upper bound for mesh points
1160 
1161   Output Parameters:
1162 
1163   Level: beginner
1164 
1165 .seealso: DMPlexCreate(), DMPlexGetChart()
1166 @*/
1167 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1168 {
1169   DM_Plex       *mesh = (DM_Plex*) dm->data;
1170   PetscErrorCode ierr;
1171 
1172   PetscFunctionBegin;
1173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1174   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1175   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1176   PetscFunctionReturn(0);
1177 }
1178 
1179 #undef __FUNCT__
1180 #define __FUNCT__ "DMPlexGetConeSize"
1181 /*@
1182   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1183 
1184   Not collective
1185 
1186   Input Parameters:
1187 + mesh - The DMPlex
1188 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1189 
1190   Output Parameter:
1191 . size - The cone size for point p
1192 
1193   Level: beginner
1194 
1195 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1196 @*/
1197 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1198 {
1199   DM_Plex       *mesh = (DM_Plex*) dm->data;
1200   PetscErrorCode ierr;
1201 
1202   PetscFunctionBegin;
1203   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1204   PetscValidPointer(size, 3);
1205   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1206   PetscFunctionReturn(0);
1207 }
1208 
1209 #undef __FUNCT__
1210 #define __FUNCT__ "DMPlexSetConeSize"
1211 /*@
1212   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1213 
1214   Not collective
1215 
1216   Input Parameters:
1217 + mesh - The DMPlex
1218 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1219 - size - The cone size for point p
1220 
1221   Output Parameter:
1222 
1223   Note:
1224   This should be called after DMPlexSetChart().
1225 
1226   Level: beginner
1227 
1228 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1229 @*/
1230 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1231 {
1232   DM_Plex       *mesh = (DM_Plex*) dm->data;
1233   PetscErrorCode ierr;
1234 
1235   PetscFunctionBegin;
1236   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1237   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1238 
1239   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1240   PetscFunctionReturn(0);
1241 }
1242 
1243 #undef __FUNCT__
1244 #define __FUNCT__ "DMPlexGetCone"
1245 /*@C
1246   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1247 
1248   Not collective
1249 
1250   Input Parameters:
1251 + mesh - The DMPlex
1252 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1253 
1254   Output Parameter:
1255 . cone - An array of points which are on the in-edges for point p
1256 
1257   Level: beginner
1258 
1259   Note:
1260   This routine is not available in Fortran.
1261 
1262 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1263 @*/
1264 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1265 {
1266   DM_Plex       *mesh = (DM_Plex*) dm->data;
1267   PetscInt       off;
1268   PetscErrorCode ierr;
1269 
1270   PetscFunctionBegin;
1271   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1272   PetscValidPointer(cone, 3);
1273   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1274   *cone = &mesh->cones[off];
1275   PetscFunctionReturn(0);
1276 }
1277 
1278 #undef __FUNCT__
1279 #define __FUNCT__ "DMPlexSetCone"
1280 /*@
1281   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1282 
1283   Not collective
1284 
1285   Input Parameters:
1286 + mesh - The DMPlex
1287 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1288 - cone - An array of points which are on the in-edges for point p
1289 
1290   Output Parameter:
1291 
1292   Note:
1293   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1294 
1295   Level: beginner
1296 
1297 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1298 @*/
1299 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1300 {
1301   DM_Plex       *mesh = (DM_Plex*) dm->data;
1302   PetscInt       pStart, pEnd;
1303   PetscInt       dof, off, c;
1304   PetscErrorCode ierr;
1305 
1306   PetscFunctionBegin;
1307   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1308   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1309   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1310   if (dof) PetscValidPointer(cone, 3);
1311   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1312   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);
1313   for (c = 0; c < dof; ++c) {
1314     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);
1315     mesh->cones[off+c] = cone[c];
1316   }
1317   PetscFunctionReturn(0);
1318 }
1319 
1320 #undef __FUNCT__
1321 #define __FUNCT__ "DMPlexGetConeOrientation"
1322 /*@C
1323   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1324 
1325   Not collective
1326 
1327   Input Parameters:
1328 + mesh - The DMPlex
1329 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1330 
1331   Output Parameter:
1332 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1333                     integer giving the prescription for cone traversal. If it is negative, the cone is
1334                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1335                     the index of the cone point on which to start.
1336 
1337   Level: beginner
1338 
1339   Note:
1340   This routine is not available in Fortran.
1341 
1342 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1343 @*/
1344 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1345 {
1346   DM_Plex       *mesh = (DM_Plex*) dm->data;
1347   PetscInt       off;
1348   PetscErrorCode ierr;
1349 
1350   PetscFunctionBegin;
1351   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1352 #if defined(PETSC_USE_DEBUG)
1353   {
1354     PetscInt dof;
1355     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1356     if (dof) PetscValidPointer(coneOrientation, 3);
1357   }
1358 #endif
1359   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1360 
1361   *coneOrientation = &mesh->coneOrientations[off];
1362   PetscFunctionReturn(0);
1363 }
1364 
1365 #undef __FUNCT__
1366 #define __FUNCT__ "DMPlexSetConeOrientation"
1367 /*@
1368   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1369 
1370   Not collective
1371 
1372   Input Parameters:
1373 + mesh - The DMPlex
1374 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1375 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1376                     integer giving the prescription for cone traversal. If it is negative, the cone is
1377                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1378                     the index of the cone point on which to start.
1379 
1380   Output Parameter:
1381 
1382   Note:
1383   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1384 
1385   Level: beginner
1386 
1387 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1388 @*/
1389 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1390 {
1391   DM_Plex       *mesh = (DM_Plex*) dm->data;
1392   PetscInt       pStart, pEnd;
1393   PetscInt       dof, off, c;
1394   PetscErrorCode ierr;
1395 
1396   PetscFunctionBegin;
1397   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1398   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1399   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1400   if (dof) PetscValidPointer(coneOrientation, 3);
1401   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1402   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);
1403   for (c = 0; c < dof; ++c) {
1404     PetscInt cdof, o = coneOrientation[c];
1405 
1406     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1407     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);
1408     mesh->coneOrientations[off+c] = o;
1409   }
1410   PetscFunctionReturn(0);
1411 }
1412 
1413 #undef __FUNCT__
1414 #define __FUNCT__ "DMPlexInsertCone"
1415 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1416 {
1417   DM_Plex       *mesh = (DM_Plex*) dm->data;
1418   PetscInt       pStart, pEnd;
1419   PetscInt       dof, off;
1420   PetscErrorCode ierr;
1421 
1422   PetscFunctionBegin;
1423   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1424   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1425   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);
1426   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);
1427   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1428   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1429   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);
1430   mesh->cones[off+conePos] = conePoint;
1431   PetscFunctionReturn(0);
1432 }
1433 
1434 #undef __FUNCT__
1435 #define __FUNCT__ "DMPlexInsertConeOrientation"
1436 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1437 {
1438   DM_Plex       *mesh = (DM_Plex*) dm->data;
1439   PetscInt       pStart, pEnd;
1440   PetscInt       dof, off;
1441   PetscErrorCode ierr;
1442 
1443   PetscFunctionBegin;
1444   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1445   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1446   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);
1447   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1448   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1449   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);
1450   mesh->coneOrientations[off+conePos] = coneOrientation;
1451   PetscFunctionReturn(0);
1452 }
1453 
1454 #undef __FUNCT__
1455 #define __FUNCT__ "DMPlexGetSupportSize"
1456 /*@
1457   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1458 
1459   Not collective
1460 
1461   Input Parameters:
1462 + mesh - The DMPlex
1463 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1464 
1465   Output Parameter:
1466 . size - The support size for point p
1467 
1468   Level: beginner
1469 
1470 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1471 @*/
1472 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1473 {
1474   DM_Plex       *mesh = (DM_Plex*) dm->data;
1475   PetscErrorCode ierr;
1476 
1477   PetscFunctionBegin;
1478   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1479   PetscValidPointer(size, 3);
1480   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1481   PetscFunctionReturn(0);
1482 }
1483 
1484 #undef __FUNCT__
1485 #define __FUNCT__ "DMPlexSetSupportSize"
1486 /*@
1487   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1488 
1489   Not collective
1490 
1491   Input Parameters:
1492 + mesh - The DMPlex
1493 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1494 - size - The support size for point p
1495 
1496   Output Parameter:
1497 
1498   Note:
1499   This should be called after DMPlexSetChart().
1500 
1501   Level: beginner
1502 
1503 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1504 @*/
1505 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1506 {
1507   DM_Plex       *mesh = (DM_Plex*) dm->data;
1508   PetscErrorCode ierr;
1509 
1510   PetscFunctionBegin;
1511   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1512   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1513 
1514   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1515   PetscFunctionReturn(0);
1516 }
1517 
1518 #undef __FUNCT__
1519 #define __FUNCT__ "DMPlexGetSupport"
1520 /*@C
1521   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1522 
1523   Not collective
1524 
1525   Input Parameters:
1526 + mesh - The DMPlex
1527 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1528 
1529   Output Parameter:
1530 . support - An array of points which are on the out-edges for point p
1531 
1532   Level: beginner
1533 
1534 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1535 @*/
1536 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1537 {
1538   DM_Plex       *mesh = (DM_Plex*) dm->data;
1539   PetscInt       off;
1540   PetscErrorCode ierr;
1541 
1542   PetscFunctionBegin;
1543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1544   PetscValidPointer(support, 3);
1545   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1546   *support = &mesh->supports[off];
1547   PetscFunctionReturn(0);
1548 }
1549 
1550 #undef __FUNCT__
1551 #define __FUNCT__ "DMPlexSetSupport"
1552 /*@
1553   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1554 
1555   Not collective
1556 
1557   Input Parameters:
1558 + mesh - The DMPlex
1559 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1560 - support - An array of points which are on the in-edges for point p
1561 
1562   Output Parameter:
1563 
1564   Note:
1565   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1566 
1567   Level: beginner
1568 
1569 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1570 @*/
1571 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1572 {
1573   DM_Plex       *mesh = (DM_Plex*) dm->data;
1574   PetscInt       pStart, pEnd;
1575   PetscInt       dof, off, c;
1576   PetscErrorCode ierr;
1577 
1578   PetscFunctionBegin;
1579   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1580   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1581   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1582   if (dof) PetscValidPointer(support, 3);
1583   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1584   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);
1585   for (c = 0; c < dof; ++c) {
1586     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);
1587     mesh->supports[off+c] = support[c];
1588   }
1589   PetscFunctionReturn(0);
1590 }
1591 
1592 #undef __FUNCT__
1593 #define __FUNCT__ "DMPlexInsertSupport"
1594 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1595 {
1596   DM_Plex       *mesh = (DM_Plex*) dm->data;
1597   PetscInt       pStart, pEnd;
1598   PetscInt       dof, off;
1599   PetscErrorCode ierr;
1600 
1601   PetscFunctionBegin;
1602   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1603   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1604   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1605   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1606   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);
1607   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);
1608   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);
1609   mesh->supports[off+supportPos] = supportPoint;
1610   PetscFunctionReturn(0);
1611 }
1612 
1613 #undef __FUNCT__
1614 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1615 /*@C
1616   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1617 
1618   Not collective
1619 
1620   Input Parameters:
1621 + mesh - The DMPlex
1622 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1623 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1624 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1625 
1626   Output Parameters:
1627 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1628 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1629 
1630   Note:
1631   If using internal storage (points is NULL on input), each call overwrites the last output.
1632 
1633   Level: beginner
1634 
1635 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1636 @*/
1637 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1638 {
1639   DM_Plex        *mesh = (DM_Plex*) dm->data;
1640   PetscInt       *closure, *fifo;
1641   const PetscInt *tmp = NULL, *tmpO = NULL;
1642   PetscInt        tmpSize, t;
1643   PetscInt        depth       = 0, maxSize;
1644   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1645   PetscErrorCode  ierr;
1646 
1647   PetscFunctionBegin;
1648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1649   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1650   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1651   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1652   if (*points) {
1653     closure = *points;
1654   } else {
1655     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1656   }
1657   closure[0] = p; closure[1] = 0;
1658   /* This is only 1-level */
1659   if (useCone) {
1660     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1661     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1662     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1663   } else {
1664     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1665     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1666   }
1667   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1668     const PetscInt cp = tmp[t];
1669     const PetscInt co = tmpO ? tmpO[t] : 0;
1670 
1671     closure[closureSize]   = cp;
1672     closure[closureSize+1] = co;
1673     fifo[fifoSize]         = cp;
1674     fifo[fifoSize+1]       = co;
1675   }
1676   while (fifoSize - fifoStart) {
1677     const PetscInt q   = fifo[fifoStart];
1678     const PetscInt o   = fifo[fifoStart+1];
1679     const PetscInt rev = o >= 0 ? 0 : 1;
1680     const PetscInt off = rev ? -(o+1) : o;
1681 
1682     if (useCone) {
1683       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1684       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1685       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1686     } else {
1687       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1688       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1689       tmpO = NULL;
1690     }
1691     for (t = 0; t < tmpSize; ++t) {
1692       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1693       const PetscInt cp = tmp[i];
1694       /* Must propogate orientation */
1695       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1696       PetscInt       c;
1697 
1698       /* Check for duplicate */
1699       for (c = 0; c < closureSize; c += 2) {
1700         if (closure[c] == cp) break;
1701       }
1702       if (c == closureSize) {
1703         closure[closureSize]   = cp;
1704         closure[closureSize+1] = co;
1705         fifo[fifoSize]         = cp;
1706         fifo[fifoSize+1]       = co;
1707         closureSize           += 2;
1708         fifoSize              += 2;
1709       }
1710     }
1711     fifoStart += 2;
1712   }
1713   if (numPoints) *numPoints = closureSize/2;
1714   if (points)    *points    = closure;
1715   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1716   PetscFunctionReturn(0);
1717 }
1718 
1719 #undef __FUNCT__
1720 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1721 /*@C
1722   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1723 
1724   Not collective
1725 
1726   Input Parameters:
1727 + mesh - The DMPlex
1728 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1729 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1730 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1731 
1732   Output Parameters:
1733 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1734 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1735 
1736   Note:
1737   If not using internal storage (points is not NULL on input), this call is unnecessary
1738 
1739   Level: beginner
1740 
1741 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1742 @*/
1743 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1744 {
1745   PetscErrorCode ierr;
1746 
1747   PetscFunctionBegin;
1748   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1749   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1750   PetscFunctionReturn(0);
1751 }
1752 
1753 #undef __FUNCT__
1754 #define __FUNCT__ "DMPlexGetMaxSizes"
1755 /*@
1756   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1757 
1758   Not collective
1759 
1760   Input Parameter:
1761 . mesh - The DMPlex
1762 
1763   Output Parameters:
1764 + maxConeSize - The maximum number of in-edges
1765 - maxSupportSize - The maximum number of out-edges
1766 
1767   Level: beginner
1768 
1769 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1770 @*/
1771 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1772 {
1773   DM_Plex *mesh = (DM_Plex*) dm->data;
1774 
1775   PetscFunctionBegin;
1776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1777   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1778   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1779   PetscFunctionReturn(0);
1780 }
1781 
1782 #undef __FUNCT__
1783 #define __FUNCT__ "DMSetUp_Plex"
1784 PetscErrorCode DMSetUp_Plex(DM dm)
1785 {
1786   DM_Plex       *mesh = (DM_Plex*) dm->data;
1787   PetscInt       size;
1788   PetscErrorCode ierr;
1789 
1790   PetscFunctionBegin;
1791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1792   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1793   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1794   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1795   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1796   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1797   if (mesh->maxSupportSize) {
1798     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1799     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1800     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1801   }
1802   PetscFunctionReturn(0);
1803 }
1804 
1805 #undef __FUNCT__
1806 #define __FUNCT__ "DMCreateSubDM_Plex"
1807 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1808 {
1809   PetscSection   section, sectionGlobal;
1810   PetscInt      *subIndices;
1811   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1812   PetscErrorCode ierr;
1813 
1814   PetscFunctionBegin;
1815   if (!numFields) PetscFunctionReturn(0);
1816   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1817   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1818   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1819   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1820   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1821   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1822   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1823   for (p = pStart; p < pEnd; ++p) {
1824     PetscInt gdof;
1825 
1826     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1827     if (gdof > 0) {
1828       for (f = 0; f < numFields; ++f) {
1829         PetscInt fdof, fcdof;
1830 
1831         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1832         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1833         subSize += fdof-fcdof;
1834       }
1835     }
1836   }
1837   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1838   for (p = pStart; p < pEnd; ++p) {
1839     PetscInt gdof, goff;
1840 
1841     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1842     if (gdof > 0) {
1843       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1844       for (f = 0; f < numFields; ++f) {
1845         PetscInt fdof, fcdof, fc, f2, poff = 0;
1846 
1847         /* Can get rid of this loop by storing field information in the global section */
1848         for (f2 = 0; f2 < fields[f]; ++f2) {
1849           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1850           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1851           poff += fdof-fcdof;
1852         }
1853         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1854         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1855         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1856           subIndices[subOff] = goff+poff+fc;
1857         }
1858       }
1859     }
1860   }
1861   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1862   if (subdm) {
1863     PetscSection subsection;
1864     PetscBool    haveNull = PETSC_FALSE;
1865     PetscInt     f, nf = 0;
1866 
1867     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1868     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1869     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1870     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1871     for (f = 0; f < numFields; ++f) {
1872       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1873       if ((*subdm)->nullspaceConstructors[f]) {
1874         haveNull = PETSC_TRUE;
1875         nf       = f;
1876       }
1877     }
1878     if (haveNull) {
1879       MatNullSpace nullSpace;
1880 
1881       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1882       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1883       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1884     }
1885     if (dm->fields) {
1886       if (nF != dm->numFields) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1887       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1888       for (f = 0; f < numFields; ++f) {
1889         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1890       }
1891       if (numFields == 1) {
1892         MatNullSpace space;
1893         Mat          pmat;
1894 
1895         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1896         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1897         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1898         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1899         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1900         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1901       }
1902     }
1903   }
1904   PetscFunctionReturn(0);
1905 }
1906 
1907 #undef __FUNCT__
1908 #define __FUNCT__ "DMPlexSymmetrize"
1909 /*@
1910   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1911 
1912   Not collective
1913 
1914   Input Parameter:
1915 . mesh - The DMPlex
1916 
1917   Output Parameter:
1918 
1919   Note:
1920   This should be called after all calls to DMPlexSetCone()
1921 
1922   Level: beginner
1923 
1924 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1925 @*/
1926 PetscErrorCode DMPlexSymmetrize(DM dm)
1927 {
1928   DM_Plex       *mesh = (DM_Plex*) dm->data;
1929   PetscInt      *offsets;
1930   PetscInt       supportSize;
1931   PetscInt       pStart, pEnd, p;
1932   PetscErrorCode ierr;
1933 
1934   PetscFunctionBegin;
1935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1936   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1937   /* Calculate support sizes */
1938   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1939   for (p = pStart; p < pEnd; ++p) {
1940     PetscInt dof, off, c;
1941 
1942     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1943     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1944     for (c = off; c < off+dof; ++c) {
1945       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1946     }
1947   }
1948   for (p = pStart; p < pEnd; ++p) {
1949     PetscInt dof;
1950 
1951     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1952 
1953     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1954   }
1955   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1956   /* Calculate supports */
1957   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1958   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1959   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1960   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1961   for (p = pStart; p < pEnd; ++p) {
1962     PetscInt dof, off, c;
1963 
1964     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1965     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1966     for (c = off; c < off+dof; ++c) {
1967       const PetscInt q = mesh->cones[c];
1968       PetscInt       offS;
1969 
1970       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1971 
1972       mesh->supports[offS+offsets[q]] = p;
1973       ++offsets[q];
1974     }
1975   }
1976   ierr = PetscFree(offsets);CHKERRQ(ierr);
1977   PetscFunctionReturn(0);
1978 }
1979 
1980 #undef __FUNCT__
1981 #define __FUNCT__ "DMPlexSetDepth_Private"
1982 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1983 {
1984   PetscInt       d;
1985   PetscErrorCode ierr;
1986 
1987   PetscFunctionBegin;
1988   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1989   if (d < 0) {
1990     /* We are guaranteed that the point has a cone since the depth was not yet set */
1991     const PetscInt *cone = NULL;
1992     PetscInt        dCone;
1993 
1994     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1995     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1996     d    = dCone+1;
1997     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1998   }
1999   *depth = d;
2000   PetscFunctionReturn(0);
2001 }
2002 
2003 #undef __FUNCT__
2004 #define __FUNCT__ "DMPlexStratify"
2005 /*@
2006   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2007   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2008   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2009   the DAG.
2010 
2011   Not collective
2012 
2013   Input Parameter:
2014 . mesh - The DMPlex
2015 
2016   Output Parameter:
2017 
2018   Notes:
2019   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2020   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2021 
2022   This should be called after all calls to DMPlexSymmetrize()
2023 
2024   Level: beginner
2025 
2026 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2027 @*/
2028 PetscErrorCode DMPlexStratify(DM dm)
2029 {
2030   DM_Plex       *mesh = (DM_Plex*) dm->data;
2031   PetscInt       pStart, pEnd, p;
2032   PetscInt       numRoots = 0, numLeaves = 0;
2033   PetscErrorCode ierr;
2034 
2035   PetscFunctionBegin;
2036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2037   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2038   /* Calculate depth */
2039   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2040   /* Initialize roots and count leaves */
2041   for (p = pStart; p < pEnd; ++p) {
2042     PetscInt coneSize, supportSize;
2043 
2044     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2045     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2046     if (!coneSize && supportSize) {
2047       ++numRoots;
2048       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2049     } else if (!supportSize && coneSize) {
2050       ++numLeaves;
2051     } else if (!supportSize && !coneSize) {
2052       /* Isolated points */
2053       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2054     }
2055   }
2056   if (numRoots + numLeaves == (pEnd - pStart)) {
2057     for (p = pStart; p < pEnd; ++p) {
2058       PetscInt coneSize, supportSize;
2059 
2060       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2061       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2062       if (!supportSize && coneSize) {
2063         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2064       }
2065     }
2066   } else {
2067     /* This might be slow since lookup is not fast */
2068     for (p = pStart; p < pEnd; ++p) {
2069       PetscInt depth;
2070 
2071       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2072     }
2073   }
2074   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2075   PetscFunctionReturn(0);
2076 }
2077 
2078 #undef __FUNCT__
2079 #define __FUNCT__ "DMPlexGetJoin"
2080 /*@C
2081   DMPlexGetJoin - Get an array for the join of the set of points
2082 
2083   Not Collective
2084 
2085   Input Parameters:
2086 + dm - The DMPlex object
2087 . numPoints - The number of input points for the join
2088 - points - The input points
2089 
2090   Output Parameters:
2091 + numCoveredPoints - The number of points in the join
2092 - coveredPoints - The points in the join
2093 
2094   Level: intermediate
2095 
2096   Note: Currently, this is restricted to a single level join
2097 
2098 .keywords: mesh
2099 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2100 @*/
2101 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2102 {
2103   DM_Plex       *mesh = (DM_Plex*) dm->data;
2104   PetscInt      *join[2];
2105   PetscInt       joinSize, i = 0;
2106   PetscInt       dof, off, p, c, m;
2107   PetscErrorCode ierr;
2108 
2109   PetscFunctionBegin;
2110   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2111   PetscValidPointer(points, 2);
2112   PetscValidPointer(numCoveredPoints, 3);
2113   PetscValidPointer(coveredPoints, 4);
2114   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2115   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2116   /* Copy in support of first point */
2117   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2118   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2119   for (joinSize = 0; joinSize < dof; ++joinSize) {
2120     join[i][joinSize] = mesh->supports[off+joinSize];
2121   }
2122   /* Check each successive support */
2123   for (p = 1; p < numPoints; ++p) {
2124     PetscInt newJoinSize = 0;
2125 
2126     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2127     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2128     for (c = 0; c < dof; ++c) {
2129       const PetscInt point = mesh->supports[off+c];
2130 
2131       for (m = 0; m < joinSize; ++m) {
2132         if (point == join[i][m]) {
2133           join[1-i][newJoinSize++] = point;
2134           break;
2135         }
2136       }
2137     }
2138     joinSize = newJoinSize;
2139     i        = 1-i;
2140   }
2141   *numCoveredPoints = joinSize;
2142   *coveredPoints    = join[i];
2143   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2144   PetscFunctionReturn(0);
2145 }
2146 
2147 #undef __FUNCT__
2148 #define __FUNCT__ "DMPlexRestoreJoin"
2149 /*@C
2150   DMPlexRestoreJoin - Restore an array for the join of the set of points
2151 
2152   Not Collective
2153 
2154   Input Parameters:
2155 + dm - The DMPlex object
2156 . numPoints - The number of input points for the join
2157 - points - The input points
2158 
2159   Output Parameters:
2160 + numCoveredPoints - The number of points in the join
2161 - coveredPoints - The points in the join
2162 
2163   Level: intermediate
2164 
2165 .keywords: mesh
2166 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2167 @*/
2168 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2169 {
2170   PetscErrorCode ierr;
2171 
2172   PetscFunctionBegin;
2173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2174   PetscValidPointer(coveredPoints, 4);
2175   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2176   PetscFunctionReturn(0);
2177 }
2178 
2179 #undef __FUNCT__
2180 #define __FUNCT__ "DMPlexGetFullJoin"
2181 /*@C
2182   DMPlexGetFullJoin - Get an array for the join of the set of points
2183 
2184   Not Collective
2185 
2186   Input Parameters:
2187 + dm - The DMPlex object
2188 . numPoints - The number of input points for the join
2189 - points - The input points
2190 
2191   Output Parameters:
2192 + numCoveredPoints - The number of points in the join
2193 - coveredPoints - The points in the join
2194 
2195   Level: intermediate
2196 
2197 .keywords: mesh
2198 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2199 @*/
2200 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2201 {
2202   DM_Plex       *mesh = (DM_Plex*) dm->data;
2203   PetscInt      *offsets, **closures;
2204   PetscInt      *join[2];
2205   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2206   PetscInt       p, d, c, m;
2207   PetscErrorCode ierr;
2208 
2209   PetscFunctionBegin;
2210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2211   PetscValidPointer(points, 2);
2212   PetscValidPointer(numCoveredPoints, 3);
2213   PetscValidPointer(coveredPoints, 4);
2214 
2215   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2216   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2217   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2218   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2219   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2220   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2221   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2222 
2223   for (p = 0; p < numPoints; ++p) {
2224     PetscInt closureSize;
2225 
2226     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2227 
2228     offsets[p*(depth+2)+0] = 0;
2229     for (d = 0; d < depth+1; ++d) {
2230       PetscInt pStart, pEnd, i;
2231 
2232       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2233       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2234         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2235           offsets[p*(depth+2)+d+1] = i;
2236           break;
2237         }
2238       }
2239       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2240     }
2241     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);
2242   }
2243   for (d = 0; d < depth+1; ++d) {
2244     PetscInt dof;
2245 
2246     /* Copy in support of first point */
2247     dof = offsets[d+1] - offsets[d];
2248     for (joinSize = 0; joinSize < dof; ++joinSize) {
2249       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2250     }
2251     /* Check each successive cone */
2252     for (p = 1; p < numPoints && joinSize; ++p) {
2253       PetscInt newJoinSize = 0;
2254 
2255       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2256       for (c = 0; c < dof; ++c) {
2257         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2258 
2259         for (m = 0; m < joinSize; ++m) {
2260           if (point == join[i][m]) {
2261             join[1-i][newJoinSize++] = point;
2262             break;
2263           }
2264         }
2265       }
2266       joinSize = newJoinSize;
2267       i        = 1-i;
2268     }
2269     if (joinSize) break;
2270   }
2271   *numCoveredPoints = joinSize;
2272   *coveredPoints    = join[i];
2273   for (p = 0; p < numPoints; ++p) {
2274     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2275   }
2276   ierr = PetscFree(closures);CHKERRQ(ierr);
2277   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2278   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2279   PetscFunctionReturn(0);
2280 }
2281 
2282 #undef __FUNCT__
2283 #define __FUNCT__ "DMPlexGetMeet"
2284 /*@C
2285   DMPlexGetMeet - Get an array for the meet of the set of points
2286 
2287   Not Collective
2288 
2289   Input Parameters:
2290 + dm - The DMPlex object
2291 . numPoints - The number of input points for the meet
2292 - points - The input points
2293 
2294   Output Parameters:
2295 + numCoveredPoints - The number of points in the meet
2296 - coveredPoints - The points in the meet
2297 
2298   Level: intermediate
2299 
2300   Note: Currently, this is restricted to a single level meet
2301 
2302 .keywords: mesh
2303 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2304 @*/
2305 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2306 {
2307   DM_Plex       *mesh = (DM_Plex*) dm->data;
2308   PetscInt      *meet[2];
2309   PetscInt       meetSize, i = 0;
2310   PetscInt       dof, off, p, c, m;
2311   PetscErrorCode ierr;
2312 
2313   PetscFunctionBegin;
2314   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2315   PetscValidPointer(points, 2);
2316   PetscValidPointer(numCoveringPoints, 3);
2317   PetscValidPointer(coveringPoints, 4);
2318   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2319   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2320   /* Copy in cone of first point */
2321   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2322   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2323   for (meetSize = 0; meetSize < dof; ++meetSize) {
2324     meet[i][meetSize] = mesh->cones[off+meetSize];
2325   }
2326   /* Check each successive cone */
2327   for (p = 1; p < numPoints; ++p) {
2328     PetscInt newMeetSize = 0;
2329 
2330     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2331     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2332     for (c = 0; c < dof; ++c) {
2333       const PetscInt point = mesh->cones[off+c];
2334 
2335       for (m = 0; m < meetSize; ++m) {
2336         if (point == meet[i][m]) {
2337           meet[1-i][newMeetSize++] = point;
2338           break;
2339         }
2340       }
2341     }
2342     meetSize = newMeetSize;
2343     i        = 1-i;
2344   }
2345   *numCoveringPoints = meetSize;
2346   *coveringPoints    = meet[i];
2347   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2348   PetscFunctionReturn(0);
2349 }
2350 
2351 #undef __FUNCT__
2352 #define __FUNCT__ "DMPlexRestoreMeet"
2353 /*@C
2354   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2355 
2356   Not Collective
2357 
2358   Input Parameters:
2359 + dm - The DMPlex object
2360 . numPoints - The number of input points for the meet
2361 - points - The input points
2362 
2363   Output Parameters:
2364 + numCoveredPoints - The number of points in the meet
2365 - coveredPoints - The points in the meet
2366 
2367   Level: intermediate
2368 
2369 .keywords: mesh
2370 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2371 @*/
2372 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2373 {
2374   PetscErrorCode ierr;
2375 
2376   PetscFunctionBegin;
2377   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2378   PetscValidPointer(coveredPoints, 4);
2379   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2380   PetscFunctionReturn(0);
2381 }
2382 
2383 #undef __FUNCT__
2384 #define __FUNCT__ "DMPlexGetFullMeet"
2385 /*@C
2386   DMPlexGetFullMeet - Get an array for the meet of the set of points
2387 
2388   Not Collective
2389 
2390   Input Parameters:
2391 + dm - The DMPlex object
2392 . numPoints - The number of input points for the meet
2393 - points - The input points
2394 
2395   Output Parameters:
2396 + numCoveredPoints - The number of points in the meet
2397 - coveredPoints - The points in the meet
2398 
2399   Level: intermediate
2400 
2401 .keywords: mesh
2402 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2403 @*/
2404 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2405 {
2406   DM_Plex       *mesh = (DM_Plex*) dm->data;
2407   PetscInt      *offsets, **closures;
2408   PetscInt      *meet[2];
2409   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2410   PetscInt       p, h, c, m;
2411   PetscErrorCode ierr;
2412 
2413   PetscFunctionBegin;
2414   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2415   PetscValidPointer(points, 2);
2416   PetscValidPointer(numCoveredPoints, 3);
2417   PetscValidPointer(coveredPoints, 4);
2418 
2419   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2420   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2421   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2422   maxSize = PetscPowInt(mesh->maxConeSize,height);
2423   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2424   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2425 
2426   for (p = 0; p < numPoints; ++p) {
2427     PetscInt closureSize;
2428 
2429     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2430 
2431     offsets[p*(height+2)+0] = 0;
2432     for (h = 0; h < height+1; ++h) {
2433       PetscInt pStart, pEnd, i;
2434 
2435       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2436       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2437         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2438           offsets[p*(height+2)+h+1] = i;
2439           break;
2440         }
2441       }
2442       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2443     }
2444     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);
2445   }
2446   for (h = 0; h < height+1; ++h) {
2447     PetscInt dof;
2448 
2449     /* Copy in cone of first point */
2450     dof = offsets[h+1] - offsets[h];
2451     for (meetSize = 0; meetSize < dof; ++meetSize) {
2452       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2453     }
2454     /* Check each successive cone */
2455     for (p = 1; p < numPoints && meetSize; ++p) {
2456       PetscInt newMeetSize = 0;
2457 
2458       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2459       for (c = 0; c < dof; ++c) {
2460         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2461 
2462         for (m = 0; m < meetSize; ++m) {
2463           if (point == meet[i][m]) {
2464             meet[1-i][newMeetSize++] = point;
2465             break;
2466           }
2467         }
2468       }
2469       meetSize = newMeetSize;
2470       i        = 1-i;
2471     }
2472     if (meetSize) break;
2473   }
2474   *numCoveredPoints = meetSize;
2475   *coveredPoints    = meet[i];
2476   for (p = 0; p < numPoints; ++p) {
2477     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2478   }
2479   ierr = PetscFree(closures);CHKERRQ(ierr);
2480   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2481   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2482   PetscFunctionReturn(0);
2483 }
2484 
2485 #undef __FUNCT__
2486 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2487 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2488 {
2489   MPI_Comm       comm;
2490   PetscErrorCode ierr;
2491 
2492   PetscFunctionBegin;
2493   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2494   PetscValidPointer(numFaceVertices,3);
2495   switch (cellDim) {
2496   case 0:
2497     *numFaceVertices = 0;
2498     break;
2499   case 1:
2500     *numFaceVertices = 1;
2501     break;
2502   case 2:
2503     switch (numCorners) {
2504     case 3: /* triangle */
2505       *numFaceVertices = 2; /* Edge has 2 vertices */
2506       break;
2507     case 4: /* quadrilateral */
2508       *numFaceVertices = 2; /* Edge has 2 vertices */
2509       break;
2510     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2511       *numFaceVertices = 3; /* Edge has 3 vertices */
2512       break;
2513     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2514       *numFaceVertices = 3; /* Edge has 3 vertices */
2515       break;
2516     default:
2517       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2518     }
2519     break;
2520   case 3:
2521     switch (numCorners) {
2522     case 4: /* tetradehdron */
2523       *numFaceVertices = 3; /* Face has 3 vertices */
2524       break;
2525     case 6: /* tet cohesive cells */
2526       *numFaceVertices = 4; /* Face has 4 vertices */
2527       break;
2528     case 8: /* hexahedron */
2529       *numFaceVertices = 4; /* Face has 4 vertices */
2530       break;
2531     case 9: /* tet cohesive Lagrange cells */
2532       *numFaceVertices = 6; /* Face has 6 vertices */
2533       break;
2534     case 10: /* quadratic tetrahedron */
2535       *numFaceVertices = 6; /* Face has 6 vertices */
2536       break;
2537     case 12: /* hex cohesive Lagrange cells */
2538       *numFaceVertices = 6; /* Face has 6 vertices */
2539       break;
2540     case 18: /* quadratic tet cohesive Lagrange cells */
2541       *numFaceVertices = 6; /* Face has 6 vertices */
2542       break;
2543     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2544       *numFaceVertices = 9; /* Face has 9 vertices */
2545       break;
2546     default:
2547       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2548     }
2549     break;
2550   default:
2551     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2552   }
2553   PetscFunctionReturn(0);
2554 }
2555 
2556 #undef __FUNCT__
2557 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2558 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2559 {
2560   const PetscInt maxFaceCases = 30;
2561   PetscInt       numFaceCases = 0;
2562   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2563   PetscInt      *off, *adj;
2564   PetscInt      *neighborCells, *tmpClosure;
2565   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2566   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2567   PetscErrorCode ierr;
2568 
2569   PetscFunctionBegin;
2570   /* For parallel partitioning, I think you have to communicate supports */
2571   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2572   cellDim = dim - cellHeight;
2573   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2574   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2575   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2576   if (cEnd - cStart == 0) {
2577     if (numVertices) *numVertices = 0;
2578     if (offsets)   *offsets   = NULL;
2579     if (adjacency) *adjacency = NULL;
2580     PetscFunctionReturn(0);
2581   }
2582   numCells  = cEnd - cStart;
2583   faceDepth = depth - cellHeight;
2584   /* Setup face recognition */
2585   if (faceDepth == 1) {
2586     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 */
2587 
2588     for (c = cStart; c < cEnd; ++c) {
2589       PetscInt corners;
2590 
2591       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2592       if (!cornersSeen[corners]) {
2593         PetscInt nFV;
2594 
2595         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2596         cornersSeen[corners] = 1;
2597 
2598         ierr = DMPlexGetNumFaceVertices_Internal(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2599 
2600         numFaceVertices[numFaceCases++] = nFV;
2601       }
2602     }
2603   }
2604   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2605   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2606   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2607   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2608   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2609   /* Count neighboring cells */
2610   for (cell = cStart; cell < cEnd; ++cell) {
2611     PetscInt numNeighbors = maxNeighbors, n;
2612 
2613     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2614     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2615     for (n = 0; n < numNeighbors; ++n) {
2616       PetscInt        cellPair[2];
2617       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2618       PetscInt        meetSize = 0;
2619       const PetscInt *meet    = NULL;
2620 
2621       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2622       if (cellPair[0] == cellPair[1]) continue;
2623       if (!found) {
2624         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2625         if (meetSize) {
2626           PetscInt f;
2627 
2628           for (f = 0; f < numFaceCases; ++f) {
2629             if (numFaceVertices[f] == meetSize) {
2630               found = PETSC_TRUE;
2631               break;
2632             }
2633           }
2634         }
2635         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2636       }
2637       if (found) ++off[cell-cStart+1];
2638     }
2639   }
2640   /* Prefix sum */
2641   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2642 
2643   if (adjacency) {
2644     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2645     /* Get neighboring cells */
2646     for (cell = cStart; cell < cEnd; ++cell) {
2647       PetscInt numNeighbors = maxNeighbors, n;
2648       PetscInt cellOffset   = 0;
2649 
2650       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2651       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2652       for (n = 0; n < numNeighbors; ++n) {
2653         PetscInt        cellPair[2];
2654         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2655         PetscInt        meetSize = 0;
2656         const PetscInt *meet    = NULL;
2657 
2658         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2659         if (cellPair[0] == cellPair[1]) continue;
2660         if (!found) {
2661           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2662           if (meetSize) {
2663             PetscInt f;
2664 
2665             for (f = 0; f < numFaceCases; ++f) {
2666               if (numFaceVertices[f] == meetSize) {
2667                 found = PETSC_TRUE;
2668                 break;
2669               }
2670             }
2671           }
2672           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2673         }
2674         if (found) {
2675           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2676           ++cellOffset;
2677         }
2678       }
2679     }
2680   }
2681   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2682   if (numVertices) *numVertices = numCells;
2683   if (offsets)   *offsets   = off;
2684   if (adjacency) *adjacency = adj;
2685   PetscFunctionReturn(0);
2686 }
2687 
2688 #if defined(PETSC_HAVE_CHACO)
2689 #if defined(PETSC_HAVE_UNISTD_H)
2690 #include <unistd.h>
2691 #endif
2692 /* Chaco does not have an include file */
2693 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2694                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2695                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2696                        int mesh_dims[3], double *goal, int global_method, int local_method,
2697                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2698 
2699 extern int FREE_GRAPH;
2700 
2701 #undef __FUNCT__
2702 #define __FUNCT__ "DMPlexPartition_Chaco"
2703 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2704 {
2705   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2706   MPI_Comm       comm;
2707   int            nvtxs          = numVertices; /* number of vertices in full graph */
2708   int           *vwgts          = NULL;   /* weights for all vertices */
2709   float         *ewgts          = NULL;   /* weights for all edges */
2710   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2711   char          *outassignname  = NULL;   /*  name of assignment output file */
2712   char          *outfilename    = NULL;   /* output file name */
2713   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2714   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2715   int            mesh_dims[3];            /* dimensions of mesh of processors */
2716   double        *goal          = NULL;    /* desired set sizes for each set */
2717   int            global_method = 1;       /* global partitioning algorithm */
2718   int            local_method  = 1;       /* local partitioning algorithm */
2719   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2720   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2721   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2722   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2723   long           seed          = 123636512; /* for random graph mutations */
2724   short int     *assignment;              /* Output partition */
2725   int            fd_stdout, fd_pipe[2];
2726   PetscInt      *points;
2727   PetscMPIInt    commSize;
2728   int            i, v, p;
2729   PetscErrorCode ierr;
2730 
2731   PetscFunctionBegin;
2732   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2733   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2734   if (!numVertices) {
2735     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2736     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2737     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2738     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2739     PetscFunctionReturn(0);
2740   }
2741   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2742   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2743 
2744   if (global_method == INERTIAL_METHOD) {
2745     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2746     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2747   }
2748   mesh_dims[0] = commSize;
2749   mesh_dims[1] = 1;
2750   mesh_dims[2] = 1;
2751   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2752   /* Chaco outputs to stdout. We redirect this to a buffer. */
2753   /* TODO: check error codes for UNIX calls */
2754 #if defined(PETSC_HAVE_UNISTD_H)
2755   {
2756     int piperet;
2757     piperet = pipe(fd_pipe);
2758     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2759     fd_stdout = dup(1);
2760     close(1);
2761     dup2(fd_pipe[1], 1);
2762   }
2763 #endif
2764   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2765                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2766                    vmax, ndims, eigtol, seed);
2767 #if defined(PETSC_HAVE_UNISTD_H)
2768   {
2769     char msgLog[10000];
2770     int  count;
2771 
2772     fflush(stdout);
2773     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2774     if (count < 0) count = 0;
2775     msgLog[count] = 0;
2776     close(1);
2777     dup2(fd_stdout, 1);
2778     close(fd_stdout);
2779     close(fd_pipe[0]);
2780     close(fd_pipe[1]);
2781     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2782   }
2783 #endif
2784   /* Convert to PetscSection+IS */
2785   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2786   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2787   for (v = 0; v < nvtxs; ++v) {
2788     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2789   }
2790   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2791   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2792   for (p = 0, i = 0; p < commSize; ++p) {
2793     for (v = 0; v < nvtxs; ++v) {
2794       if (assignment[v] == p) points[i++] = v;
2795     }
2796   }
2797   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2798   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2799   if (global_method == INERTIAL_METHOD) {
2800     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2801   }
2802   ierr = PetscFree(assignment);CHKERRQ(ierr);
2803   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2804   PetscFunctionReturn(0);
2805 }
2806 #endif
2807 
2808 #if defined(PETSC_HAVE_PARMETIS)
2809 #undef __FUNCT__
2810 #define __FUNCT__ "DMPlexPartition_ParMetis"
2811 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2812 {
2813   PetscFunctionBegin;
2814   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2815   PetscFunctionReturn(0);
2816 }
2817 #endif
2818 
2819 #undef __FUNCT__
2820 #define __FUNCT__ "DMPlexEnlargePartition"
2821 /* Expand the partition by BFS on the adjacency graph */
2822 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2823 {
2824   PetscHashI      h;
2825   const PetscInt *points;
2826   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2827   PetscInt        pStart, pEnd, part, q;
2828   PetscErrorCode  ierr;
2829 
2830   PetscFunctionBegin;
2831   PetscHashICreate(h);
2832   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2833   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2834   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2835   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2836   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2837   for (part = pStart; part < pEnd; ++part) {
2838     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2839 
2840     PetscHashIClear(h);
2841     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2842     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2843     /* Add all existing points to h */
2844     for (p = 0; p < numPoints; ++p) {
2845       const PetscInt point = points[off+p];
2846       PetscHashIAdd(h, point, 1);
2847     }
2848     PetscHashISize(h, nP);
2849     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2850     /* Add all points in next BFS level */
2851     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2852     for (p = 0; p < numPoints; ++p) {
2853       const PetscInt point = points[off+p];
2854       PetscInt       s     = start[point], e = start[point+1], a;
2855 
2856       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2857     }
2858     PetscHashISize(h, numNewPoints);
2859     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2860     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2861     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2862     totPoints += numNewPoints;
2863   }
2864   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2865   PetscHashIDestroy(h);
2866   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2867   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2868   for (part = pStart, q = 0; part < pEnd; ++part) {
2869     PetscInt numPoints, p;
2870 
2871     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2872     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2873     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2874   }
2875   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2876   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2877   PetscFunctionReturn(0);
2878 }
2879 
2880 #undef __FUNCT__
2881 #define __FUNCT__ "DMPlexCreatePartition"
2882 /*
2883   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2884 
2885   Collective on DM
2886 
2887   Input Parameters:
2888   + dm - The DM
2889   . height - The height for points in the partition
2890   - enlarge - Expand each partition with neighbors
2891 
2892   Output Parameters:
2893   + partSection - The PetscSection giving the division of points by partition
2894   . partition - The list of points by partition
2895   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2896   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2897 
2898   Level: developer
2899 
2900 .seealso DMPlexDistribute()
2901 */
2902 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2903 {
2904   PetscMPIInt    size;
2905   PetscErrorCode ierr;
2906 
2907   PetscFunctionBegin;
2908   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2909 
2910   *origPartSection = NULL;
2911   *origPartition   = NULL;
2912   if (size == 1) {
2913     PetscInt *points;
2914     PetscInt  cStart, cEnd, c;
2915 
2916     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2917     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2918     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2919     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2920     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2921     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2922     for (c = cStart; c < cEnd; ++c) points[c] = c;
2923     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2924     PetscFunctionReturn(0);
2925   }
2926   if (height == 0) {
2927     PetscInt  numVertices;
2928     PetscInt *start     = NULL;
2929     PetscInt *adjacency = NULL;
2930 
2931     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2932     if (1) {
2933 #if defined(PETSC_HAVE_CHACO)
2934       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2935 #endif
2936     } else {
2937 #if defined(PETSC_HAVE_PARMETIS)
2938       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2939 #endif
2940     }
2941     if (enlarge) {
2942       *origPartSection = *partSection;
2943       *origPartition   = *partition;
2944 
2945       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2946     }
2947     ierr = PetscFree(start);CHKERRQ(ierr);
2948     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2949 # if 0
2950   } else if (height == 1) {
2951     /* Build the dual graph for faces and partition the hypergraph */
2952     PetscInt numEdges;
2953 
2954     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2955     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2956     destroyCSR(numEdges, start, adjacency);
2957 #endif
2958   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2959   PetscFunctionReturn(0);
2960 }
2961 
2962 #undef __FUNCT__
2963 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2964 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2965 {
2966   /* const PetscInt  height = 0; */
2967   const PetscInt *partArray;
2968   PetscInt       *allPoints, *partPoints = NULL;
2969   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2970   PetscErrorCode  ierr;
2971 
2972   PetscFunctionBegin;
2973   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2974   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2975   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2976   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2977   for (rank = rStart; rank < rEnd; ++rank) {
2978     PetscInt partSize = 0;
2979     PetscInt numPoints, offset, p;
2980 
2981     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2982     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2983     for (p = 0; p < numPoints; ++p) {
2984       PetscInt  point   = partArray[offset+p], closureSize, c;
2985       PetscInt *closure = NULL;
2986 
2987       /* TODO Include support for height > 0 case */
2988       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2989       /* Merge into existing points */
2990       if (partSize+closureSize > maxPartSize) {
2991         PetscInt *tmpPoints;
2992 
2993         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2994         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2995         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2996         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2997 
2998         partPoints = tmpPoints;
2999       }
3000       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3001       partSize += closureSize;
3002 
3003       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3004       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3005     }
3006     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3007   }
3008   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3009   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3010   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3011 
3012   for (rank = rStart; rank < rEnd; ++rank) {
3013     PetscInt partSize = 0, newOffset;
3014     PetscInt numPoints, offset, p;
3015 
3016     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3017     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3018     for (p = 0; p < numPoints; ++p) {
3019       PetscInt  point   = partArray[offset+p], closureSize, c;
3020       PetscInt *closure = NULL;
3021 
3022       /* TODO Include support for height > 0 case */
3023       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3024       /* Merge into existing points */
3025       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3026       partSize += closureSize;
3027 
3028       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3029       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3030     }
3031     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3032     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3033   }
3034   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3035   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3036   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3037   PetscFunctionReturn(0);
3038 }
3039 
3040 #undef __FUNCT__
3041 #define __FUNCT__ "DMPlexDistributeField"
3042 /*
3043   Input Parameters:
3044 . originalSection
3045 , originalVec
3046 
3047   Output Parameters:
3048 . newSection
3049 . newVec
3050 */
3051 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3052 {
3053   PetscSF        fieldSF;
3054   PetscInt      *remoteOffsets, fieldSize;
3055   PetscScalar   *originalValues, *newValues;
3056   PetscErrorCode ierr;
3057 
3058   PetscFunctionBegin;
3059   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3060 
3061   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3062   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3063   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3064 
3065   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3066   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3067   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3068   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3069   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3070   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3071   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3072   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3073   PetscFunctionReturn(0);
3074 }
3075 
3076 #undef __FUNCT__
3077 #define __FUNCT__ "DMPlexDistribute"
3078 /*@C
3079   DMPlexDistribute - Distributes the mesh and any associated sections.
3080 
3081   Not Collective
3082 
3083   Input Parameter:
3084 + dm  - The original DMPlex object
3085 . partitioner - The partitioning package, or NULL for the default
3086 - overlap - The overlap of partitions, 0 is the default
3087 
3088   Output Parameter:
3089 . parallelMesh - The distributed DMPlex object, or NULL
3090 
3091   Note: If the mesh was not distributed, the return value is NULL
3092 
3093   Level: intermediate
3094 
3095 .keywords: mesh, elements
3096 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3097 @*/
3098 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3099 {
3100   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3101   MPI_Comm               comm;
3102   const PetscInt         height = 0;
3103   PetscInt               dim, numRemoteRanks;
3104   IS                     origCellPart,        cellPart,        part;
3105   PetscSection           origCellPartSection, cellPartSection, partSection;
3106   PetscSFNode           *remoteRanks;
3107   PetscSF                partSF, pointSF, coneSF;
3108   ISLocalToGlobalMapping renumbering;
3109   PetscSection           originalConeSection, newConeSection;
3110   PetscInt              *remoteOffsets;
3111   PetscInt              *cones, *newCones, newConesSize;
3112   PetscBool              flg;
3113   PetscMPIInt            rank, numProcs, p;
3114   PetscErrorCode         ierr;
3115 
3116   PetscFunctionBegin;
3117   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3118   PetscValidPointer(dmParallel,4);
3119 
3120   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3121   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3122   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3123   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3124 
3125   *dmParallel = NULL;
3126   if (numProcs == 1) PetscFunctionReturn(0);
3127 
3128   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3129   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3130   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3131   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3132   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3133   if (!rank) numRemoteRanks = numProcs;
3134   else       numRemoteRanks = 0;
3135   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3136   for (p = 0; p < numRemoteRanks; ++p) {
3137     remoteRanks[p].rank  = p;
3138     remoteRanks[p].index = 0;
3139   }
3140   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3141   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3142   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3143   if (flg) {
3144     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3145     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3146     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3147     if (origCellPart) {
3148       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3149       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3150       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3151     }
3152     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3153   }
3154   /* Close the partition over the mesh */
3155   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3156   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3157   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3158   /* Create new mesh */
3159   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3160   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3161   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3162   pmesh = (DM_Plex*) (*dmParallel)->data;
3163   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3164   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3165   if (flg) {
3166     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3167     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3168     ierr = ISView(part, NULL);CHKERRQ(ierr);
3169     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3170     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3171     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3172   }
3173   /* Distribute cone section */
3174   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3175   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3176   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3177   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3178   {
3179     PetscInt pStart, pEnd, p;
3180 
3181     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3182     for (p = pStart; p < pEnd; ++p) {
3183       PetscInt coneSize;
3184       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3185       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3186     }
3187   }
3188   /* Communicate and renumber cones */
3189   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3190   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3191   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3192   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3193   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3194   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3195   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3196   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3197   if (flg) {
3198     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3199     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3200     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3201     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3202     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3203   }
3204   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3205   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3206   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3207   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3208   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3209   /* Create supports and stratify sieve */
3210   {
3211     PetscInt pStart, pEnd;
3212 
3213     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3214     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3215   }
3216   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3217   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3218   /* Distribute Coordinates */
3219   {
3220     PetscSection originalCoordSection, newCoordSection;
3221     Vec          originalCoordinates, newCoordinates;
3222     const char  *name;
3223 
3224     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3225     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3226     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3227     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3228     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3229     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3230 
3231     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3232     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3233     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3234   }
3235   /* Distribute labels */
3236   {
3237     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3238     PetscInt numLabels = 0, l;
3239 
3240     /* Bcast number of labels */
3241     while (next) {
3242       ++numLabels; next = next->next;
3243     }
3244     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3245     next = mesh->labels;
3246     for (l = 0; l < numLabels; ++l) {
3247       DMLabel         newLabel;
3248       const PetscInt *partArray;
3249       char           *name;
3250       PetscInt       *stratumSizes = NULL, *points = NULL;
3251       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3252       PetscInt        nameSize, s, p;
3253       PetscBool       isdepth;
3254       size_t          len = 0;
3255 
3256       /* Bcast name (could filter for no points) */
3257       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3258       nameSize = len;
3259       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3260       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3261       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3262       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3263       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3264       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3265       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3266       newLabel->name = name;
3267       /* Bcast numStrata (could filter for no points in stratum) */
3268       if (!rank) newLabel->numStrata = next->numStrata;
3269       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3270       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3271                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3272                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3273       /* Bcast stratumValues (could filter for no points in stratum) */
3274       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3275       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3276       /* Find size on each process and Scatter */
3277       if (!rank) {
3278         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3279         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3280         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3281         for (s = 0; s < next->numStrata; ++s) {
3282           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3283             const PetscInt point = next->points[p];
3284             PetscInt       proc;
3285 
3286             for (proc = 0; proc < numProcs; ++proc) {
3287               PetscInt dof, off, pPart;
3288 
3289               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3290               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3291               for (pPart = off; pPart < off+dof; ++pPart) {
3292                 if (partArray[pPart] == point) {
3293                   ++stratumSizes[proc*next->numStrata+s];
3294                   break;
3295                 }
3296               }
3297             }
3298           }
3299         }
3300         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3301       }
3302       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3303       /* Calculate stratumOffsets */
3304       newLabel->stratumOffsets[0] = 0;
3305       for (s = 0; s < newLabel->numStrata; ++s) {
3306         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3307       }
3308       /* Pack points and Scatter */
3309       if (!rank) {
3310         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3311         displs[0] = 0;
3312         for (p = 0; p < numProcs; ++p) {
3313           sendcnts[p] = 0;
3314           for (s = 0; s < next->numStrata; ++s) {
3315             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3316           }
3317           offsets[p]  = displs[p];
3318           displs[p+1] = displs[p] + sendcnts[p];
3319         }
3320         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3321         for (s = 0; s < next->numStrata; ++s) {
3322           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3323             const PetscInt point = next->points[p];
3324             PetscInt       proc;
3325 
3326             for (proc = 0; proc < numProcs; ++proc) {
3327               PetscInt dof, off, pPart;
3328 
3329               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3330               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3331               for (pPart = off; pPart < off+dof; ++pPart) {
3332                 if (partArray[pPart] == point) {
3333                   points[offsets[proc]++] = point;
3334                   break;
3335                 }
3336               }
3337             }
3338           }
3339         }
3340       }
3341       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3342       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3343       ierr = PetscFree(points);CHKERRQ(ierr);
3344       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3345       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3346       /* Renumber points */
3347       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3348       /* Sort points */
3349       for (s = 0; s < newLabel->numStrata; ++s) {
3350         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3351       }
3352       /* Insert into list */
3353       if (newNext) newNext->next = newLabel;
3354       else pmesh->labels = newLabel;
3355       newNext = newLabel;
3356       if (!rank) next = next->next;
3357     }
3358   }
3359   /* Cleanup Partition */
3360   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3361   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3362   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3363   ierr = ISDestroy(&part);CHKERRQ(ierr);
3364   /* Create point SF for parallel mesh */
3365   {
3366     const PetscInt *leaves;
3367     PetscSFNode    *remotePoints, *rowners, *lowners;
3368     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3369     PetscInt        pStart, pEnd;
3370 
3371     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3372     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3373     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3374     for (p=0; p<numRoots; p++) {
3375       rowners[p].rank  = -1;
3376       rowners[p].index = -1;
3377     }
3378     if (origCellPart) {
3379       /* Make sure cells in the original partition are not assigned to other procs */
3380       const PetscInt *origCells;
3381 
3382       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3383       for (p = 0; p < numProcs; ++p) {
3384         PetscInt dof, off, d;
3385 
3386         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3387         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3388         for (d = off; d < off+dof; ++d) {
3389           rowners[origCells[d]].rank = p;
3390         }
3391       }
3392       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3393     }
3394     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3395     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3396 
3397     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3398     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3399     for (p = 0; p < numLeaves; ++p) {
3400       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3401         lowners[p].rank  = rank;
3402         lowners[p].index = leaves ? leaves[p] : p;
3403       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3404         lowners[p].rank  = -2;
3405         lowners[p].index = -2;
3406       }
3407     }
3408     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3409       rowners[p].rank  = -3;
3410       rowners[p].index = -3;
3411     }
3412     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3413     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3414     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3415     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3416     for (p = 0; p < numLeaves; ++p) {
3417       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3418       if (lowners[p].rank != rank) ++numGhostPoints;
3419     }
3420     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3421     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3422     for (p = 0, gp = 0; p < numLeaves; ++p) {
3423       if (lowners[p].rank != rank) {
3424         ghostPoints[gp]        = leaves ? leaves[p] : p;
3425         remotePoints[gp].rank  = lowners[p].rank;
3426         remotePoints[gp].index = lowners[p].index;
3427         ++gp;
3428       }
3429     }
3430     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3431     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3432     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3433   }
3434   /* Cleanup */
3435   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3436   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3437   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3438   PetscFunctionReturn(0);
3439 }
3440 
3441 #undef __FUNCT__
3442 #define __FUNCT__ "DMPlexRenumber_Private"
3443 /*
3444   Reasons to renumber:
3445 
3446   1) Permute points, e.g. bandwidth reduction (Renumber)
3447 
3448     a) Must not mix strata
3449 
3450   2) Shift numbers for point insertion (Shift)
3451 
3452     a) Want operation brken into parts so that insertion can be interleaved
3453 
3454   renumbering - An IS which provides the new numbering
3455 */
3456 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3457 {
3458   PetscFunctionBegin;
3459   PetscFunctionReturn(0);
3460 }
3461 
3462 #undef __FUNCT__
3463 #define __FUNCT__ "DMPlexShiftPoint_Private"
3464 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3465 {
3466   if (depth < 0) return p;
3467   /* Cells    */ if (p < depthEnd[depth])   return p;
3468   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3469   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3470   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3471 }
3472 
3473 #undef __FUNCT__
3474 #define __FUNCT__ "DMPlexShiftSizes_Private"
3475 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3476 {
3477   PetscInt      *depthEnd;
3478   PetscInt       depth = 0, d, pStart, pEnd, p;
3479   PetscErrorCode ierr;
3480 
3481   PetscFunctionBegin;
3482   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3483   if (depth < 0) PetscFunctionReturn(0);
3484   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3485   /* Step 1: Expand chart */
3486   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3487   for (d = 0; d <= depth; ++d) {
3488     pEnd += depthShift[d];
3489     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3490   }
3491   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3492   /* Step 2: Set cone and support sizes */
3493   for (d = 0; d <= depth; ++d) {
3494     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3495     for (p = pStart; p < pEnd; ++p) {
3496       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3497       PetscInt size;
3498 
3499       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3500       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3501       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3502       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3503     }
3504   }
3505   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3506   PetscFunctionReturn(0);
3507 }
3508 
3509 #undef __FUNCT__
3510 #define __FUNCT__ "DMPlexShiftPoints_Private"
3511 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3512 {
3513   PetscInt      *depthEnd, *newpoints;
3514   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3515   PetscErrorCode ierr;
3516 
3517   PetscFunctionBegin;
3518   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3519   if (depth < 0) PetscFunctionReturn(0);
3520   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3521   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3522   for (d = 0; d <= depth; ++d) {
3523     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3524   }
3525   /* Step 5: Set cones and supports */
3526   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3527   for (p = pStart; p < pEnd; ++p) {
3528     const PetscInt *points = NULL, *orientations = NULL;
3529     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3530 
3531     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3532     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3533     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3534     for (i = 0; i < size; ++i) {
3535       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3536     }
3537     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3538     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3539     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3540     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3541     for (i = 0; i < size; ++i) {
3542       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3543     }
3544     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3545   }
3546   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3547   PetscFunctionReturn(0);
3548 }
3549 
3550 #undef __FUNCT__
3551 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3552 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3553 {
3554   PetscSection   coordSection, newCoordSection;
3555   Vec            coordinates, newCoordinates;
3556   PetscScalar   *coords, *newCoords;
3557   PetscInt      *depthEnd, coordSize;
3558   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3559   PetscErrorCode ierr;
3560 
3561   PetscFunctionBegin;
3562   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3563   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3564   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3565   for (d = 0; d <= depth; ++d) {
3566     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3567   }
3568   /* Step 8: Convert coordinates */
3569   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3570   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3571   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3572   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);CHKERRQ(ierr);
3573   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3574   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3575   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3576   for (v = vStartNew; v < vEndNew; ++v) {
3577     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3578     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3579   }
3580   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3581   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3582   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3583   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &newCoordinates);CHKERRQ(ierr);
3584   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3585   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3586   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3587   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3588   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3589   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3590   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3591   for (v = vStart; v < vEnd; ++v) {
3592     PetscInt dof, off, noff, d;
3593 
3594     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3595     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3596     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3597     for (d = 0; d < dof; ++d) {
3598       newCoords[noff+d] = coords[off+d];
3599     }
3600   }
3601   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3602   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3603   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3604   ierr = PetscSectionDestroy(&newCoordSection);CHKERRQ(ierr);
3605   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3606   PetscFunctionReturn(0);
3607 }
3608 
3609 #undef __FUNCT__
3610 #define __FUNCT__ "DMPlexShiftSF_Private"
3611 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3612 {
3613   PetscInt          *depthEnd;
3614   PetscInt           depth = 0, d;
3615   PetscSF            sfPoint, sfPointNew;
3616   const PetscSFNode *remotePoints;
3617   PetscSFNode       *gremotePoints;
3618   const PetscInt    *localPoints;
3619   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3620   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3621   PetscMPIInt        numProcs;
3622   PetscErrorCode     ierr;
3623 
3624   PetscFunctionBegin;
3625   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3626   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3627   for (d = 0; d <= depth; ++d) {
3628     totShift += depthShift[d];
3629     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3630   }
3631   /* Step 9: Convert pointSF */
3632   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
3633   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3634   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3635   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3636   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3637   if (numRoots >= 0) {
3638     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3639     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3640     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3641     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3642     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3643     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3644     for (l = 0; l < numLeaves; ++l) {
3645       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3646       gremotePoints[l].rank  = remotePoints[l].rank;
3647       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3648     }
3649     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3650     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3651   }
3652   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3653   PetscFunctionReturn(0);
3654 }
3655 
3656 #undef __FUNCT__
3657 #define __FUNCT__ "DMPlexShiftLabels_Private"
3658 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3659 {
3660   PetscSF            sfPoint;
3661   DMLabel            vtkLabel, ghostLabel;
3662   PetscInt          *depthEnd;
3663   const PetscSFNode *leafRemote;
3664   const PetscInt    *leafLocal;
3665   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3666   PetscMPIInt        rank;
3667   PetscErrorCode     ierr;
3668 
3669   PetscFunctionBegin;
3670   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3671   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3672   for (d = 0; d <= depth; ++d) {
3673     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3674   }
3675   /* Step 10: Convert labels */
3676   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3677   for (l = 0; l < numLabels; ++l) {
3678     DMLabel         label, newlabel;
3679     const char     *lname;
3680     PetscBool       isDepth;
3681     IS              valueIS;
3682     const PetscInt *values;
3683     PetscInt        numValues, val;
3684 
3685     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3686     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3687     if (isDepth) continue;
3688     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3689     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3690     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3691     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3692     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3693     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3694     for (val = 0; val < numValues; ++val) {
3695       IS              pointIS;
3696       const PetscInt *points;
3697       PetscInt        numPoints, p;
3698 
3699       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3700       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3701       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3702       for (p = 0; p < numPoints; ++p) {
3703         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3704 
3705         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3706       }
3707       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3708       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3709     }
3710     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3711     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3712   }
3713   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3714   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3715   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
3716   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3717   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3718   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3719   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3720   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3721   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3722   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3723   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3724     for (; c < leafLocal[l] && c < cEnd; ++c) {
3725       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3726     }
3727     if (leafLocal[l] >= cEnd) break;
3728     if (leafRemote[l].rank == rank) {
3729       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3730     } else {
3731       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3732     }
3733   }
3734   for (; c < cEnd; ++c) {
3735     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3736   }
3737   if (0) {
3738     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3739     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3740     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3741   }
3742   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3743   for (f = fStart; f < fEnd; ++f) {
3744     PetscInt numCells;
3745 
3746     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3747     if (numCells < 2) {
3748       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3749     } else {
3750       const PetscInt *cells = NULL;
3751       PetscInt        vA, vB;
3752 
3753       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3754       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3755       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3756       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3757     }
3758   }
3759   if (0) {
3760     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3761     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3762     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3763   }
3764   PetscFunctionReturn(0);
3765 }
3766 
3767 #undef __FUNCT__
3768 #define __FUNCT__ "DMPlexConstructGhostCells_Internal"
3769 static PetscErrorCode DMPlexConstructGhostCells_Internal(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3770 {
3771   DMLabel         label;
3772   IS              valueIS;
3773   const PetscInt *values;
3774   PetscInt       *depthShift;
3775   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3776   PetscErrorCode  ierr;
3777 
3778   PetscFunctionBegin;
3779   /* Count ghost cells */
3780   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3781   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3782   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3783   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3784 
3785   *numGhostCells = 0;
3786   for (fs = 0; fs < numFS; ++fs) {
3787     PetscInt numBdFaces;
3788 
3789     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3790 
3791     *numGhostCells += numBdFaces;
3792   }
3793   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3794   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3795   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3796   if (depth >= 0) depthShift[depth] = *numGhostCells;
3797   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3798   /* Step 3: Set cone/support sizes for new points */
3799   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3800   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3801     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3802   }
3803   for (fs = 0; fs < numFS; ++fs) {
3804     IS              faceIS;
3805     const PetscInt *faces;
3806     PetscInt        numFaces, f;
3807 
3808     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3809     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3810     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3811     for (f = 0; f < numFaces; ++f) {
3812       PetscInt size;
3813 
3814       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3815       if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3816       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3817     }
3818     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3819     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3820   }
3821   /* Step 4: Setup ghosted DM */
3822   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3823   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3824   /* Step 6: Set cones and supports for new points */
3825   ghostCell = cEnd;
3826   for (fs = 0; fs < numFS; ++fs) {
3827     IS              faceIS;
3828     const PetscInt *faces;
3829     PetscInt        numFaces, f;
3830 
3831     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3832     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3833     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3834     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3835       PetscInt newFace = faces[f] + *numGhostCells;
3836 
3837       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3838       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3839     }
3840     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3841     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3842   }
3843   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3844   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3845   /* Step 7: Stratify */
3846   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3847   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3848   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3849   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3850   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3851   PetscFunctionReturn(0);
3852 }
3853 
3854 #undef __FUNCT__
3855 #define __FUNCT__ "DMPlexConstructGhostCells"
3856 /*@C
3857   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3858 
3859   Collective on dm
3860 
3861   Input Parameters:
3862 + dm - The original DM
3863 - labelName - The label specifying the boundary faces, or "Face Sets" if this is NULL
3864 
3865   Output Parameters:
3866 + numGhostCells - The number of ghost cells added to the DM
3867 - dmGhosted - The new DM
3868 
3869   Level: developer
3870 
3871 .seealso: DMCreate()
3872 */
3873 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3874 {
3875   DM             gdm;
3876   PetscInt       dim;
3877   PetscErrorCode ierr;
3878 
3879   PetscFunctionBegin;
3880   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3881   PetscValidPointer(numGhostCells, 3);
3882   PetscValidPointer(dmGhosted, 4);
3883   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &gdm);CHKERRQ(ierr);
3884   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3885   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3886   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3887   ierr = DMPlexConstructGhostCells_Internal(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3888   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3889   *dmGhosted = gdm;
3890   PetscFunctionReturn(0);
3891 }
3892 
3893 #undef __FUNCT__
3894 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3895 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3896 {
3897   MPI_Comm        comm;
3898   IS              valueIS, *pointIS;
3899   const PetscInt *values, **splitPoints;
3900   PetscSection    coordSection;
3901   Vec             coordinates;
3902   PetscScalar    *coords;
3903   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3904   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3905   PetscErrorCode  ierr;
3906 
3907   PetscFunctionBegin;
3908   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3909   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3910   /* Count split points and add cohesive cells */
3911   if (label) {
3912     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3913     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3914     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3915   }
3916   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3917   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3918   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3919   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3920   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3921   for (d = 0; d <= depth; ++d) {
3922     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3923     numSplitPoints[d] = 0;
3924     splitPoints[d]    = NULL;
3925     pointIS[d]        = NULL;
3926   }
3927   for (sp = 0; sp < numSP; ++sp) {
3928     const PetscInt dep = values[sp];
3929 
3930     if ((dep < 0) || (dep > depth)) continue;
3931     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3932     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3933     if (pointIS[dep]) {
3934       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3935       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3936     }
3937   }
3938   if (depth >= 0) {
3939     /* Calculate number of additional points */
3940     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3941     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3942     /* Calculate hybrid bound for each dimension */
3943     pMaxNew[0] += depthShift[depth];
3944     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3945     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3946 
3947     /* Calculate point offset for each dimension */
3948     depthOffset[depth] = 0;
3949     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3950     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3951     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3952   }
3953   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3954   /* Step 3: Set cone/support sizes for new points */
3955   for (dep = 0; dep <= depth; ++dep) {
3956     for (p = 0; p < numSplitPoints[dep]; ++p) {
3957       const PetscInt  oldp   = splitPoints[dep][p];
3958       const PetscInt  newp   = depthOffset[dep] + oldp;
3959       const PetscInt  splitp = pMaxNew[dep] + p;
3960       const PetscInt *support;
3961       PetscInt        coneSize, supportSize, q, e;
3962 
3963       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3964       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3965       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3966       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3967       if (dep == depth-1) {
3968         const PetscInt ccell = pMaxNew[depth] + p;
3969         /* Add cohesive cells, they are prisms */
3970         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3971       } else if (dep == 0) {
3972         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3973 
3974         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3975         /* Split old vertex: Edges in old split faces and new cohesive edge */
3976         for (e = 0, q = 0; e < supportSize; ++e) {
3977           PetscInt val;
3978 
3979           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3980           if ((val == 1) || (val == (shift + 1))) ++q;
3981         }
3982         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3983         /* Split new vertex: Edges in new split faces and new cohesive edge */
3984         for (e = 0, q = 0; e < supportSize; ++e) {
3985           PetscInt val;
3986 
3987           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3988           if ((val == 1) || (val == -(shift + 1))) ++q;
3989         }
3990         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
3991         /* Add cohesive edges */
3992         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
3993         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3994       } else if (dep == dim-2) {
3995         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3996         /* Split old edge: Faces in positive side cells and old split faces */
3997         for (e = 0, q = 0; e < supportSize; ++e) {
3998           PetscInt val;
3999 
4000           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4001           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4002         }
4003         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4004         /* Split new edge: Faces in negative side cells and new split faces */
4005         for (e = 0, q = 0; e < supportSize; ++e) {
4006           PetscInt val;
4007 
4008           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4009           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4010         }
4011         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4012       }
4013     }
4014   }
4015   /* Step 4: Setup split DM */
4016   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4017   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4018   /* Step 6: Set cones and supports for new points */
4019   for (dep = 0; dep <= depth; ++dep) {
4020     for (p = 0; p < numSplitPoints[dep]; ++p) {
4021       const PetscInt  oldp   = splitPoints[dep][p];
4022       const PetscInt  newp   = depthOffset[dep] + oldp;
4023       const PetscInt  splitp = pMaxNew[dep] + p;
4024       const PetscInt *cone, *support, *ornt;
4025       PetscInt        coneSize, supportSize, q, v, e, s;
4026 
4027       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4028       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4029       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4030       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4031       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4032       if (dep == depth-1) {
4033         const PetscInt  ccell = pMaxNew[depth] + p;
4034         const PetscInt *supportF;
4035 
4036         /* Split face:       copy in old face to new face to start */
4037         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4038         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4039         /* Split old face:   old vertices/edges in cone so no change */
4040         /* Split new face:   new vertices/edges in cone */
4041         for (q = 0; q < coneSize; ++q) {
4042           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4043 
4044           coneNew[2+q] = pMaxNew[dim-2] + v;
4045         }
4046         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4047         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4048         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4049         coneNew[0] = newp;
4050         coneNew[1] = splitp;
4051         for (q = 0; q < coneSize; ++q) {
4052           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4053         }
4054         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4055 
4056 
4057         for (s = 0; s < supportSize; ++s) {
4058           PetscInt val;
4059 
4060           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4061           if (val < 0) {
4062             /* Split old face:   Replace negative side cell with cohesive cell */
4063             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4064           } else {
4065             /* Split new face:   Replace positive side cell with cohesive cell */
4066             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4067           }
4068         }
4069       } else if (dep == 0) {
4070         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4071 
4072         /* Split old vertex: Edges in old split faces and new cohesive edge */
4073         for (e = 0, q = 0; e < supportSize; ++e) {
4074           PetscInt val;
4075 
4076           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4077           if ((val == 1) || (val == (shift + 1))) {
4078             supportNew[q++] = depthOffset[1] + support[e];
4079           }
4080         }
4081         supportNew[q] = cedge;
4082 
4083         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4084         /* Split new vertex: Edges in new split faces and new cohesive edge */
4085         for (e = 0, q = 0; e < supportSize; ++e) {
4086           PetscInt val, edge;
4087 
4088           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4089           if (val == 1) {
4090             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4091             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4092             supportNew[q++] = pMaxNew[1] + edge;
4093           } else if (val == -(shift + 1)) {
4094             supportNew[q++] = depthOffset[1] + support[e];
4095           }
4096         }
4097         supportNew[q] = cedge;
4098         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4099         /* Cohesive edge:    Old and new split vertex, punting on support */
4100         coneNew[0] = newp;
4101         coneNew[1] = splitp;
4102         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4103       } else if (dep == dim-2) {
4104         /* Split old edge:   old vertices in cone so no change */
4105         /* Split new edge:   new vertices in cone */
4106         for (q = 0; q < coneSize; ++q) {
4107           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4108 
4109           coneNew[q] = pMaxNew[dim-3] + v;
4110         }
4111         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4112         /* Split old edge: Faces in positive side cells and old split faces */
4113         for (e = 0, q = 0; e < supportSize; ++e) {
4114           PetscInt val;
4115 
4116           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4117           if ((val == dim-1) || (val == (shift + dim-1))) {
4118             supportNew[q++] = depthOffset[dim-1] + support[e];
4119           }
4120         }
4121         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4122         /* Split new edge: Faces in negative side cells and new split faces */
4123         for (e = 0, q = 0; e < supportSize; ++e) {
4124           PetscInt val, face;
4125 
4126           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4127           if (val == dim-1) {
4128             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4129             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4130             supportNew[q++] = pMaxNew[dim-1] + face;
4131           } else if (val == -(shift + dim-1)) {
4132             supportNew[q++] = depthOffset[dim-1] + support[e];
4133           }
4134         }
4135         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4136       }
4137     }
4138   }
4139   /* Step 6b: Replace split points in negative side cones */
4140   for (sp = 0; sp < numSP; ++sp) {
4141     PetscInt        dep = values[sp];
4142     IS              pIS;
4143     PetscInt        numPoints;
4144     const PetscInt *points;
4145 
4146     if (dep >= 0) continue;
4147     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4148     if (!pIS) continue;
4149     dep  = -dep - shift;
4150     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4151     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4152     for (p = 0; p < numPoints; ++p) {
4153       const PetscInt  oldp = points[p];
4154       const PetscInt  newp = depthOffset[dep] + oldp;
4155       const PetscInt *cone;
4156       PetscInt        coneSize, c;
4157       PetscBool       replaced = PETSC_FALSE;
4158 
4159       /* Negative edge: replace split vertex */
4160       /* Negative cell: replace split face */
4161       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4162       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4163       for (c = 0; c < coneSize; ++c) {
4164         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4165         PetscInt       csplitp, cp, val;
4166 
4167         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4168         if (val == dep-1) {
4169           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4170           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4171           csplitp  = pMaxNew[dep-1] + cp;
4172           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4173           replaced = PETSC_TRUE;
4174         }
4175       }
4176       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4177     }
4178     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4179     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4180   }
4181   /* Step 7: Stratify */
4182   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4183   /* Step 8: Coordinates */
4184   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4185   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4186   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4187   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4188   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4189     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4190     const PetscInt splitp = pMaxNew[0] + v;
4191     PetscInt       dof, off, soff, d;
4192 
4193     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4194     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4195     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4196     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4197   }
4198   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4199   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4200   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4201   /* Step 10: Labels */
4202   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4203   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4204   for (dep = 0; dep <= depth; ++dep) {
4205     for (p = 0; p < numSplitPoints[dep]; ++p) {
4206       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4207       const PetscInt splitp = pMaxNew[dep] + p;
4208       PetscInt       l;
4209 
4210       for (l = 0; l < numLabels; ++l) {
4211         DMLabel     mlabel;
4212         const char *lname;
4213         PetscInt    val;
4214 
4215         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4216         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4217         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4218         if (val >= 0) {
4219           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4220           if (dep == 0) {
4221             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4222             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4223           }
4224         }
4225       }
4226     }
4227   }
4228   for (sp = 0; sp < numSP; ++sp) {
4229     const PetscInt dep = values[sp];
4230 
4231     if ((dep < 0) || (dep > depth)) continue;
4232     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4233     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4234   }
4235   if (label) {
4236     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4237     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4238   }
4239   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4240   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4241   PetscFunctionReturn(0);
4242 }
4243 
4244 #undef __FUNCT__
4245 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4246 /*@C
4247   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4248 
4249   Collective on dm
4250 
4251   Input Parameters:
4252 + dm - The original DM
4253 - labelName - The label specifying the boundary faces (this could be auto-generated)
4254 
4255   Output Parameters:
4256 - dmSplit - The new DM
4257 
4258   Level: developer
4259 
4260 .seealso: DMCreate()
4261 */
4262 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4263 {
4264   DM             sdm;
4265   PetscInt       dim;
4266   PetscErrorCode ierr;
4267 
4268   PetscFunctionBegin;
4269   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4270   PetscValidPointer(dmSplit, 4);
4271   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &sdm);CHKERRQ(ierr);
4272   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4273   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4274   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4275   switch (dim) {
4276   case 2:
4277   case 3:
4278     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4279     break;
4280   default:
4281     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4282   }
4283   *dmSplit = sdm;
4284   PetscFunctionReturn(0);
4285 }
4286 
4287 #undef __FUNCT__
4288 #define __FUNCT__ "DMLabelCohesiveComplete"
4289 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4290 {
4291   IS              dimIS;
4292   const PetscInt *points;
4293   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4294   PetscErrorCode  ierr;
4295 
4296   PetscFunctionBegin;
4297   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4298   /* Cell orientation for face gives the side of the fault */
4299   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4300   if (!dimIS) PetscFunctionReturn(0);
4301   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4302   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4303   for (p = 0; p < numPoints; ++p) {
4304     const PetscInt *support;
4305     PetscInt        supportSize, s;
4306 
4307     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4308     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4309     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4310     for (s = 0; s < supportSize; ++s) {
4311       const PetscInt *cone, *ornt;
4312       PetscInt        coneSize, c;
4313       PetscBool       pos = PETSC_TRUE;
4314 
4315       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4316       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4317       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4318       for (c = 0; c < coneSize; ++c) {
4319         if (cone[c] == points[p]) {
4320           if (ornt[c] >= 0) {
4321             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4322           } else {
4323             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4324             pos  = PETSC_FALSE;
4325           }
4326           break;
4327         }
4328       }
4329       if (c == coneSize) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4330       /* Put faces touching the fault in the label */
4331       for (c = 0; c < coneSize; ++c) {
4332         const PetscInt point = cone[c];
4333 
4334         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4335         if (val == -1) {
4336           PetscInt *closure = NULL;
4337           PetscInt  closureSize, cl;
4338 
4339           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4340           for (cl = 0; cl < closureSize*2; cl += 2) {
4341             const PetscInt clp = closure[cl];
4342 
4343             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4344             if ((val >= 0) && (val < dim-1)) {
4345               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4346               break;
4347             }
4348           }
4349           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4350         }
4351       }
4352     }
4353   }
4354   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4355   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4356   /* Search for other cells/faces/edges connected to the fault by a vertex */
4357   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4358   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4359   if (!dimIS) PetscFunctionReturn(0);
4360   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4361   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4362   for (p = 0; p < numPoints; ++p) {
4363     PetscInt *star = NULL;
4364     PetscInt  starSize, s;
4365     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4366 
4367     /* First mark cells connected to the fault */
4368     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4369     while (again) {
4370       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4371       again = 0;
4372       for (s = 0; s < starSize*2; s += 2) {
4373         const PetscInt  point = star[s];
4374         const PetscInt *cone;
4375         PetscInt        coneSize, c;
4376 
4377         if ((point < cStart) || (point >= cEnd)) continue;
4378         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4379         if (val != -1) continue;
4380         again = 2;
4381         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4382         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4383         for (c = 0; c < coneSize; ++c) {
4384           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4385           if (val != -1) {
4386             if (abs(val) < shift) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4387             if (val > 0) {
4388               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4389             } else {
4390               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4391             }
4392             again = 1;
4393             break;
4394           }
4395         }
4396       }
4397     }
4398     /* Classify the rest by cell membership */
4399     for (s = 0; s < starSize*2; s += 2) {
4400       const PetscInt point = star[s];
4401 
4402       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4403       if (val == -1) {
4404         PetscInt  *sstar = NULL;
4405         PetscInt   sstarSize, ss;
4406         PetscBool  marked = PETSC_FALSE;
4407 
4408         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4409         for (ss = 0; ss < sstarSize*2; ss += 2) {
4410           const PetscInt spoint = sstar[ss];
4411 
4412           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4413           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4414           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4415           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4416           if (val > 0) {
4417             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4418           } else {
4419             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4420           }
4421           marked = PETSC_TRUE;
4422           break;
4423         }
4424         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4425         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
4426       }
4427     }
4428     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4429   }
4430   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4431   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4432   PetscFunctionReturn(0);
4433 }
4434 
4435 #if defined(PETSC_HAVE_TRIANGLE)
4436 #include <triangle.h>
4437 
4438 #undef __FUNCT__
4439 #define __FUNCT__ "InitInput_Triangle"
4440 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4441 {
4442   PetscFunctionBegin;
4443   inputCtx->numberofpoints             = 0;
4444   inputCtx->numberofpointattributes    = 0;
4445   inputCtx->pointlist                  = NULL;
4446   inputCtx->pointattributelist         = NULL;
4447   inputCtx->pointmarkerlist            = NULL;
4448   inputCtx->numberofsegments           = 0;
4449   inputCtx->segmentlist                = NULL;
4450   inputCtx->segmentmarkerlist          = NULL;
4451   inputCtx->numberoftriangleattributes = 0;
4452   inputCtx->trianglelist               = NULL;
4453   inputCtx->numberofholes              = 0;
4454   inputCtx->holelist                   = NULL;
4455   inputCtx->numberofregions            = 0;
4456   inputCtx->regionlist                 = NULL;
4457   PetscFunctionReturn(0);
4458 }
4459 
4460 #undef __FUNCT__
4461 #define __FUNCT__ "InitOutput_Triangle"
4462 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4463 {
4464   PetscFunctionBegin;
4465   outputCtx->numberofpoints        = 0;
4466   outputCtx->pointlist             = NULL;
4467   outputCtx->pointattributelist    = NULL;
4468   outputCtx->pointmarkerlist       = NULL;
4469   outputCtx->numberoftriangles     = 0;
4470   outputCtx->trianglelist          = NULL;
4471   outputCtx->triangleattributelist = NULL;
4472   outputCtx->neighborlist          = NULL;
4473   outputCtx->segmentlist           = NULL;
4474   outputCtx->segmentmarkerlist     = NULL;
4475   outputCtx->numberofedges         = 0;
4476   outputCtx->edgelist              = NULL;
4477   outputCtx->edgemarkerlist        = NULL;
4478   PetscFunctionReturn(0);
4479 }
4480 
4481 #undef __FUNCT__
4482 #define __FUNCT__ "FiniOutput_Triangle"
4483 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4484 {
4485   PetscFunctionBegin;
4486   free(outputCtx->pointmarkerlist);
4487   free(outputCtx->edgelist);
4488   free(outputCtx->edgemarkerlist);
4489   free(outputCtx->trianglelist);
4490   free(outputCtx->neighborlist);
4491   PetscFunctionReturn(0);
4492 }
4493 
4494 #undef __FUNCT__
4495 #define __FUNCT__ "DMPlexGenerate_Triangle"
4496 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4497 {
4498   MPI_Comm             comm;
4499   PetscInt             dim              = 2;
4500   const PetscBool      createConvexHull = PETSC_FALSE;
4501   const PetscBool      constrained      = PETSC_FALSE;
4502   struct triangulateio in;
4503   struct triangulateio out;
4504   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4505   PetscMPIInt          rank;
4506   PetscErrorCode       ierr;
4507 
4508   PetscFunctionBegin;
4509   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4510   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4511   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4512   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4513   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4514 
4515   in.numberofpoints = vEnd - vStart;
4516   if (in.numberofpoints > 0) {
4517     PetscSection coordSection;
4518     Vec          coordinates;
4519     PetscScalar *array;
4520 
4521     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4522     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4523     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4524     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4525     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4526     for (v = vStart; v < vEnd; ++v) {
4527       const PetscInt idx = v - vStart;
4528       PetscInt       off, d;
4529 
4530       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4531       for (d = 0; d < dim; ++d) {
4532         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4533       }
4534       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4535     }
4536     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4537   }
4538   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4539   in.numberofsegments = eEnd - eStart;
4540   if (in.numberofsegments > 0) {
4541     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4542     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4543     for (e = eStart; e < eEnd; ++e) {
4544       const PetscInt  idx = e - eStart;
4545       const PetscInt *cone;
4546 
4547       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4548 
4549       in.segmentlist[idx*2+0] = cone[0] - vStart;
4550       in.segmentlist[idx*2+1] = cone[1] - vStart;
4551 
4552       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4553     }
4554   }
4555 #if 0 /* Do not currently support holes */
4556   PetscReal *holeCoords;
4557   PetscInt   h, d;
4558 
4559   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4560   if (in.numberofholes > 0) {
4561     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4562     for (h = 0; h < in.numberofholes; ++h) {
4563       for (d = 0; d < dim; ++d) {
4564         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4565       }
4566     }
4567   }
4568 #endif
4569   if (!rank) {
4570     char args[32];
4571 
4572     /* Take away 'Q' for verbose output */
4573     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4574     if (createConvexHull) {
4575       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4576     }
4577     if (constrained) {
4578       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4579     }
4580     triangulate(args, &in, &out, NULL);
4581   }
4582   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4583   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4584   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4585   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4586   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4587 
4588   {
4589     const PetscInt numCorners  = 3;
4590     const PetscInt numCells    = out.numberoftriangles;
4591     const PetscInt numVertices = out.numberofpoints;
4592     const int     *cells      = out.trianglelist;
4593     const double  *meshCoords = out.pointlist;
4594 
4595     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4596     /* Set labels */
4597     for (v = 0; v < numVertices; ++v) {
4598       if (out.pointmarkerlist[v]) {
4599         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4600       }
4601     }
4602     if (interpolate) {
4603       for (e = 0; e < out.numberofedges; e++) {
4604         if (out.edgemarkerlist[e]) {
4605           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4606           const PetscInt *edges;
4607           PetscInt        numEdges;
4608 
4609           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4610           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4611           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4612           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4613         }
4614       }
4615     }
4616     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4617   }
4618 #if 0 /* Do not currently support holes */
4619   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4620 #endif
4621   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4622   PetscFunctionReturn(0);
4623 }
4624 
4625 #undef __FUNCT__
4626 #define __FUNCT__ "DMPlexRefine_Triangle"
4627 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4628 {
4629   MPI_Comm             comm;
4630   PetscInt             dim  = 2;
4631   struct triangulateio in;
4632   struct triangulateio out;
4633   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4634   PetscMPIInt          rank;
4635   PetscErrorCode       ierr;
4636 
4637   PetscFunctionBegin;
4638   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4639   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4640   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4641   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4642   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4643   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4644   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4645 
4646   in.numberofpoints = vEnd - vStart;
4647   if (in.numberofpoints > 0) {
4648     PetscSection coordSection;
4649     Vec          coordinates;
4650     PetscScalar *array;
4651 
4652     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4653     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4654     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4655     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4656     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4657     for (v = vStart; v < vEnd; ++v) {
4658       const PetscInt idx = v - vStart;
4659       PetscInt       off, d;
4660 
4661       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4662       for (d = 0; d < dim; ++d) {
4663         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4664       }
4665       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4666     }
4667     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4668   }
4669   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4670 
4671   in.numberofcorners   = 3;
4672   in.numberoftriangles = cEnd - cStart;
4673 
4674   in.trianglearealist  = (double*) maxVolumes;
4675   if (in.numberoftriangles > 0) {
4676     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4677     for (c = cStart; c < cEnd; ++c) {
4678       const PetscInt idx      = c - cStart;
4679       PetscInt      *closure = NULL;
4680       PetscInt       closureSize;
4681 
4682       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4683       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4684       for (v = 0; v < 3; ++v) {
4685         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4686       }
4687       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4688     }
4689   }
4690   /* TODO: Segment markers are missing on input */
4691 #if 0 /* Do not currently support holes */
4692   PetscReal *holeCoords;
4693   PetscInt   h, d;
4694 
4695   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4696   if (in.numberofholes > 0) {
4697     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4698     for (h = 0; h < in.numberofholes; ++h) {
4699       for (d = 0; d < dim; ++d) {
4700         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4701       }
4702     }
4703   }
4704 #endif
4705   if (!rank) {
4706     char args[32];
4707 
4708     /* Take away 'Q' for verbose output */
4709     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4710     triangulate(args, &in, &out, NULL);
4711   }
4712   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4713   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4714   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4715   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4716   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4717 
4718   {
4719     const PetscInt numCorners  = 3;
4720     const PetscInt numCells    = out.numberoftriangles;
4721     const PetscInt numVertices = out.numberofpoints;
4722     const int     *cells      = out.trianglelist;
4723     const double  *meshCoords = out.pointlist;
4724     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4725 
4726     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4727     /* Set labels */
4728     for (v = 0; v < numVertices; ++v) {
4729       if (out.pointmarkerlist[v]) {
4730         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4731       }
4732     }
4733     if (interpolate) {
4734       PetscInt e;
4735 
4736       for (e = 0; e < out.numberofedges; e++) {
4737         if (out.edgemarkerlist[e]) {
4738           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4739           const PetscInt *edges;
4740           PetscInt        numEdges;
4741 
4742           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4743           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4744           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4745           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4746         }
4747       }
4748     }
4749     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4750   }
4751 #if 0 /* Do not currently support holes */
4752   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4753 #endif
4754   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4755   PetscFunctionReturn(0);
4756 }
4757 #endif
4758 
4759 #if defined(PETSC_HAVE_TETGEN)
4760 #include <tetgen.h>
4761 #undef __FUNCT__
4762 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4763 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4764 {
4765   MPI_Comm       comm;
4766   const PetscInt dim  = 3;
4767   ::tetgenio     in;
4768   ::tetgenio     out;
4769   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4770   PetscMPIInt    rank;
4771   PetscErrorCode ierr;
4772 
4773   PetscFunctionBegin;
4774   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4775   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4776   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4777   in.numberofpoints = vEnd - vStart;
4778   if (in.numberofpoints > 0) {
4779     PetscSection coordSection;
4780     Vec          coordinates;
4781     PetscScalar *array;
4782 
4783     in.pointlist       = new double[in.numberofpoints*dim];
4784     in.pointmarkerlist = new int[in.numberofpoints];
4785 
4786     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4787     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4788     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4789     for (v = vStart; v < vEnd; ++v) {
4790       const PetscInt idx = v - vStart;
4791       PetscInt       off, d;
4792 
4793       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4794       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4795       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4796     }
4797     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4798   }
4799   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4800 
4801   in.numberoffacets = fEnd - fStart;
4802   if (in.numberoffacets > 0) {
4803     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4804     in.facetmarkerlist = new int[in.numberoffacets];
4805     for (f = fStart; f < fEnd; ++f) {
4806       const PetscInt idx     = f - fStart;
4807       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
4808 
4809       in.facetlist[idx].numberofpolygons = 1;
4810       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4811       in.facetlist[idx].numberofholes    = 0;
4812       in.facetlist[idx].holelist         = NULL;
4813 
4814       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4815       for (p = 0; p < numPoints*2; p += 2) {
4816         const PetscInt point = points[p];
4817         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4818       }
4819 
4820       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4821       poly->numberofvertices = numVertices;
4822       poly->vertexlist       = new int[poly->numberofvertices];
4823       for (v = 0; v < numVertices; ++v) {
4824         const PetscInt vIdx = points[v] - vStart;
4825         poly->vertexlist[v] = vIdx;
4826       }
4827       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4828       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4829     }
4830   }
4831   if (!rank) {
4832     char args[32];
4833 
4834     /* Take away 'Q' for verbose output */
4835     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4836     ::tetrahedralize(args, &in, &out);
4837   }
4838   {
4839     const PetscInt numCorners  = 4;
4840     const PetscInt numCells    = out.numberoftetrahedra;
4841     const PetscInt numVertices = out.numberofpoints;
4842     const int     *cells      = out.tetrahedronlist;
4843     const double  *meshCoords = out.pointlist;
4844 
4845     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4846     /* Set labels */
4847     for (v = 0; v < numVertices; ++v) {
4848       if (out.pointmarkerlist[v]) {
4849         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4850       }
4851     }
4852     if (interpolate) {
4853       PetscInt e;
4854 
4855       for (e = 0; e < out.numberofedges; e++) {
4856         if (out.edgemarkerlist[e]) {
4857           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4858           const PetscInt *edges;
4859           PetscInt        numEdges;
4860 
4861           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4862           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4863           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4864           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4865         }
4866       }
4867       for (f = 0; f < out.numberoftrifaces; f++) {
4868         if (out.trifacemarkerlist[f]) {
4869           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4870           const PetscInt *faces;
4871           PetscInt        numFaces;
4872 
4873           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4874           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4875           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4876           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4877         }
4878       }
4879     }
4880     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4881   }
4882   PetscFunctionReturn(0);
4883 }
4884 
4885 #undef __FUNCT__
4886 #define __FUNCT__ "DMPlexRefine_Tetgen"
4887 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4888 {
4889   MPI_Comm       comm;
4890   const PetscInt dim  = 3;
4891   ::tetgenio     in;
4892   ::tetgenio     out;
4893   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4894   PetscMPIInt    rank;
4895   PetscErrorCode ierr;
4896 
4897   PetscFunctionBegin;
4898   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4899   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4900   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4901   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4902   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4903 
4904   in.numberofpoints = vEnd - vStart;
4905   if (in.numberofpoints > 0) {
4906     PetscSection coordSection;
4907     Vec          coordinates;
4908     PetscScalar *array;
4909 
4910     in.pointlist       = new double[in.numberofpoints*dim];
4911     in.pointmarkerlist = new int[in.numberofpoints];
4912 
4913     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4914     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4915     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4916     for (v = vStart; v < vEnd; ++v) {
4917       const PetscInt idx = v - vStart;
4918       PetscInt       off, d;
4919 
4920       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4921       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4922       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4923     }
4924     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4925   }
4926   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4927 
4928   in.numberofcorners       = 4;
4929   in.numberoftetrahedra    = cEnd - cStart;
4930   in.tetrahedronvolumelist = (double*) maxVolumes;
4931   if (in.numberoftetrahedra > 0) {
4932     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
4933     for (c = cStart; c < cEnd; ++c) {
4934       const PetscInt idx      = c - cStart;
4935       PetscInt      *closure = NULL;
4936       PetscInt       closureSize;
4937 
4938       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4939       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4940       for (v = 0; v < 4; ++v) {
4941         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4942       }
4943       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4944     }
4945   }
4946   /* TODO: Put in boundary faces with markers */
4947   if (!rank) {
4948     char args[32];
4949 
4950     /* Take away 'Q' for verbose output */
4951     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
4952     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
4953     ::tetrahedralize(args, &in, &out);
4954   }
4955   in.tetrahedronvolumelist = NULL;
4956 
4957   {
4958     const PetscInt numCorners  = 4;
4959     const PetscInt numCells    = out.numberoftetrahedra;
4960     const PetscInt numVertices = out.numberofpoints;
4961     const int     *cells      = out.tetrahedronlist;
4962     const double  *meshCoords = out.pointlist;
4963     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4964 
4965     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4966     /* Set labels */
4967     for (v = 0; v < numVertices; ++v) {
4968       if (out.pointmarkerlist[v]) {
4969         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4970       }
4971     }
4972     if (interpolate) {
4973       PetscInt e, f;
4974 
4975       for (e = 0; e < out.numberofedges; e++) {
4976         if (out.edgemarkerlist[e]) {
4977           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4978           const PetscInt *edges;
4979           PetscInt        numEdges;
4980 
4981           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4982           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4983           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4984           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4985         }
4986       }
4987       for (f = 0; f < out.numberoftrifaces; f++) {
4988         if (out.trifacemarkerlist[f]) {
4989           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4990           const PetscInt *faces;
4991           PetscInt        numFaces;
4992 
4993           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4994           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4995           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4996           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4997         }
4998       }
4999     }
5000     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5001   }
5002   PetscFunctionReturn(0);
5003 }
5004 #endif
5005 
5006 #if defined(PETSC_HAVE_CTETGEN)
5007 #include "ctetgen.h"
5008 
5009 #undef __FUNCT__
5010 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5011 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5012 {
5013   MPI_Comm       comm;
5014   const PetscInt dim  = 3;
5015   PLC           *in, *out;
5016   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5017   PetscMPIInt    rank;
5018   PetscErrorCode ierr;
5019 
5020   PetscFunctionBegin;
5021   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5022   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5023   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5024   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5025   ierr = PLCCreate(&in);CHKERRQ(ierr);
5026   ierr = PLCCreate(&out);CHKERRQ(ierr);
5027 
5028   in->numberofpoints = vEnd - vStart;
5029   if (in->numberofpoints > 0) {
5030     PetscSection coordSection;
5031     Vec          coordinates;
5032     PetscScalar *array;
5033 
5034     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5035     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5036     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5037     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5038     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5039     for (v = vStart; v < vEnd; ++v) {
5040       const PetscInt idx = v - vStart;
5041       PetscInt       off, d, m;
5042 
5043       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5044       for (d = 0; d < dim; ++d) {
5045         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5046       }
5047       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5048 
5049       in->pointmarkerlist[idx] = (int) m;
5050     }
5051     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5052   }
5053   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5054 
5055   in->numberoffacets = fEnd - fStart;
5056   if (in->numberoffacets > 0) {
5057     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5058     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5059     for (f = fStart; f < fEnd; ++f) {
5060       const PetscInt idx     = f - fStart;
5061       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5062       polygon       *poly;
5063 
5064       in->facetlist[idx].numberofpolygons = 1;
5065 
5066       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5067 
5068       in->facetlist[idx].numberofholes    = 0;
5069       in->facetlist[idx].holelist         = NULL;
5070 
5071       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5072       for (p = 0; p < numPoints*2; p += 2) {
5073         const PetscInt point = points[p];
5074         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5075       }
5076 
5077       poly                   = in->facetlist[idx].polygonlist;
5078       poly->numberofvertices = numVertices;
5079       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5080       for (v = 0; v < numVertices; ++v) {
5081         const PetscInt vIdx = points[v] - vStart;
5082         poly->vertexlist[v] = vIdx;
5083       }
5084       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5085       in->facetmarkerlist[idx] = (int) m;
5086       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5087     }
5088   }
5089   if (!rank) {
5090     TetGenOpts t;
5091 
5092     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5093     t.in        = boundary; /* Should go away */
5094     t.plc       = 1;
5095     t.quality   = 1;
5096     t.edgesout  = 1;
5097     t.zeroindex = 1;
5098     t.quiet     = 1;
5099     t.verbose   = verbose;
5100     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5101     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5102   }
5103   {
5104     const PetscInt numCorners  = 4;
5105     const PetscInt numCells    = out->numberoftetrahedra;
5106     const PetscInt numVertices = out->numberofpoints;
5107     const int     *cells      = out->tetrahedronlist;
5108     const double  *meshCoords = out->pointlist;
5109 
5110     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
5111     /* Set labels */
5112     for (v = 0; v < numVertices; ++v) {
5113       if (out->pointmarkerlist[v]) {
5114         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5115       }
5116     }
5117     if (interpolate) {
5118       PetscInt e;
5119 
5120       for (e = 0; e < out->numberofedges; e++) {
5121         if (out->edgemarkerlist[e]) {
5122           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5123           const PetscInt *edges;
5124           PetscInt        numEdges;
5125 
5126           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5127           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5128           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5129           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5130         }
5131       }
5132       for (f = 0; f < out->numberoftrifaces; f++) {
5133         if (out->trifacemarkerlist[f]) {
5134           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5135           const PetscInt *faces;
5136           PetscInt        numFaces;
5137 
5138           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5139           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5140           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5141           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5142         }
5143       }
5144     }
5145     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5146   }
5147 
5148   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5149   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5150   PetscFunctionReturn(0);
5151 }
5152 
5153 #undef __FUNCT__
5154 #define __FUNCT__ "DMPlexRefine_CTetgen"
5155 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5156 {
5157   MPI_Comm       comm;
5158   const PetscInt dim  = 3;
5159   PLC           *in, *out;
5160   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5161   PetscMPIInt    rank;
5162   PetscErrorCode ierr;
5163 
5164   PetscFunctionBegin;
5165   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5166   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5167   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5168   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5169   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5170   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5171   ierr = PLCCreate(&in);CHKERRQ(ierr);
5172   ierr = PLCCreate(&out);CHKERRQ(ierr);
5173 
5174   in->numberofpoints = vEnd - vStart;
5175   if (in->numberofpoints > 0) {
5176     PetscSection coordSection;
5177     Vec          coordinates;
5178     PetscScalar *array;
5179 
5180     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5181     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5182     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5183     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5184     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5185     for (v = vStart; v < vEnd; ++v) {
5186       const PetscInt idx = v - vStart;
5187       PetscInt       off, d, m;
5188 
5189       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5190       for (d = 0; d < dim; ++d) {
5191         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5192       }
5193       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5194 
5195       in->pointmarkerlist[idx] = (int) m;
5196     }
5197     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5198   }
5199   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5200 
5201   in->numberofcorners       = 4;
5202   in->numberoftetrahedra    = cEnd - cStart;
5203   in->tetrahedronvolumelist = maxVolumes;
5204   if (in->numberoftetrahedra > 0) {
5205     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5206     for (c = cStart; c < cEnd; ++c) {
5207       const PetscInt idx      = c - cStart;
5208       PetscInt      *closure = NULL;
5209       PetscInt       closureSize;
5210 
5211       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5212       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5213       for (v = 0; v < 4; ++v) {
5214         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5215       }
5216       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5217     }
5218   }
5219   if (!rank) {
5220     TetGenOpts t;
5221 
5222     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5223 
5224     t.in        = dm; /* Should go away */
5225     t.refine    = 1;
5226     t.varvolume = 1;
5227     t.quality   = 1;
5228     t.edgesout  = 1;
5229     t.zeroindex = 1;
5230     t.quiet     = 1;
5231     t.verbose   = verbose; /* Change this */
5232 
5233     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5234     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5235   }
5236   {
5237     const PetscInt numCorners  = 4;
5238     const PetscInt numCells    = out->numberoftetrahedra;
5239     const PetscInt numVertices = out->numberofpoints;
5240     const int     *cells       = out->tetrahedronlist;
5241     const double  *meshCoords  = out->pointlist;
5242     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5243 
5244     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
5245     /* Set labels */
5246     for (v = 0; v < numVertices; ++v) {
5247       if (out->pointmarkerlist[v]) {
5248         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5249       }
5250     }
5251     if (interpolate) {
5252       PetscInt e, f;
5253 
5254       for (e = 0; e < out->numberofedges; e++) {
5255         if (out->edgemarkerlist[e]) {
5256           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5257           const PetscInt *edges;
5258           PetscInt        numEdges;
5259 
5260           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5261           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5262           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5263           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5264         }
5265       }
5266       for (f = 0; f < out->numberoftrifaces; f++) {
5267         if (out->trifacemarkerlist[f]) {
5268           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5269           const PetscInt *faces;
5270           PetscInt        numFaces;
5271 
5272           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5273           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5274           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5275           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5276         }
5277       }
5278     }
5279     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5280   }
5281   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5282   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5283   PetscFunctionReturn(0);
5284 }
5285 #endif
5286 
5287 #undef __FUNCT__
5288 #define __FUNCT__ "DMPlexGenerate"
5289 /*@C
5290   DMPlexGenerate - Generates a mesh.
5291 
5292   Not Collective
5293 
5294   Input Parameters:
5295 + boundary - The DMPlex boundary object
5296 . name - The mesh generation package name
5297 - interpolate - Flag to create intermediate mesh elements
5298 
5299   Output Parameter:
5300 . mesh - The DMPlex object
5301 
5302   Level: intermediate
5303 
5304 .keywords: mesh, elements
5305 .seealso: DMPlexCreate(), DMRefine()
5306 @*/
5307 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5308 {
5309   PetscInt       dim;
5310   char           genname[1024];
5311   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5312   PetscErrorCode ierr;
5313 
5314   PetscFunctionBegin;
5315   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5316   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5317   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5318   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5319   if (flg) name = genname;
5320   if (name) {
5321     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5322     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5323     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5324   }
5325   switch (dim) {
5326   case 1:
5327     if (!name || isTriangle) {
5328 #if defined(PETSC_HAVE_TRIANGLE)
5329       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5330 #else
5331       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5332 #endif
5333     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5334     break;
5335   case 2:
5336     if (!name || isCTetgen) {
5337 #if defined(PETSC_HAVE_CTETGEN)
5338       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5339 #else
5340       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5341 #endif
5342     } else if (isTetgen) {
5343 #if defined(PETSC_HAVE_TETGEN)
5344       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5345 #else
5346       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5347 #endif
5348     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5349     break;
5350   default:
5351     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5352   }
5353   PetscFunctionReturn(0);
5354 }
5355 
5356 typedef PetscInt CellRefiner;
5357 
5358 #undef __FUNCT__
5359 #define __FUNCT__ "GetDepthStart_Private"
5360 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5361 {
5362   PetscFunctionBegin;
5363   if (cStart) *cStart = 0;
5364   if (vStart) *vStart = depthSize[depth];
5365   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5366   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5367   PetscFunctionReturn(0);
5368 }
5369 
5370 #undef __FUNCT__
5371 #define __FUNCT__ "GetDepthEnd_Private"
5372 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5373 {
5374   PetscFunctionBegin;
5375   if (cEnd) *cEnd = depthSize[depth];
5376   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5377   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5378   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5379   PetscFunctionReturn(0);
5380 }
5381 
5382 #undef __FUNCT__
5383 #define __FUNCT__ "CellRefinerGetSizes"
5384 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5385 {
5386   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5387   PetscErrorCode ierr;
5388 
5389   PetscFunctionBegin;
5390   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5391   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5392   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5393   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5394   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5395   switch (refiner) {
5396   case 1:
5397     /* Simplicial 2D */
5398     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5399     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5400     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5401     break;
5402   case 3:
5403     /* Hybrid 2D */
5404     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5405     cMax = PetscMin(cEnd, cMax);
5406     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5407     fMax         = PetscMin(fEnd, fMax);
5408     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5409     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 */
5410     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5411     break;
5412   case 2:
5413     /* Hex 2D */
5414     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5415     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5416     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5417     break;
5418   default:
5419     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5420   }
5421   PetscFunctionReturn(0);
5422 }
5423 
5424 #undef __FUNCT__
5425 #define __FUNCT__ "CellRefinerSetConeSizes"
5426 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5427 {
5428   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5429   PetscErrorCode ierr;
5430 
5431   PetscFunctionBegin;
5432   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5433   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5434   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5435   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5436   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5437   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5438   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5439   switch (refiner) {
5440   case 1:
5441     /* Simplicial 2D */
5442     /* All cells have 3 faces */
5443     for (c = cStart; c < cEnd; ++c) {
5444       for (r = 0; r < 4; ++r) {
5445         const PetscInt newp = (c - cStart)*4 + r;
5446 
5447         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5448       }
5449     }
5450     /* Split faces have 2 vertices and the same cells as the parent */
5451     for (f = fStart; f < fEnd; ++f) {
5452       for (r = 0; r < 2; ++r) {
5453         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5454         PetscInt       size;
5455 
5456         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5457         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5458         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5459       }
5460     }
5461     /* Interior faces have 2 vertices and 2 cells */
5462     for (c = cStart; c < cEnd; ++c) {
5463       for (r = 0; r < 3; ++r) {
5464         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5465 
5466         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5467         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5468       }
5469     }
5470     /* Old vertices have identical supports */
5471     for (v = vStart; v < vEnd; ++v) {
5472       const PetscInt newp = vStartNew + (v - vStart);
5473       PetscInt       size;
5474 
5475       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5476       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5477     }
5478     /* Face vertices have 2 + cells*2 supports */
5479     for (f = fStart; f < fEnd; ++f) {
5480       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5481       PetscInt       size;
5482 
5483       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5484       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5485     }
5486     break;
5487   case 2:
5488     /* Hex 2D */
5489     /* All cells have 4 faces */
5490     for (c = cStart; c < cEnd; ++c) {
5491       for (r = 0; r < 4; ++r) {
5492         const PetscInt newp = (c - cStart)*4 + r;
5493 
5494         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5495       }
5496     }
5497     /* Split faces have 2 vertices and the same cells as the parent */
5498     for (f = fStart; f < fEnd; ++f) {
5499       for (r = 0; r < 2; ++r) {
5500         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5501         PetscInt       size;
5502 
5503         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5504         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5505         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5506       }
5507     }
5508     /* Interior faces have 2 vertices and 2 cells */
5509     for (c = cStart; c < cEnd; ++c) {
5510       for (r = 0; r < 4; ++r) {
5511         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5512 
5513         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5514         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5515       }
5516     }
5517     /* Old vertices have identical supports */
5518     for (v = vStart; v < vEnd; ++v) {
5519       const PetscInt newp = vStartNew + (v - vStart);
5520       PetscInt       size;
5521 
5522       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5523       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5524     }
5525     /* Face vertices have 2 + cells supports */
5526     for (f = fStart; f < fEnd; ++f) {
5527       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5528       PetscInt       size;
5529 
5530       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5531       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5532     }
5533     /* Cell vertices have 4 supports */
5534     for (c = cStart; c < cEnd; ++c) {
5535       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5536 
5537       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5538     }
5539     break;
5540   case 3:
5541     /* Hybrid 2D */
5542     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5543     cMax = PetscMin(cEnd, cMax);
5544     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5545     fMax = PetscMin(fEnd, fMax);
5546     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5547     /* Interior cells have 3 faces */
5548     for (c = cStart; c < cMax; ++c) {
5549       for (r = 0; r < 4; ++r) {
5550         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5551 
5552         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5553       }
5554     }
5555     /* Hybrid cells have 4 faces */
5556     for (c = cMax; c < cEnd; ++c) {
5557       for (r = 0; r < 2; ++r) {
5558         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5559 
5560         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5561       }
5562     }
5563     /* Interior split faces have 2 vertices and the same cells as the parent */
5564     for (f = fStart; f < fMax; ++f) {
5565       for (r = 0; r < 2; ++r) {
5566         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5567         PetscInt       size;
5568 
5569         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5570         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5571         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5572       }
5573     }
5574     /* Interior cell faces have 2 vertices and 2 cells */
5575     for (c = cStart; c < cMax; ++c) {
5576       for (r = 0; r < 3; ++r) {
5577         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5578 
5579         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5580         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5581       }
5582     }
5583     /* Hybrid faces have 2 vertices and the same cells */
5584     for (f = fMax; f < fEnd; ++f) {
5585       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5586       PetscInt       size;
5587 
5588       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5589       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5590       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5591     }
5592     /* Hybrid cell faces have 2 vertices and 2 cells */
5593     for (c = cMax; c < cEnd; ++c) {
5594       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5595 
5596       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5597       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5598     }
5599     /* Old vertices have identical supports */
5600     for (v = vStart; v < vEnd; ++v) {
5601       const PetscInt newp = vStartNew + (v - vStart);
5602       PetscInt       size;
5603 
5604       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5605       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5606     }
5607     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5608     for (f = fStart; f < fMax; ++f) {
5609       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5610       const PetscInt *support;
5611       PetscInt       size, newSize = 2, s;
5612 
5613       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5614       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5615       for (s = 0; s < size; ++s) {
5616         if (support[s] >= cMax) newSize += 1;
5617         else newSize += 2;
5618       }
5619       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5620     }
5621     break;
5622   default:
5623     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5624   }
5625   PetscFunctionReturn(0);
5626 }
5627 
5628 #undef __FUNCT__
5629 #define __FUNCT__ "CellRefinerSetCones"
5630 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5631 {
5632   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;
5633   PetscInt       maxSupportSize, *supportRef;
5634   PetscErrorCode ierr;
5635 
5636   PetscFunctionBegin;
5637   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5638   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5639   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5640   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5641   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5642   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5643   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5644   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5645   switch (refiner) {
5646   case 1:
5647     /* Simplicial 2D */
5648     /*
5649      2
5650      |\
5651      | \
5652      |  \
5653      |   \
5654      | C  \
5655      |     \
5656      |      \
5657      2---1---1
5658      |\  D  / \
5659      | 2   0   \
5660      |A \ /  B  \
5661      0---0-------1
5662      */
5663     /* All cells have 3 faces */
5664     for (c = cStart; c < cEnd; ++c) {
5665       const PetscInt  newp = cStartNew + (c - cStart)*4;
5666       const PetscInt *cone, *ornt;
5667       PetscInt        coneNew[3], orntNew[3];
5668 
5669       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5670       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5671       /* A triangle */
5672       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5673       orntNew[0] = ornt[0];
5674       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5675       orntNew[1] = -2;
5676       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5677       orntNew[2] = ornt[2];
5678       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5679       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5680 #if 1
5681       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);
5682       for (p = 0; p < 3; ++p) {
5683         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);
5684       }
5685 #endif
5686       /* B triangle */
5687       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5688       orntNew[0] = ornt[0];
5689       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5690       orntNew[1] = ornt[1];
5691       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5692       orntNew[2] = -2;
5693       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5694       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5695 #if 1
5696       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);
5697       for (p = 0; p < 3; ++p) {
5698         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);
5699       }
5700 #endif
5701       /* C triangle */
5702       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5703       orntNew[0] = -2;
5704       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5705       orntNew[1] = ornt[1];
5706       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5707       orntNew[2] = ornt[2];
5708       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5709       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5710 #if 1
5711       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);
5712       for (p = 0; p < 3; ++p) {
5713         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);
5714       }
5715 #endif
5716       /* D triangle */
5717       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5718       orntNew[0] = 0;
5719       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5720       orntNew[1] = 0;
5721       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5722       orntNew[2] = 0;
5723       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5724       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5725 #if 1
5726       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);
5727       for (p = 0; p < 3; ++p) {
5728         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);
5729       }
5730 #endif
5731     }
5732     /* Split faces have 2 vertices and the same cells as the parent */
5733     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5734     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5735     for (f = fStart; f < fEnd; ++f) {
5736       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5737 
5738       for (r = 0; r < 2; ++r) {
5739         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5740         const PetscInt *cone, *support;
5741         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5742 
5743         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5744         coneNew[0]       = vStartNew + (cone[0] - vStart);
5745         coneNew[1]       = vStartNew + (cone[1] - vStart);
5746         coneNew[(r+1)%2] = newv;
5747         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5748 #if 1
5749         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5750         for (p = 0; p < 2; ++p) {
5751           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);
5752         }
5753 #endif
5754         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5755         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5756         for (s = 0; s < supportSize; ++s) {
5757           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5758           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5759           for (c = 0; c < coneSize; ++c) {
5760             if (cone[c] == f) break;
5761           }
5762           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5763         }
5764         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5765 #if 1
5766         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5767         for (p = 0; p < supportSize; ++p) {
5768           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);
5769         }
5770 #endif
5771       }
5772     }
5773     /* Interior faces have 2 vertices and 2 cells */
5774     for (c = cStart; c < cEnd; ++c) {
5775       const PetscInt *cone;
5776 
5777       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5778       for (r = 0; r < 3; ++r) {
5779         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5780         PetscInt       coneNew[2];
5781         PetscInt       supportNew[2];
5782 
5783         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5784         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5785         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5786 #if 1
5787         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5788         for (p = 0; p < 2; ++p) {
5789           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);
5790         }
5791 #endif
5792         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5793         supportNew[1] = (c - cStart)*4 + 3;
5794         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5795 #if 1
5796         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5797         for (p = 0; p < 2; ++p) {
5798           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);
5799         }
5800 #endif
5801       }
5802     }
5803     /* Old vertices have identical supports */
5804     for (v = vStart; v < vEnd; ++v) {
5805       const PetscInt  newp = vStartNew + (v - vStart);
5806       const PetscInt *support, *cone;
5807       PetscInt        size, s;
5808 
5809       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5810       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5811       for (s = 0; s < size; ++s) {
5812         PetscInt r = 0;
5813 
5814         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5815         if (cone[1] == v) r = 1;
5816         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5817       }
5818       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5819 #if 1
5820       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5821       for (p = 0; p < size; ++p) {
5822         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);
5823       }
5824 #endif
5825     }
5826     /* Face vertices have 2 + cells*2 supports */
5827     for (f = fStart; f < fEnd; ++f) {
5828       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5829       const PetscInt *cone, *support;
5830       PetscInt        size, s;
5831 
5832       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5833       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5834       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5835       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5836       for (s = 0; s < size; ++s) {
5837         PetscInt r = 0;
5838 
5839         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5840         if      (cone[1] == f) r = 1;
5841         else if (cone[2] == f) r = 2;
5842         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5843         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5844       }
5845       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5846 #if 1
5847       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5848       for (p = 0; p < 2+size*2; ++p) {
5849         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);
5850       }
5851 #endif
5852     }
5853     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5854     break;
5855   case 2:
5856     /* Hex 2D */
5857     /*
5858      3---------2---------2
5859      |         |         |
5860      |    D    2    C    |
5861      |         |         |
5862      3----3----0----1----1
5863      |         |         |
5864      |    A    0    B    |
5865      |         |         |
5866      0---------0---------1
5867      */
5868     /* All cells have 4 faces */
5869     for (c = cStart; c < cEnd; ++c) {
5870       const PetscInt  newp = (c - cStart)*4;
5871       const PetscInt *cone, *ornt;
5872       PetscInt        coneNew[4], orntNew[4];
5873 
5874       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5875       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5876       /* A quad */
5877       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5878       orntNew[0] = ornt[0];
5879       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5880       orntNew[1] = 0;
5881       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5882       orntNew[2] = -2;
5883       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5884       orntNew[3] = ornt[3];
5885       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5886       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5887 #if 1
5888       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);
5889       for (p = 0; p < 4; ++p) {
5890         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);
5891       }
5892 #endif
5893       /* B quad */
5894       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5895       orntNew[0] = ornt[0];
5896       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5897       orntNew[1] = ornt[1];
5898       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5899       orntNew[2] = 0;
5900       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5901       orntNew[3] = -2;
5902       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5903       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5904 #if 1
5905       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);
5906       for (p = 0; p < 4; ++p) {
5907         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);
5908       }
5909 #endif
5910       /* C quad */
5911       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5912       orntNew[0] = -2;
5913       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5914       orntNew[1] = ornt[1];
5915       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5916       orntNew[2] = ornt[2];
5917       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5918       orntNew[3] = 0;
5919       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5920       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5921 #if 1
5922       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);
5923       for (p = 0; p < 4; ++p) {
5924         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);
5925       }
5926 #endif
5927       /* D quad */
5928       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5929       orntNew[0] = 0;
5930       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5931       orntNew[1] = -2;
5932       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5933       orntNew[2] = ornt[2];
5934       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
5935       orntNew[3] = ornt[3];
5936       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5937       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5938 #if 1
5939       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);
5940       for (p = 0; p < 4; ++p) {
5941         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);
5942       }
5943 #endif
5944     }
5945     /* Split faces have 2 vertices and the same cells as the parent */
5946     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5947     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5948     for (f = fStart; f < fEnd; ++f) {
5949       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5950 
5951       for (r = 0; r < 2; ++r) {
5952         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5953         const PetscInt *cone, *support;
5954         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5955 
5956         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5957         coneNew[0]       = vStartNew + (cone[0] - vStart);
5958         coneNew[1]       = vStartNew + (cone[1] - vStart);
5959         coneNew[(r+1)%2] = newv;
5960         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5961 #if 1
5962         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5963         for (p = 0; p < 2; ++p) {
5964           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);
5965         }
5966 #endif
5967         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5968         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5969         for (s = 0; s < supportSize; ++s) {
5970           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5971           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5972           for (c = 0; c < coneSize; ++c) {
5973             if (cone[c] == f) break;
5974           }
5975           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
5976         }
5977         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5978 #if 1
5979         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5980         for (p = 0; p < supportSize; ++p) {
5981           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);
5982         }
5983 #endif
5984       }
5985     }
5986     /* Interior faces have 2 vertices and 2 cells */
5987     for (c = cStart; c < cEnd; ++c) {
5988       const PetscInt *cone;
5989       PetscInt        coneNew[2], supportNew[2];
5990 
5991       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5992       for (r = 0; r < 4; ++r) {
5993         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5994 
5995         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5996         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5997         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5998 #if 1
5999         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6000         for (p = 0; p < 2; ++p) {
6001           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);
6002         }
6003 #endif
6004         supportNew[0] = (c - cStart)*4 + r;
6005         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6006         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6007 #if 1
6008         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6009         for (p = 0; p < 2; ++p) {
6010           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);
6011         }
6012 #endif
6013       }
6014     }
6015     /* Old vertices have identical supports */
6016     for (v = vStart; v < vEnd; ++v) {
6017       const PetscInt  newp = vStartNew + (v - vStart);
6018       const PetscInt *support, *cone;
6019       PetscInt        size, s;
6020 
6021       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6022       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6023       for (s = 0; s < size; ++s) {
6024         PetscInt r = 0;
6025 
6026         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6027         if (cone[1] == v) r = 1;
6028         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6029       }
6030       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6031 #if 1
6032       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6033       for (p = 0; p < size; ++p) {
6034         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);
6035       }
6036 #endif
6037     }
6038     /* Face vertices have 2 + cells supports */
6039     for (f = fStart; f < fEnd; ++f) {
6040       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6041       const PetscInt *cone, *support;
6042       PetscInt        size, s;
6043 
6044       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6045       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6046       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6047       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6048       for (s = 0; s < size; ++s) {
6049         PetscInt r = 0;
6050 
6051         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6052         if      (cone[1] == f) r = 1;
6053         else if (cone[2] == f) r = 2;
6054         else if (cone[3] == f) r = 3;
6055         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6056       }
6057       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6058 #if 1
6059       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6060       for (p = 0; p < 2+size; ++p) {
6061         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);
6062       }
6063 #endif
6064     }
6065     /* Cell vertices have 4 supports */
6066     for (c = cStart; c < cEnd; ++c) {
6067       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6068       PetscInt       supportNew[4];
6069 
6070       for (r = 0; r < 4; ++r) {
6071         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6072       }
6073       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6074     }
6075     break;
6076   case 3:
6077     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6078     cMax = PetscMin(cEnd, cMax);
6079     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6080     fMax = PetscMin(fEnd, fMax);
6081     /* Interior cells have 3 faces */
6082     for (c = cStart; c < cMax; ++c) {
6083       const PetscInt  newp = cStartNew + (c - cStart)*4;
6084       const PetscInt *cone, *ornt;
6085       PetscInt        coneNew[3], orntNew[3];
6086 
6087       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6088       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6089       /* A triangle */
6090       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6091       orntNew[0] = ornt[0];
6092       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6093       orntNew[1] = -2;
6094       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6095       orntNew[2] = ornt[2];
6096       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6097       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6098 #if 1
6099       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);
6100       for (p = 0; p < 3; ++p) {
6101         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);
6102       }
6103 #endif
6104       /* B triangle */
6105       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6106       orntNew[0] = ornt[0];
6107       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6108       orntNew[1] = ornt[1];
6109       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6110       orntNew[2] = -2;
6111       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6112       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6113 #if 1
6114       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);
6115       for (p = 0; p < 3; ++p) {
6116         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);
6117       }
6118 #endif
6119       /* C triangle */
6120       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6121       orntNew[0] = -2;
6122       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6123       orntNew[1] = ornt[1];
6124       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6125       orntNew[2] = ornt[2];
6126       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6127       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6128 #if 1
6129       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);
6130       for (p = 0; p < 3; ++p) {
6131         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);
6132       }
6133 #endif
6134       /* D triangle */
6135       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6136       orntNew[0] = 0;
6137       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6138       orntNew[1] = 0;
6139       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6140       orntNew[2] = 0;
6141       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6142       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6143 #if 1
6144       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);
6145       for (p = 0; p < 3; ++p) {
6146         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);
6147       }
6148 #endif
6149     }
6150     /*
6151      2----3----3
6152      |         |
6153      |    B    |
6154      |         |
6155      0----4--- 1
6156      |         |
6157      |    A    |
6158      |         |
6159      0----2----1
6160      */
6161     /* Hybrid cells have 4 faces */
6162     for (c = cMax; c < cEnd; ++c) {
6163       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6164       const PetscInt *cone, *ornt;
6165       PetscInt        coneNew[4], orntNew[4];
6166 
6167       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6168       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6169       /* A quad */
6170       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6171       orntNew[0] = ornt[0];
6172       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6173       orntNew[1] = ornt[1];
6174       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6175       orntNew[2] = 0;
6176       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6177       orntNew[3] = 0;
6178       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6179       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6180 #if 1
6181       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);
6182       for (p = 0; p < 4; ++p) {
6183         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);
6184       }
6185 #endif
6186       /* B quad */
6187       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6188       orntNew[0] = ornt[0];
6189       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6190       orntNew[1] = ornt[1];
6191       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6192       orntNew[2] = 0;
6193       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6194       orntNew[3] = 0;
6195       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6196       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6197 #if 1
6198       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);
6199       for (p = 0; p < 4; ++p) {
6200         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);
6201       }
6202 #endif
6203     }
6204     /* Interior split faces have 2 vertices and the same cells as the parent */
6205     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6206     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6207     for (f = fStart; f < fMax; ++f) {
6208       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6209 
6210       for (r = 0; r < 2; ++r) {
6211         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6212         const PetscInt *cone, *support;
6213         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6214 
6215         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6216         coneNew[0]       = vStartNew + (cone[0] - vStart);
6217         coneNew[1]       = vStartNew + (cone[1] - vStart);
6218         coneNew[(r+1)%2] = newv;
6219         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6220 #if 1
6221         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6222         for (p = 0; p < 2; ++p) {
6223           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);
6224         }
6225 #endif
6226         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6227         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6228         for (s = 0; s < supportSize; ++s) {
6229           if (support[s] >= cMax) {
6230             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6231           } else {
6232             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6233             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6234             for (c = 0; c < coneSize; ++c) {
6235               if (cone[c] == f) break;
6236             }
6237             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6238           }
6239         }
6240         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6241 #if 1
6242         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6243         for (p = 0; p < supportSize; ++p) {
6244           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);
6245         }
6246 #endif
6247       }
6248     }
6249     /* Interior cell faces have 2 vertices and 2 cells */
6250     for (c = cStart; c < cMax; ++c) {
6251       const PetscInt *cone;
6252 
6253       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6254       for (r = 0; r < 3; ++r) {
6255         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6256         PetscInt       coneNew[2];
6257         PetscInt       supportNew[2];
6258 
6259         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6260         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6261         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6262 #if 1
6263         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6264         for (p = 0; p < 2; ++p) {
6265           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);
6266         }
6267 #endif
6268         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6269         supportNew[1] = (c - cStart)*4 + 3;
6270         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6271 #if 1
6272         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6273         for (p = 0; p < 2; ++p) {
6274           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);
6275         }
6276 #endif
6277       }
6278     }
6279     /* Interior hybrid faces have 2 vertices and the same cells */
6280     for (f = fMax; f < fEnd; ++f) {
6281       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6282       const PetscInt *cone;
6283       const PetscInt *support;
6284       PetscInt        coneNew[2];
6285       PetscInt        supportNew[2];
6286       PetscInt        size, s, r;
6287 
6288       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6289       coneNew[0] = vStartNew + (cone[0] - vStart);
6290       coneNew[1] = vStartNew + (cone[1] - vStart);
6291       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6292 #if 1
6293       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6294       for (p = 0; p < 2; ++p) {
6295         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);
6296       }
6297 #endif
6298       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6299       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6300       for (s = 0; s < size; ++s) {
6301         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6302         for (r = 0; r < 2; ++r) {
6303           if (cone[r+2] == f) break;
6304         }
6305         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6306       }
6307       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6308 #if 1
6309       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6310       for (p = 0; p < size; ++p) {
6311         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);
6312       }
6313 #endif
6314     }
6315     /* Cell hybrid faces have 2 vertices and 2 cells */
6316     for (c = cMax; c < cEnd; ++c) {
6317       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6318       const PetscInt *cone;
6319       PetscInt        coneNew[2];
6320       PetscInt        supportNew[2];
6321 
6322       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6323       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6324       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6325       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6326 #if 1
6327       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6328       for (p = 0; p < 2; ++p) {
6329         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);
6330       }
6331 #endif
6332       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6333       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6334       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6335 #if 1
6336       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6337       for (p = 0; p < 2; ++p) {
6338         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);
6339       }
6340 #endif
6341     }
6342     /* Old vertices have identical supports */
6343     for (v = vStart; v < vEnd; ++v) {
6344       const PetscInt  newp = vStartNew + (v - vStart);
6345       const PetscInt *support, *cone;
6346       PetscInt        size, s;
6347 
6348       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6349       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6350       for (s = 0; s < size; ++s) {
6351         if (support[s] >= fMax) {
6352           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6353         } else {
6354           PetscInt r = 0;
6355 
6356           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6357           if (cone[1] == v) r = 1;
6358           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6359         }
6360       }
6361       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6362 #if 1
6363       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6364       for (p = 0; p < size; ++p) {
6365         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);
6366       }
6367 #endif
6368     }
6369     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6370     for (f = fStart; f < fMax; ++f) {
6371       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6372       const PetscInt *cone, *support;
6373       PetscInt        size, newSize = 2, s;
6374 
6375       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6376       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6377       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6378       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6379       for (s = 0; s < size; ++s) {
6380         PetscInt r = 0;
6381 
6382         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6383         if (support[s] >= cMax) {
6384           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6385 
6386           newSize += 1;
6387         } else {
6388           if      (cone[1] == f) r = 1;
6389           else if (cone[2] == f) r = 2;
6390           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6391           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6392 
6393           newSize += 2;
6394         }
6395       }
6396       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6397 #if 1
6398       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6399       for (p = 0; p < newSize; ++p) {
6400         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);
6401       }
6402 #endif
6403     }
6404     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6405     break;
6406   default:
6407     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6408   }
6409   PetscFunctionReturn(0);
6410 }
6411 
6412 #undef __FUNCT__
6413 #define __FUNCT__ "CellRefinerSetCoordinates"
6414 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6415 {
6416   PetscSection   coordSection, coordSectionNew;
6417   Vec            coordinates, coordinatesNew;
6418   PetscScalar   *coords, *coordsNew;
6419   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6420   PetscErrorCode ierr;
6421 
6422   PetscFunctionBegin;
6423   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6424   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6425   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6426   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6427   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6428   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6429   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6430   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6431   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6432   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6433   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6434   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6435   if (fMax < 0) fMax = fEnd;
6436   switch (refiner) {
6437   case 1:
6438   case 2:
6439   case 3:
6440     /* Simplicial and Hex 2D */
6441     /* All vertices have the dim coordinates */
6442     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6443       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6444       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6445     }
6446     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6447     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6448     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6449     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6450     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6451     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6452     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6453     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6454     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6455     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6456     /* Old vertices have the same coordinates */
6457     for (v = vStart; v < vEnd; ++v) {
6458       const PetscInt newv = vStartNew + (v - vStart);
6459       PetscInt       off, offnew, d;
6460 
6461       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6462       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6463       for (d = 0; d < dim; ++d) {
6464         coordsNew[offnew+d] = coords[off+d];
6465       }
6466     }
6467     /* Face vertices have the average of endpoint coordinates */
6468     for (f = fStart; f < fMax; ++f) {
6469       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6470       const PetscInt *cone;
6471       PetscInt        coneSize, offA, offB, offnew, d;
6472 
6473       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6474       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6475       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6476       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6477       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6478       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6479       for (d = 0; d < dim; ++d) {
6480         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6481       }
6482     }
6483     /* Just Hex 2D */
6484     if (refiner == 2) {
6485       /* Cell vertices have the average of corner coordinates */
6486       for (c = cStart; c < cEnd; ++c) {
6487         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6488         PetscInt      *cone = NULL;
6489         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6490 
6491         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6492         for (p = 0; p < closureSize*2; p += 2) {
6493           const PetscInt point = cone[p];
6494           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6495         }
6496         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6497         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6498         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6499         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6500         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6501         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6502         for (d = 0; d < dim; ++d) {
6503           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6504         }
6505         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6506       }
6507     }
6508     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6509     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6510     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6511     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6512     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6513     break;
6514   default:
6515     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6516   }
6517   PetscFunctionReturn(0);
6518 }
6519 
6520 #undef __FUNCT__
6521 #define __FUNCT__ "DMPlexCreateProcessSF"
6522 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6523 {
6524   PetscInt           numRoots, numLeaves, l;
6525   const PetscInt    *localPoints;
6526   const PetscSFNode *remotePoints;
6527   PetscInt          *localPointsNew;
6528   PetscSFNode       *remotePointsNew;
6529   PetscInt          *ranks, *ranksNew;
6530   PetscErrorCode     ierr;
6531 
6532   PetscFunctionBegin;
6533   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6534   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6535   for (l = 0; l < numLeaves; ++l) {
6536     ranks[l] = remotePoints[l].rank;
6537   }
6538   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6539   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6540   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6541   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6542   for (l = 0; l < numLeaves; ++l) {
6543     ranksNew[l]              = ranks[l];
6544     localPointsNew[l]        = l;
6545     remotePointsNew[l].index = 0;
6546     remotePointsNew[l].rank  = ranksNew[l];
6547   }
6548   ierr = PetscFree(ranks);CHKERRQ(ierr);
6549   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6550   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
6551   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6552   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6553   PetscFunctionReturn(0);
6554 }
6555 
6556 #undef __FUNCT__
6557 #define __FUNCT__ "CellRefinerCreateSF"
6558 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6559 {
6560   PetscSF            sf, sfNew, sfProcess;
6561   IS                 processRanks;
6562   MPI_Datatype       depthType;
6563   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6564   const PetscInt    *localPoints, *neighbors;
6565   const PetscSFNode *remotePoints;
6566   PetscInt          *localPointsNew;
6567   PetscSFNode       *remotePointsNew;
6568   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6569   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6570   PetscErrorCode     ierr;
6571 
6572   PetscFunctionBegin;
6573   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6574   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6575   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6576   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6577   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6578   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6579   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6580   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6581   switch (refiner) {
6582   case 3:
6583     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6584     cMax = PetscMin(cEnd, cMax);
6585     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6586     fMax = PetscMin(fEnd, fMax);
6587   }
6588   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6589   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6590   /* Caculate size of new SF */
6591   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6592   if (numRoots < 0) PetscFunctionReturn(0);
6593   for (l = 0; l < numLeaves; ++l) {
6594     const PetscInt p = localPoints[l];
6595 
6596     switch (refiner) {
6597     case 1:
6598       /* Simplicial 2D */
6599       if ((p >= vStart) && (p < vEnd)) {
6600         /* Old vertices stay the same */
6601         ++numLeavesNew;
6602       } else if ((p >= fStart) && (p < fEnd)) {
6603         /* Old faces add new faces and vertex */
6604         numLeavesNew += 1 + 2;
6605       } else if ((p >= cStart) && (p < cEnd)) {
6606         /* Old cells add new cells and interior faces */
6607         numLeavesNew += 4 + 3;
6608       }
6609       break;
6610     case 2:
6611       /* Hex 2D */
6612       if ((p >= vStart) && (p < vEnd)) {
6613         /* Old vertices stay the same */
6614         ++numLeavesNew;
6615       } else if ((p >= fStart) && (p < fEnd)) {
6616         /* Old faces add new faces and vertex */
6617         numLeavesNew += 1 + 2;
6618       } else if ((p >= cStart) && (p < cEnd)) {
6619         /* Old cells add new cells and interior faces */
6620         numLeavesNew += 4 + 4;
6621       }
6622       break;
6623     default:
6624       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6625     }
6626   }
6627   /* Communicate depthSizes for each remote rank */
6628   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6629   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6630   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6631   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);
6632   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6633   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6634   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6635   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6636   for (n = 0; n < numNeighbors; ++n) {
6637     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6638   }
6639   depthSizeOld[depth]   = cMax;
6640   depthSizeOld[0]       = vMax;
6641   depthSizeOld[depth-1] = fMax;
6642   depthSizeOld[1]       = eMax;
6643 
6644   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6645   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6646 
6647   depthSizeOld[depth]   = cEnd - cStart;
6648   depthSizeOld[0]       = vEnd - vStart;
6649   depthSizeOld[depth-1] = fEnd - fStart;
6650   depthSizeOld[1]       = eEnd - eStart;
6651 
6652   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6653   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6654   for (n = 0; n < numNeighbors; ++n) {
6655     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6656   }
6657   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6658   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6659   /* Calculate new point SF */
6660   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6661   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6662   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6663   for (l = 0, m = 0; l < numLeaves; ++l) {
6664     PetscInt    p     = localPoints[l];
6665     PetscInt    rp    = remotePoints[l].index, n;
6666     PetscMPIInt rrank = remotePoints[l].rank;
6667 
6668     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6669     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6670     switch (refiner) {
6671     case 1:
6672       /* Simplicial 2D */
6673       if ((p >= vStart) && (p < vEnd)) {
6674         /* Old vertices stay the same */
6675         localPointsNew[m]        = vStartNew     + (p  - vStart);
6676         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6677         remotePointsNew[m].rank  = rrank;
6678         ++m;
6679       } else if ((p >= fStart) && (p < fEnd)) {
6680         /* Old faces add new faces and vertex */
6681         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6682         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6683         remotePointsNew[m].rank  = rrank;
6684         ++m;
6685         for (r = 0; r < 2; ++r, ++m) {
6686           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6687           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6688           remotePointsNew[m].rank  = rrank;
6689         }
6690       } else if ((p >= cStart) && (p < cEnd)) {
6691         /* Old cells add new cells and interior faces */
6692         for (r = 0; r < 4; ++r, ++m) {
6693           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6694           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6695           remotePointsNew[m].rank  = rrank;
6696         }
6697         for (r = 0; r < 3; ++r, ++m) {
6698           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6699           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6700           remotePointsNew[m].rank  = rrank;
6701         }
6702       }
6703       break;
6704     case 2:
6705       /* Hex 2D */
6706       if ((p >= vStart) && (p < vEnd)) {
6707         /* Old vertices stay the same */
6708         localPointsNew[m]        = vStartNew     + (p  - vStart);
6709         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6710         remotePointsNew[m].rank  = rrank;
6711         ++m;
6712       } else if ((p >= fStart) && (p < fEnd)) {
6713         /* Old faces add new faces and vertex */
6714         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6715         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6716         remotePointsNew[m].rank  = rrank;
6717         ++m;
6718         for (r = 0; r < 2; ++r, ++m) {
6719           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6720           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6721           remotePointsNew[m].rank  = rrank;
6722         }
6723       } else if ((p >= cStart) && (p < cEnd)) {
6724         /* Old cells add new cells and interior faces */
6725         for (r = 0; r < 4; ++r, ++m) {
6726           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6727           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6728           remotePointsNew[m].rank  = rrank;
6729         }
6730         for (r = 0; r < 4; ++r, ++m) {
6731           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6732           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6733           remotePointsNew[m].rank  = rrank;
6734         }
6735       }
6736       break;
6737     case 3:
6738       /* Hybrid simplicial 2D */
6739       if ((p >= vStart) && (p < vEnd)) {
6740         /* Old vertices stay the same */
6741         localPointsNew[m]        = vStartNew     + (p  - vStart);
6742         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6743         remotePointsNew[m].rank  = rrank;
6744         ++m;
6745       } else if ((p >= fStart) && (p < fMax)) {
6746         /* Old interior faces add new faces and vertex */
6747         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6748         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6749         remotePointsNew[m].rank  = rrank;
6750         ++m;
6751         for (r = 0; r < 2; ++r, ++m) {
6752           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6753           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6754           remotePointsNew[m].rank  = rrank;
6755         }
6756       } else if ((p >= fMax) && (p < fEnd)) {
6757         /* Old hybrid faces stay the same */
6758         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6759         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6760         remotePointsNew[m].rank  = rrank;
6761         ++m;
6762       } else if ((p >= cStart) && (p < cMax)) {
6763         /* Old interior cells add new cells and interior faces */
6764         for (r = 0; r < 4; ++r, ++m) {
6765           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6766           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6767           remotePointsNew[m].rank  = rrank;
6768         }
6769         for (r = 0; r < 3; ++r, ++m) {
6770           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6771           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6772           remotePointsNew[m].rank  = rrank;
6773         }
6774       } else if ((p >= cStart) && (p < cMax)) {
6775         /* Old hybrid cells add new cells and hybrid face */
6776         for (r = 0; r < 2; ++r, ++m) {
6777           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6778           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6779           remotePointsNew[m].rank  = rrank;
6780         }
6781         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6782         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]);
6783         remotePointsNew[m].rank  = rrank;
6784         ++m;
6785       }
6786       break;
6787     default:
6788       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6789     }
6790   }
6791   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6792   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6793   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6794   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6795   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6796   PetscFunctionReturn(0);
6797 }
6798 
6799 #undef __FUNCT__
6800 #define __FUNCT__ "CellRefinerCreateLabels"
6801 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6802 {
6803   PetscInt       numLabels, l;
6804   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6805   PetscErrorCode ierr;
6806 
6807   PetscFunctionBegin;
6808   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6809   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6810   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6811   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6812 
6813   cStartNew = 0;
6814   vStartNew = depthSize[2];
6815   fStartNew = depthSize[2] + depthSize[0];
6816 
6817   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6818   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6819   switch (refiner) {
6820   case 3:
6821     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6822     cMax = PetscMin(cEnd, cMax);
6823     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6824     fMax = PetscMin(fEnd, fMax);
6825   }
6826   for (l = 0; l < numLabels; ++l) {
6827     DMLabel         label, labelNew;
6828     const char     *lname;
6829     PetscBool       isDepth;
6830     IS              valueIS;
6831     const PetscInt *values;
6832     PetscInt        numValues, val;
6833 
6834     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6835     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6836     if (isDepth) continue;
6837     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6838     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6839     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6840     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6841     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6842     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6843     for (val = 0; val < numValues; ++val) {
6844       IS              pointIS;
6845       const PetscInt *points;
6846       PetscInt        numPoints, n;
6847 
6848       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6849       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6850       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6851       for (n = 0; n < numPoints; ++n) {
6852         const PetscInt p = points[n];
6853         switch (refiner) {
6854         case 1:
6855           /* Simplicial 2D */
6856           if ((p >= vStart) && (p < vEnd)) {
6857             /* Old vertices stay the same */
6858             newp = vStartNew + (p - vStart);
6859             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6860           } else if ((p >= fStart) && (p < fEnd)) {
6861             /* Old faces add new faces and vertex */
6862             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6863             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6864             for (r = 0; r < 2; ++r) {
6865               newp = fStartNew + (p - fStart)*2 + r;
6866               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6867             }
6868           } else if ((p >= cStart) && (p < cEnd)) {
6869             /* Old cells add new cells and interior faces */
6870             for (r = 0; r < 4; ++r) {
6871               newp = cStartNew + (p - cStart)*4 + r;
6872               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6873             }
6874             for (r = 0; r < 3; ++r) {
6875               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6876               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6877             }
6878           }
6879           break;
6880         case 2:
6881           /* Hex 2D */
6882           if ((p >= vStart) && (p < vEnd)) {
6883             /* Old vertices stay the same */
6884             newp = vStartNew + (p - vStart);
6885             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6886           } else if ((p >= fStart) && (p < fEnd)) {
6887             /* Old faces add new faces and vertex */
6888             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6889             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6890             for (r = 0; r < 2; ++r) {
6891               newp = fStartNew + (p - fStart)*2 + r;
6892               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6893             }
6894           } else if ((p >= cStart) && (p < cEnd)) {
6895             /* Old cells add new cells and interior faces and vertex */
6896             for (r = 0; r < 4; ++r) {
6897               newp = cStartNew + (p - cStart)*4 + r;
6898               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6899             }
6900             for (r = 0; r < 4; ++r) {
6901               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6902               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6903             }
6904             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6905             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6906           }
6907           break;
6908         case 3:
6909           /* Hybrid simplicial 2D */
6910           if ((p >= vStart) && (p < vEnd)) {
6911             /* Old vertices stay the same */
6912             newp = vStartNew + (p - vStart);
6913             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6914           } else if ((p >= fStart) && (p < fMax)) {
6915             /* Old interior faces add new faces and vertex */
6916             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6917             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6918             for (r = 0; r < 2; ++r) {
6919               newp = fStartNew + (p - fStart)*2 + r;
6920               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6921             }
6922           } else if ((p >= fMax) && (p < fEnd)) {
6923             /* Old hybrid faces stay the same */
6924             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6925             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6926           } else if ((p >= cStart) && (p < cMax)) {
6927             /* Old interior cells add new cells and interior faces */
6928             for (r = 0; r < 4; ++r) {
6929               newp = cStartNew + (p - cStart)*4 + r;
6930               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6931             }
6932             for (r = 0; r < 3; ++r) {
6933               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6934               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6935             }
6936           } else if ((p >= cMax) && (p < cEnd)) {
6937             /* Old hybrid cells add new cells and hybrid face */
6938             for (r = 0; r < 2; ++r) {
6939               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6940               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6941             }
6942             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6943             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6944           }
6945           break;
6946         default:
6947           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6948         }
6949       }
6950       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6951       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6952     }
6953     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6954     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6955     if (0) {
6956       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6957       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6958       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6959     }
6960   }
6961   PetscFunctionReturn(0);
6962 }
6963 
6964 #undef __FUNCT__
6965 #define __FUNCT__ "DMPlexRefine_Uniform"
6966 /* This will only work for interpolated meshes */
6967 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6968 {
6969   DM             rdm;
6970   PetscInt      *depthSize;
6971   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6972   PetscErrorCode ierr;
6973 
6974   PetscFunctionBegin;
6975   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6976   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6977   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6978   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6979   /* Calculate number of new points of each depth */
6980   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6981   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
6982   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6983   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6984   /* Step 1: Set chart */
6985   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6986   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6987   /* Step 2: Set cone/support sizes */
6988   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6989   /* Step 3: Setup refined DM */
6990   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6991   /* Step 4: Set cones and supports */
6992   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6993   /* Step 5: Stratify */
6994   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6995   /* Step 6: Set coordinates for vertices */
6996   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6997   /* Step 7: Create pointSF */
6998   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6999   /* Step 8: Create labels */
7000   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7001   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7002 
7003   *dmRefined = rdm;
7004   PetscFunctionReturn(0);
7005 }
7006 
7007 #undef __FUNCT__
7008 #define __FUNCT__ "DMPlexSetRefinementUniform"
7009 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7010 {
7011   DM_Plex *mesh = (DM_Plex*) dm->data;
7012 
7013   PetscFunctionBegin;
7014   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7015   mesh->refinementUniform = refinementUniform;
7016   PetscFunctionReturn(0);
7017 }
7018 
7019 #undef __FUNCT__
7020 #define __FUNCT__ "DMPlexGetRefinementUniform"
7021 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7022 {
7023   DM_Plex *mesh = (DM_Plex*) dm->data;
7024 
7025   PetscFunctionBegin;
7026   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7027   PetscValidPointer(refinementUniform,  2);
7028   *refinementUniform = mesh->refinementUniform;
7029   PetscFunctionReturn(0);
7030 }
7031 
7032 #undef __FUNCT__
7033 #define __FUNCT__ "DMPlexSetRefinementLimit"
7034 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7035 {
7036   DM_Plex *mesh = (DM_Plex*) dm->data;
7037 
7038   PetscFunctionBegin;
7039   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7040   mesh->refinementLimit = refinementLimit;
7041   PetscFunctionReturn(0);
7042 }
7043 
7044 #undef __FUNCT__
7045 #define __FUNCT__ "DMPlexGetRefinementLimit"
7046 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7047 {
7048   DM_Plex *mesh = (DM_Plex*) dm->data;
7049 
7050   PetscFunctionBegin;
7051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7052   PetscValidPointer(refinementLimit,  2);
7053   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7054   *refinementLimit = mesh->refinementLimit;
7055   PetscFunctionReturn(0);
7056 }
7057 
7058 #undef __FUNCT__
7059 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7060 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7061 {
7062   PetscInt       dim, cStart, coneSize, cMax;
7063   PetscErrorCode ierr;
7064 
7065   PetscFunctionBegin;
7066   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7067   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7068   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7069   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7070   switch (dim) {
7071   case 2:
7072     switch (coneSize) {
7073     case 3:
7074       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7075       else *cellRefiner = 1; /* Triangular */
7076       break;
7077     case 4:
7078       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7079       else *cellRefiner = 2; /* Quadrilateral */
7080       break;
7081     default:
7082       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7083     }
7084     break;
7085   default:
7086     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7087   }
7088   PetscFunctionReturn(0);
7089 }
7090 
7091 #undef __FUNCT__
7092 #define __FUNCT__ "DMRefine_Plex"
7093 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7094 {
7095   PetscReal      refinementLimit;
7096   PetscInt       dim, cStart, cEnd;
7097   char           genname[1024], *name = NULL;
7098   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7099   PetscErrorCode ierr;
7100 
7101   PetscFunctionBegin;
7102   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7103   if (isUniform) {
7104     CellRefiner cellRefiner;
7105 
7106     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7107     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7108     PetscFunctionReturn(0);
7109   }
7110   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7111   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7112   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7113   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7114   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7115   if (flg) name = genname;
7116   if (name) {
7117     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7118     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7119     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7120   }
7121   switch (dim) {
7122   case 2:
7123     if (!name || isTriangle) {
7124 #if defined(PETSC_HAVE_TRIANGLE)
7125       double  *maxVolumes;
7126       PetscInt c;
7127 
7128       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7129       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7130       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7131 #else
7132       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7133 #endif
7134     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7135     break;
7136   case 3:
7137     if (!name || isCTetgen) {
7138 #if defined(PETSC_HAVE_CTETGEN)
7139       PetscReal *maxVolumes;
7140       PetscInt   c;
7141 
7142       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7143       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7144       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7145 #else
7146       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7147 #endif
7148     } else if (isTetgen) {
7149 #if defined(PETSC_HAVE_TETGEN)
7150       double  *maxVolumes;
7151       PetscInt c;
7152 
7153       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7154       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7155       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7156 #else
7157       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7158 #endif
7159     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7160     break;
7161   default:
7162     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7163   }
7164   PetscFunctionReturn(0);
7165 }
7166 
7167 #undef __FUNCT__
7168 #define __FUNCT__ "DMPlexGetDepth"
7169 /*@
7170   DMPlexGetDepth - get the number of strata
7171 
7172   Not Collective
7173 
7174   Input Parameters:
7175 . dm           - The DMPlex object
7176 
7177   Output Parameters:
7178 . depth - number of strata
7179 
7180   Level: developer
7181 
7182   Notes:
7183   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7184 
7185 .keywords: mesh, points
7186 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7187 @*/
7188 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7189 {
7190   PetscInt       d;
7191   PetscErrorCode ierr;
7192 
7193   PetscFunctionBegin;
7194   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7195   PetscValidPointer(depth, 2);
7196   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7197   *depth = d-1;
7198   PetscFunctionReturn(0);
7199 }
7200 
7201 #undef __FUNCT__
7202 #define __FUNCT__ "DMPlexGetDepthStratum"
7203 /*@
7204   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7205 
7206   Not Collective
7207 
7208   Input Parameters:
7209 + dm           - The DMPlex object
7210 - stratumValue - The requested depth
7211 
7212   Output Parameters:
7213 + start - The first point at this depth
7214 - end   - One beyond the last point at this depth
7215 
7216   Level: developer
7217 
7218 .keywords: mesh, points
7219 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7220 @*/
7221 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7222 {
7223   DM_Plex       *mesh = (DM_Plex*) dm->data;
7224   DMLabel        next  = mesh->labels;
7225   PetscBool      flg   = PETSC_FALSE;
7226   PetscInt       depth;
7227   PetscErrorCode ierr;
7228 
7229   PetscFunctionBegin;
7230   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7231   if (stratumValue < 0) {
7232     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7233     PetscFunctionReturn(0);
7234   } else {
7235     PetscInt pStart, pEnd;
7236 
7237     if (start) *start = 0;
7238     if (end)   *end   = 0;
7239     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7240     if (pStart == pEnd) PetscFunctionReturn(0);
7241   }
7242   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7243   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7244   /* We should have a generic GetLabel() and a Label class */
7245   while (next) {
7246     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7247     if (flg) break;
7248     next = next->next;
7249   }
7250   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7251   depth = stratumValue;
7252   if ((depth < 0) || (depth >= next->numStrata)) {
7253     if (start) *start = 0;
7254     if (end)   *end   = 0;
7255   } else {
7256     if (start) *start = next->points[next->stratumOffsets[depth]];
7257     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7258   }
7259   PetscFunctionReturn(0);
7260 }
7261 
7262 #undef __FUNCT__
7263 #define __FUNCT__ "DMPlexGetHeightStratum"
7264 /*@
7265   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7266 
7267   Not Collective
7268 
7269   Input Parameters:
7270 + dm           - The DMPlex object
7271 - stratumValue - The requested height
7272 
7273   Output Parameters:
7274 + start - The first point at this height
7275 - end   - One beyond the last point at this height
7276 
7277   Level: developer
7278 
7279 .keywords: mesh, points
7280 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7281 @*/
7282 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7283 {
7284   DM_Plex       *mesh = (DM_Plex*) dm->data;
7285   DMLabel        next  = mesh->labels;
7286   PetscBool      flg   = PETSC_FALSE;
7287   PetscInt       depth;
7288   PetscErrorCode ierr;
7289 
7290   PetscFunctionBegin;
7291   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7292   if (stratumValue < 0) {
7293     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7294   } else {
7295     PetscInt pStart, pEnd;
7296 
7297     if (start) *start = 0;
7298     if (end)   *end   = 0;
7299     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7300     if (pStart == pEnd) PetscFunctionReturn(0);
7301   }
7302   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7303   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7304   /* We should have a generic GetLabel() and a Label class */
7305   while (next) {
7306     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7307     if (flg) break;
7308     next = next->next;
7309   }
7310   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7311   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7312   if ((depth < 0) || (depth >= next->numStrata)) {
7313     if (start) *start = 0;
7314     if (end)   *end   = 0;
7315   } else {
7316     if (start) *start = next->points[next->stratumOffsets[depth]];
7317     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7318   }
7319   PetscFunctionReturn(0);
7320 }
7321 
7322 #undef __FUNCT__
7323 #define __FUNCT__ "DMPlexCreateSectionInitial"
7324 /* Set the number of dof on each point and separate by fields */
7325 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7326 {
7327   PetscInt      *numDofTot;
7328   PetscInt       pStart = 0, pEnd = 0;
7329   PetscInt       p, d, f;
7330   PetscErrorCode ierr;
7331 
7332   PetscFunctionBegin;
7333   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7334   for (d = 0; d <= dim; ++d) {
7335     numDofTot[d] = 0;
7336     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7337   }
7338   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7339   if (numFields > 0) {
7340     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7341     if (numComp) {
7342       for (f = 0; f < numFields; ++f) {
7343         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7344       }
7345     }
7346   }
7347   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7348   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7349   for (d = 0; d <= dim; ++d) {
7350     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7351     for (p = pStart; p < pEnd; ++p) {
7352       for (f = 0; f < numFields; ++f) {
7353         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7354       }
7355       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7356     }
7357   }
7358   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7359   PetscFunctionReturn(0);
7360 }
7361 
7362 #undef __FUNCT__
7363 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7364 /* Set the number of dof on each point and separate by fields
7365    If constDof is PETSC_DETERMINE, constrain every dof on the point
7366 */
7367 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7368 {
7369   PetscInt       numFields;
7370   PetscInt       bc;
7371   PetscErrorCode ierr;
7372 
7373   PetscFunctionBegin;
7374   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7375   for (bc = 0; bc < numBC; ++bc) {
7376     PetscInt        field = 0;
7377     const PetscInt *idx;
7378     PetscInt        n, i;
7379 
7380     if (numFields) field = bcField[bc];
7381     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7382     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7383     for (i = 0; i < n; ++i) {
7384       const PetscInt p        = idx[i];
7385       PetscInt       numConst = constDof;
7386 
7387       /* Constrain every dof on the point */
7388       if (numConst < 0) {
7389         if (numFields) {
7390           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7391         } else {
7392           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7393         }
7394       }
7395       if (numFields) {
7396         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7397       }
7398       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7399     }
7400     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7401   }
7402   PetscFunctionReturn(0);
7403 }
7404 
7405 #undef __FUNCT__
7406 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7407 /* Set the constrained indices on each point and separate by fields */
7408 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7409 {
7410   PetscInt      *maxConstraints;
7411   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7412   PetscErrorCode ierr;
7413 
7414   PetscFunctionBegin;
7415   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7416   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7417   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7418   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7419   for (p = pStart; p < pEnd; ++p) {
7420     PetscInt cdof;
7421 
7422     if (numFields) {
7423       for (f = 0; f < numFields; ++f) {
7424         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7425         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7426       }
7427     } else {
7428       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7429       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7430     }
7431   }
7432   for (f = 0; f < numFields; ++f) {
7433     maxConstraints[numFields] += maxConstraints[f];
7434   }
7435   if (maxConstraints[numFields]) {
7436     PetscInt *indices;
7437 
7438     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7439     for (p = pStart; p < pEnd; ++p) {
7440       PetscInt cdof, d;
7441 
7442       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7443       if (cdof) {
7444         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7445         if (numFields) {
7446           PetscInt numConst = 0, foff = 0;
7447 
7448           for (f = 0; f < numFields; ++f) {
7449             PetscInt cfdof, fdof;
7450 
7451             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7452             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7453             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7454             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7455             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7456             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7457             numConst += cfdof;
7458             foff     += fdof;
7459           }
7460           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7461         } else {
7462           for (d = 0; d < cdof; ++d) indices[d] = d;
7463         }
7464         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7465       }
7466     }
7467     ierr = PetscFree(indices);CHKERRQ(ierr);
7468   }
7469   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7470   PetscFunctionReturn(0);
7471 }
7472 
7473 #undef __FUNCT__
7474 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7475 /* Set the constrained field indices on each point */
7476 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7477 {
7478   const PetscInt *points, *indices;
7479   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7480   PetscErrorCode  ierr;
7481 
7482   PetscFunctionBegin;
7483   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7484   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7485 
7486   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7487   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7488   if (!constraintIndices) {
7489     PetscInt *idx, i;
7490 
7491     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7492     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7493     for (i = 0; i < maxDof; ++i) idx[i] = i;
7494     for (p = 0; p < numPoints; ++p) {
7495       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7496     }
7497     ierr = PetscFree(idx);CHKERRQ(ierr);
7498   } else {
7499     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7500     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7501     for (p = 0; p < numPoints; ++p) {
7502       PetscInt fcdof;
7503 
7504       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7505       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);
7506       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7507     }
7508     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7509   }
7510   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7511   PetscFunctionReturn(0);
7512 }
7513 
7514 #undef __FUNCT__
7515 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7516 /* Set the constrained indices on each point and separate by fields */
7517 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7518 {
7519   PetscInt      *indices;
7520   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7521   PetscErrorCode ierr;
7522 
7523   PetscFunctionBegin;
7524   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7525   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7526   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7527   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7528   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7529   for (p = pStart; p < pEnd; ++p) {
7530     PetscInt cdof, d;
7531 
7532     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7533     if (cdof) {
7534       PetscInt numConst = 0, foff = 0;
7535 
7536       for (f = 0; f < numFields; ++f) {
7537         const PetscInt *fcind;
7538         PetscInt        fdof, fcdof;
7539 
7540         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7541         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7542         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7543         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7544         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
7545         foff     += fdof;
7546         numConst += fcdof;
7547       }
7548       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7549       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7550     }
7551   }
7552   ierr = PetscFree(indices);CHKERRQ(ierr);
7553   PetscFunctionReturn(0);
7554 }
7555 
7556 #undef __FUNCT__
7557 #define __FUNCT__ "DMPlexCreateSection"
7558 /*@C
7559   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7560 
7561   Not Collective
7562 
7563   Input Parameters:
7564 + dm        - The DMPlex object
7565 . dim       - The spatial dimension of the problem
7566 . numFields - The number of fields in the problem
7567 . numComp   - An array of size numFields that holds the number of components for each field
7568 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7569 . numBC     - The number of boundary conditions
7570 . bcField   - An array of size numBC giving the field number for each boundry condition
7571 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7572 
7573   Output Parameter:
7574 . section - The PetscSection object
7575 
7576   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
7577   nubmer of dof for field 0 on each edge.
7578 
7579   Level: developer
7580 
7581 .keywords: mesh, elements
7582 .seealso: DMPlexCreate(), PetscSectionCreate()
7583 @*/
7584 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
7585 {
7586   PetscErrorCode ierr;
7587 
7588   PetscFunctionBegin;
7589   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7590   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7591   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7592   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7593   {
7594     PetscBool view = PETSC_FALSE;
7595 
7596     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7597     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7598   }
7599   PetscFunctionReturn(0);
7600 }
7601 
7602 #undef __FUNCT__
7603 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7604 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
7605 {
7606   PetscSection   section;
7607   PetscErrorCode ierr;
7608 
7609   PetscFunctionBegin;
7610   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7611   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7612   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7613   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7614   PetscFunctionReturn(0);
7615 }
7616 
7617 #undef __FUNCT__
7618 #define __FUNCT__ "DMPlexGetCoordinateSection"
7619 /*@
7620   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7621 
7622   Not Collective
7623 
7624   Input Parameter:
7625 . dm - The DMPlex object
7626 
7627   Output Parameter:
7628 . section - The PetscSection object
7629 
7630   Level: intermediate
7631 
7632 .keywords: mesh, coordinates
7633 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7634 @*/
7635 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
7636 {
7637   DM             cdm;
7638   PetscErrorCode ierr;
7639 
7640   PetscFunctionBegin;
7641   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7642   PetscValidPointer(section, 2);
7643   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7644   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7645   PetscFunctionReturn(0);
7646 }
7647 
7648 #undef __FUNCT__
7649 #define __FUNCT__ "DMPlexSetCoordinateSection"
7650 /*@
7651   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7652 
7653   Not Collective
7654 
7655   Input Parameters:
7656 + dm      - The DMPlex object
7657 - section - The PetscSection object
7658 
7659   Level: intermediate
7660 
7661 .keywords: mesh, coordinates
7662 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7663 @*/
7664 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
7665 {
7666   DM             cdm;
7667   PetscErrorCode ierr;
7668 
7669   PetscFunctionBegin;
7670   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7671   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
7672   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7673   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7674   PetscFunctionReturn(0);
7675 }
7676 
7677 #undef __FUNCT__
7678 #define __FUNCT__ "DMPlexGetConeSection"
7679 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
7680 {
7681   DM_Plex *mesh = (DM_Plex*) dm->data;
7682 
7683   PetscFunctionBegin;
7684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7685   if (section) *section = mesh->coneSection;
7686   PetscFunctionReturn(0);
7687 }
7688 
7689 #undef __FUNCT__
7690 #define __FUNCT__ "DMPlexGetCones"
7691 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
7692 {
7693   DM_Plex *mesh = (DM_Plex*) dm->data;
7694 
7695   PetscFunctionBegin;
7696   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7697   if (cones) *cones = mesh->cones;
7698   PetscFunctionReturn(0);
7699 }
7700 
7701 #undef __FUNCT__
7702 #define __FUNCT__ "DMPlexGetConeOrientations"
7703 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
7704 {
7705   DM_Plex *mesh = (DM_Plex*) dm->data;
7706 
7707   PetscFunctionBegin;
7708   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7709   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7710   PetscFunctionReturn(0);
7711 }
7712 
7713 #undef __FUNCT__
7714 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7715 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7716 {
7717   const PetscInt embedDim = 2;
7718   PetscReal      x        = PetscRealPart(point[0]);
7719   PetscReal      y        = PetscRealPart(point[1]);
7720   PetscReal      v0[2], J[4], invJ[4], detJ;
7721   PetscReal      xi, eta;
7722   PetscErrorCode ierr;
7723 
7724   PetscFunctionBegin;
7725   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7726   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7727   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7728 
7729   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
7730   else *cell = -1;
7731   PetscFunctionReturn(0);
7732 }
7733 
7734 #undef __FUNCT__
7735 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7736 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7737 {
7738   PetscSection       coordSection;
7739   Vec                coordsLocal;
7740   const PetscScalar *coords;
7741   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7742   PetscReal          x         = PetscRealPart(point[0]);
7743   PetscReal          y         = PetscRealPart(point[1]);
7744   PetscInt           crossings = 0, f;
7745   PetscErrorCode     ierr;
7746 
7747   PetscFunctionBegin;
7748   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7749   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7750   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7751   for (f = 0; f < 4; ++f) {
7752     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7753     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7754     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7755     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7756     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7757     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7758     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7759     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7760     if ((cond1 || cond2)  && above) ++crossings;
7761   }
7762   if (crossings % 2) *cell = c;
7763   else *cell = -1;
7764   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7765   PetscFunctionReturn(0);
7766 }
7767 
7768 #undef __FUNCT__
7769 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7770 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7771 {
7772   const PetscInt embedDim = 3;
7773   PetscReal      v0[3], J[9], invJ[9], detJ;
7774   PetscReal      x = PetscRealPart(point[0]);
7775   PetscReal      y = PetscRealPart(point[1]);
7776   PetscReal      z = PetscRealPart(point[2]);
7777   PetscReal      xi, eta, zeta;
7778   PetscErrorCode ierr;
7779 
7780   PetscFunctionBegin;
7781   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7782   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7783   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7784   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7785 
7786   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
7787   else *cell = -1;
7788   PetscFunctionReturn(0);
7789 }
7790 
7791 #undef __FUNCT__
7792 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7793 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7794 {
7795   PetscSection       coordSection;
7796   Vec                coordsLocal;
7797   const PetscScalar *coords;
7798   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7799                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7800   PetscBool          found = PETSC_TRUE;
7801   PetscInt           f;
7802   PetscErrorCode     ierr;
7803 
7804   PetscFunctionBegin;
7805   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7806   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7807   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7808   for (f = 0; f < 6; ++f) {
7809     /* Check the point is under plane */
7810     /*   Get face normal */
7811     PetscReal v_i[3];
7812     PetscReal v_j[3];
7813     PetscReal normal[3];
7814     PetscReal pp[3];
7815     PetscReal dot;
7816 
7817     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
7818     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
7819     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
7820     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
7821     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
7822     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
7823     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
7824     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
7825     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
7826     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
7827     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
7828     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
7829     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7830 
7831     /* Check that projected point is in face (2D location problem) */
7832     if (dot < 0.0) {
7833       found = PETSC_FALSE;
7834       break;
7835     }
7836   }
7837   if (found) *cell = c;
7838   else *cell = -1;
7839   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7840   PetscFunctionReturn(0);
7841 }
7842 
7843 #undef __FUNCT__
7844 #define __FUNCT__ "DMLocatePoints_Plex"
7845 /*
7846  Need to implement using the guess
7847 */
7848 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7849 {
7850   PetscInt       cell = -1 /*, guess = -1*/;
7851   PetscInt       bs, numPoints, p;
7852   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7853   PetscInt      *cells;
7854   PetscScalar   *a;
7855   PetscErrorCode ierr;
7856 
7857   PetscFunctionBegin;
7858   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7859   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7860   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7861   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7862   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7863   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7864   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7865   if (bs != dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
7866   numPoints /= bs;
7867   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7868   for (p = 0; p < numPoints; ++p) {
7869     const PetscScalar *point = &a[p*bs];
7870 
7871     switch (dim) {
7872     case 2:
7873       for (c = cStart; c < cEnd; ++c) {
7874         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7875         switch (coneSize) {
7876         case 3:
7877           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7878           break;
7879         case 4:
7880           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7881           break;
7882         default:
7883           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7884         }
7885         if (cell >= 0) break;
7886       }
7887       break;
7888     case 3:
7889       for (c = cStart; c < cEnd; ++c) {
7890         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7891         switch (coneSize) {
7892         case 4:
7893           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
7894           break;
7895         case 8:
7896           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
7897           break;
7898         default:
7899           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7900         }
7901         if (cell >= 0) break;
7902       }
7903       break;
7904     default:
7905       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
7906     }
7907     cells[p] = cell;
7908   }
7909   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
7910   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
7911   PetscFunctionReturn(0);
7912 }
7913 
7914 /******************************** FEM Support **********************************/
7915 
7916 #undef __FUNCT__
7917 #define __FUNCT__ "DMPlexVecGetClosure"
7918 /*@C
7919   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
7920 
7921   Not collective
7922 
7923   Input Parameters:
7924 + dm - The DM
7925 . section - The section describing the layout in v, or NULL to use the default section
7926 . v - The local vector
7927 - point - The sieve point in the DM
7928 
7929   Output Parameters:
7930 + csize - The number of values in the closure, or NULL
7931 - values - The array of values, which is a borrowed array and should not be freed
7932 
7933   Level: intermediate
7934 
7935 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7936 @*/
7937 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
7938 {
7939   PetscScalar   *array, *vArray;
7940   PetscInt      *points = NULL;
7941   PetscInt       offsets[32];
7942   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
7943   PetscErrorCode ierr;
7944 
7945   PetscFunctionBegin;
7946   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7947   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7948   if (!section) {
7949     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7950   }
7951   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7952   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7953   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7954   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7955   /* Compress out points not in the section */
7956   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7957   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7958     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7959       points[q*2]   = points[p];
7960       points[q*2+1] = points[p+1];
7961       ++q;
7962     }
7963   }
7964   numPoints = q;
7965   for (p = 0, size = 0; p < numPoints*2; p += 2) {
7966     PetscInt dof, fdof;
7967 
7968     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7969     for (f = 0; f < numFields; ++f) {
7970       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7971       offsets[f+1] += fdof;
7972     }
7973     size += dof;
7974   }
7975   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7976   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
7977   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
7978   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
7979   for (p = 0; p < numPoints*2; p += 2) {
7980     PetscInt     o = points[p+1];
7981     PetscInt     dof, off, d;
7982     PetscScalar *varr;
7983 
7984     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7985     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
7986     varr = &vArray[off];
7987     if (numFields) {
7988       PetscInt fdof, foff, fcomp, f, c;
7989 
7990       for (f = 0, foff = 0; f < numFields; ++f) {
7991         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7992         if (o >= 0) {
7993           for (d = 0; d < fdof; ++d, ++offsets[f]) {
7994             array[offsets[f]] = varr[foff+d];
7995           }
7996         } else {
7997           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7998           for (d = fdof/fcomp-1; d >= 0; --d) {
7999             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8000               array[offsets[f]] = varr[foff+d*fcomp+c];
8001             }
8002           }
8003         }
8004         foff += fdof;
8005       }
8006     } else {
8007       if (o >= 0) {
8008         for (d = 0; d < dof; ++d, ++offsets[0]) {
8009           array[offsets[0]] = varr[d];
8010         }
8011       } else {
8012         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8013           array[offsets[0]] = varr[d];
8014         }
8015       }
8016     }
8017   }
8018   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8019   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8020   if (csize) *csize = size;
8021   *values = array;
8022   PetscFunctionReturn(0);
8023 }
8024 
8025 #undef __FUNCT__
8026 #define __FUNCT__ "DMPlexVecRestoreClosure"
8027 /*@C
8028   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8029 
8030   Not collective
8031 
8032   Input Parameters:
8033 + dm - The DM
8034 . section - The section describing the layout in v, or NULL to use the default section
8035 . v - The local vector
8036 . point - The sieve point in the DM
8037 . csize - The number of values in the closure, or NULL
8038 - values - The array of values, which is a borrowed array and should not be freed
8039 
8040   Level: intermediate
8041 
8042 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8043 @*/
8044 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8045 {
8046   PetscInt       size = 0;
8047   PetscErrorCode ierr;
8048 
8049   PetscFunctionBegin;
8050   /* Should work without recalculating size */
8051   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8052   PetscFunctionReturn(0);
8053 }
8054 
8055 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8056 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8057 
8058 #undef __FUNCT__
8059 #define __FUNCT__ "updatePoint_private"
8060 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8061 {
8062   PetscInt        cdof;   /* The number of constraints on this point */
8063   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8064   PetscScalar    *a;
8065   PetscInt        off, cind = 0, k;
8066   PetscErrorCode  ierr;
8067 
8068   PetscFunctionBegin;
8069   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8070   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8071   a    = &array[off];
8072   if (!cdof || setBC) {
8073     if (orientation >= 0) {
8074       for (k = 0; k < dof; ++k) {
8075         fuse(&a[k], values[k]);
8076       }
8077     } else {
8078       for (k = 0; k < dof; ++k) {
8079         fuse(&a[k], values[dof-k-1]);
8080       }
8081     }
8082   } else {
8083     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8084     if (orientation >= 0) {
8085       for (k = 0; k < dof; ++k) {
8086         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8087         fuse(&a[k], values[k]);
8088       }
8089     } else {
8090       for (k = 0; k < dof; ++k) {
8091         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8092         fuse(&a[k], values[dof-k-1]);
8093       }
8094     }
8095   }
8096   PetscFunctionReturn(0);
8097 }
8098 
8099 #undef __FUNCT__
8100 #define __FUNCT__ "updatePointFields_private"
8101 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8102 {
8103   PetscScalar   *a;
8104   PetscInt       numFields, off, foff, f;
8105   PetscErrorCode ierr;
8106 
8107   PetscFunctionBegin;
8108   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8109   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8110   a    = &array[off];
8111   for (f = 0, foff = 0; f < numFields; ++f) {
8112     PetscInt        fdof, fcomp, fcdof;
8113     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8114     PetscInt        cind = 0, k, c;
8115 
8116     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8117     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8118     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8119     if (!fcdof || setBC) {
8120       if (orientation >= 0) {
8121         for (k = 0; k < fdof; ++k) {
8122           fuse(&a[foff+k], values[foffs[f]+k]);
8123         }
8124       } else {
8125         for (k = fdof/fcomp-1; k >= 0; --k) {
8126           for (c = 0; c < fcomp; ++c) {
8127             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8128           }
8129         }
8130       }
8131     } else {
8132       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8133       if (orientation >= 0) {
8134         for (k = 0; k < fdof; ++k) {
8135           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8136           fuse(&a[foff+k], values[foffs[f]+k]);
8137         }
8138       } else {
8139         for (k = fdof/fcomp-1; k >= 0; --k) {
8140           for (c = 0; c < fcomp; ++c) {
8141             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8142             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8143           }
8144         }
8145       }
8146     }
8147     foff     += fdof;
8148     foffs[f] += fdof;
8149   }
8150   PetscFunctionReturn(0);
8151 }
8152 
8153 #undef __FUNCT__
8154 #define __FUNCT__ "DMPlexVecSetClosure"
8155 /*@C
8156   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8157 
8158   Not collective
8159 
8160   Input Parameters:
8161 + dm - The DM
8162 . section - The section describing the layout in v, or NULL to use the default sectionw
8163 . v - The local vector
8164 . point - The sieve point in the DM
8165 . values - The array of values, which is a borrowed array and should not be freed
8166 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8167 
8168   Level: intermediate
8169 
8170 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8171 @*/
8172 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8173 {
8174   PetscScalar   *array;
8175   PetscInt      *points = NULL;
8176   PetscInt       offsets[32];
8177   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8178   PetscErrorCode ierr;
8179 
8180   PetscFunctionBegin;
8181   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8182   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8183   if (!section) {
8184     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8185   }
8186   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8187   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8188   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8189   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8190   /* Compress out points not in the section */
8191   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8192   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8193     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8194       points[q*2]   = points[p];
8195       points[q*2+1] = points[p+1];
8196       ++q;
8197     }
8198   }
8199   numPoints = q;
8200   for (p = 0; p < numPoints*2; p += 2) {
8201     PetscInt fdof;
8202 
8203     for (f = 0; f < numFields; ++f) {
8204       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8205       offsets[f+1] += fdof;
8206     }
8207   }
8208   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8209   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8210   if (numFields) {
8211     switch (mode) {
8212     case INSERT_VALUES:
8213       for (p = 0; p < numPoints*2; p += 2) {
8214         PetscInt o = points[p+1];
8215         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8216       } break;
8217     case INSERT_ALL_VALUES:
8218       for (p = 0; p < numPoints*2; p += 2) {
8219         PetscInt o = points[p+1];
8220         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8221       } break;
8222     case ADD_VALUES:
8223       for (p = 0; p < numPoints*2; p += 2) {
8224         PetscInt o = points[p+1];
8225         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8226       } break;
8227     case ADD_ALL_VALUES:
8228       for (p = 0; p < numPoints*2; p += 2) {
8229         PetscInt o = points[p+1];
8230         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8231       } break;
8232     default:
8233       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8234     }
8235   } else {
8236     switch (mode) {
8237     case INSERT_VALUES:
8238       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8239         PetscInt o = points[p+1];
8240         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8241         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8242       } break;
8243     case INSERT_ALL_VALUES:
8244       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8245         PetscInt o = points[p+1];
8246         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8247         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8248       } break;
8249     case ADD_VALUES:
8250       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8251         PetscInt o = points[p+1];
8252         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8253         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8254       } break;
8255     case ADD_ALL_VALUES:
8256       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8257         PetscInt o = points[p+1];
8258         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8259         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8260       } break;
8261     default:
8262       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8263     }
8264   }
8265   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8266   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8267   PetscFunctionReturn(0);
8268 }
8269 
8270 #undef __FUNCT__
8271 #define __FUNCT__ "DMPlexPrintMatSetValues"
8272 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8273 {
8274   PetscMPIInt    rank;
8275   PetscInt       i, j;
8276   PetscErrorCode ierr;
8277 
8278   PetscFunctionBegin;
8279   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8280   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8281   for (i = 0; i < numIndices; i++) {
8282     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8283   }
8284   for (i = 0; i < numIndices; i++) {
8285     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8286     for (j = 0; j < numIndices; j++) {
8287 #if defined(PETSC_USE_COMPLEX)
8288       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8289 #else
8290       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8291 #endif
8292     }
8293     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8294   }
8295   PetscFunctionReturn(0);
8296 }
8297 
8298 #undef __FUNCT__
8299 #define __FUNCT__ "indicesPoint_private"
8300 /* . off - The global offset of this point */
8301 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8302 {
8303   PetscInt        dof;    /* The number of unknowns on this point */
8304   PetscInt        cdof;   /* The number of constraints on this point */
8305   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8306   PetscInt        cind = 0, k;
8307   PetscErrorCode  ierr;
8308 
8309   PetscFunctionBegin;
8310   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8311   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8312   if (!cdof || setBC) {
8313     if (orientation >= 0) {
8314       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8315     } else {
8316       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8317     }
8318   } else {
8319     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8320     if (orientation >= 0) {
8321       for (k = 0; k < dof; ++k) {
8322         if ((cind < cdof) && (k == cdofs[cind])) {
8323           /* Insert check for returning constrained indices */
8324           indices[*loff+k] = -(off+k+1);
8325           ++cind;
8326         } else {
8327           indices[*loff+k] = off+k-cind;
8328         }
8329       }
8330     } else {
8331       for (k = 0; k < dof; ++k) {
8332         if ((cind < cdof) && (k == cdofs[cind])) {
8333           /* Insert check for returning constrained indices */
8334           indices[*loff+dof-k-1] = -(off+k+1);
8335           ++cind;
8336         } else {
8337           indices[*loff+dof-k-1] = off+k-cind;
8338         }
8339       }
8340     }
8341   }
8342   *loff += dof;
8343   PetscFunctionReturn(0);
8344 }
8345 
8346 #undef __FUNCT__
8347 #define __FUNCT__ "indicesPointFields_private"
8348 /* . off - The global offset of this point */
8349 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8350 {
8351   PetscInt       numFields, foff, f;
8352   PetscErrorCode ierr;
8353 
8354   PetscFunctionBegin;
8355   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8356   for (f = 0, foff = 0; f < numFields; ++f) {
8357     PetscInt        fdof, fcomp, cfdof;
8358     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8359     PetscInt        cind = 0, k, c;
8360 
8361     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8362     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8363     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8364     if (!cfdof || setBC) {
8365       if (orientation >= 0) {
8366         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8367       } else {
8368         for (k = fdof/fcomp-1; k >= 0; --k) {
8369           for (c = 0; c < fcomp; ++c) {
8370             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8371           }
8372         }
8373       }
8374     } else {
8375       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8376       if (orientation >= 0) {
8377         for (k = 0; k < fdof; ++k) {
8378           if ((cind < cfdof) && (k == fcdofs[cind])) {
8379             indices[foffs[f]+k] = -(off+foff+k+1);
8380             ++cind;
8381           } else {
8382             indices[foffs[f]+k] = off+foff+k-cind;
8383           }
8384         }
8385       } else {
8386         for (k = fdof/fcomp-1; k >= 0; --k) {
8387           for (c = 0; c < fcomp; ++c) {
8388             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8389               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8390               ++cind;
8391             } else {
8392               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8393             }
8394           }
8395         }
8396       }
8397     }
8398     foff     += fdof - cfdof;
8399     foffs[f] += fdof;
8400   }
8401   PetscFunctionReturn(0);
8402 }
8403 
8404 #undef __FUNCT__
8405 #define __FUNCT__ "DMPlexMatSetClosure"
8406 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8407 {
8408   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8409   PetscInt      *points = NULL;
8410   PetscInt      *indices;
8411   PetscInt       offsets[32];
8412   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8413   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8414   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8415   PetscErrorCode ierr;
8416 
8417   PetscFunctionBegin;
8418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8419   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8420   if (useDefault) {
8421     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8422   }
8423   if (useGlobalDefault) {
8424     if (useDefault) {
8425       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8426     } else {
8427       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8428     }
8429   }
8430   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8431   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8432   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8433   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8434   /* Compress out points not in the section */
8435   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8436   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8437     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8438       points[q*2]   = points[p];
8439       points[q*2+1] = points[p+1];
8440       ++q;
8441     }
8442   }
8443   numPoints = q;
8444   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8445     PetscInt fdof;
8446 
8447     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8448     for (f = 0; f < numFields; ++f) {
8449       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8450       offsets[f+1] += fdof;
8451     }
8452     numIndices += dof;
8453   }
8454   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8455 
8456   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8457   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8458   if (numFields) {
8459     for (p = 0; p < numPoints*2; p += 2) {
8460       PetscInt o = points[p+1];
8461       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8462       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8463     }
8464   } else {
8465     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8466       PetscInt o = points[p+1];
8467       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8468       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8469     }
8470   }
8471   if (useGlobalDefault && !useDefault) {
8472     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8473   }
8474   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8475   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8476   if (ierr) {
8477     PetscMPIInt    rank;
8478     PetscErrorCode ierr2;
8479 
8480     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
8481     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8482     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8483     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8484     CHKERRQ(ierr);
8485   }
8486   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8487   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8488   PetscFunctionReturn(0);
8489 }
8490 
8491 #undef __FUNCT__
8492 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8493 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8494 {
8495   PetscSection       coordSection;
8496   Vec                coordinates;
8497   const PetscScalar *coords;
8498   const PetscInt     dim = 2;
8499   PetscInt           d, f;
8500   PetscErrorCode     ierr;
8501 
8502   PetscFunctionBegin;
8503   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8504   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8505   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8506   if (v0) {
8507     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8508   }
8509   if (J) {
8510     for (d = 0; d < dim; d++) {
8511       for (f = 0; f < dim; f++) {
8512         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8513       }
8514     }
8515     *detJ = J[0]*J[3] - J[1]*J[2];
8516 #if 0
8517     if (detJ < 0.0) {
8518       const PetscReal xLength = mesh->periodicity[0];
8519 
8520       if (xLength != 0.0) {
8521         PetscReal v0x = coords[0*dim+0];
8522 
8523         if (v0x == 0.0) v0x = v0[0] = xLength;
8524         for (f = 0; f < dim; f++) {
8525           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8526 
8527           J[0*dim+f] = 0.5*(px - v0x);
8528         }
8529       }
8530       detJ = J[0]*J[3] - J[1]*J[2];
8531     }
8532 #endif
8533     PetscLogFlops(8.0 + 3.0);
8534   }
8535   if (invJ) {
8536     const PetscReal invDet = 1.0/(*detJ);
8537 
8538     invJ[0] =  invDet*J[3];
8539     invJ[1] = -invDet*J[1];
8540     invJ[2] = -invDet*J[2];
8541     invJ[3] =  invDet*J[0];
8542     PetscLogFlops(5.0);
8543   }
8544   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8545   PetscFunctionReturn(0);
8546 }
8547 
8548 #undef __FUNCT__
8549 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8550 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8551 {
8552   PetscSection       coordSection;
8553   Vec                coordinates;
8554   const PetscScalar *coords;
8555   const PetscInt     dim = 2;
8556   PetscInt           d, f;
8557   PetscErrorCode     ierr;
8558 
8559   PetscFunctionBegin;
8560   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8561   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8562   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8563   if (v0) {
8564     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8565   }
8566   if (J) {
8567     for (d = 0; d < dim; d++) {
8568       for (f = 0; f < dim; f++) {
8569         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8570       }
8571     }
8572     *detJ = J[0]*J[3] - J[1]*J[2];
8573     PetscLogFlops(8.0 + 3.0);
8574   }
8575   if (invJ) {
8576     const PetscReal invDet = 1.0/(*detJ);
8577 
8578     invJ[0] =  invDet*J[3];
8579     invJ[1] = -invDet*J[1];
8580     invJ[2] = -invDet*J[2];
8581     invJ[3] =  invDet*J[0];
8582     PetscLogFlops(5.0);
8583   }
8584   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8585   PetscFunctionReturn(0);
8586 }
8587 
8588 #undef __FUNCT__
8589 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8590 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8591 {
8592   PetscSection       coordSection;
8593   Vec                coordinates;
8594   const PetscScalar *coords;
8595   const PetscInt     dim = 3;
8596   PetscInt           d, f;
8597   PetscErrorCode     ierr;
8598 
8599   PetscFunctionBegin;
8600   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8601   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8602   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8603   if (v0) {
8604     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8605   }
8606   if (J) {
8607     for (d = 0; d < dim; d++) {
8608       for (f = 0; f < dim; f++) {
8609         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8610       }
8611     }
8612     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8613     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8614              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8615              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8616     PetscLogFlops(18.0 + 12.0);
8617   }
8618   if (invJ) {
8619     const PetscReal invDet = 1.0/(*detJ);
8620 
8621     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8622     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8623     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8624     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8625     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8626     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8627     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8628     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8629     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8630     PetscLogFlops(37.0);
8631   }
8632   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8633   PetscFunctionReturn(0);
8634 }
8635 
8636 #undef __FUNCT__
8637 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8638 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8639 {
8640   PetscSection       coordSection;
8641   Vec                coordinates;
8642   const PetscScalar *coords;
8643   const PetscInt     dim = 3;
8644   PetscInt           d;
8645   PetscErrorCode     ierr;
8646 
8647   PetscFunctionBegin;
8648   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8649   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8650   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8651   if (v0) {
8652     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8653   }
8654   if (J) {
8655     for (d = 0; d < dim; d++) {
8656       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8657       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8658       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8659     }
8660     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8661              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8662              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8663     PetscLogFlops(18.0 + 12.0);
8664   }
8665   if (invJ) {
8666     const PetscReal invDet = -1.0/(*detJ);
8667 
8668     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8669     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8670     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8671     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8672     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8673     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8674     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8675     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8676     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8677     PetscLogFlops(37.0);
8678   }
8679   *detJ *= 8.0;
8680   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8681   PetscFunctionReturn(0);
8682 }
8683 
8684 #undef __FUNCT__
8685 #define __FUNCT__ "DMPlexComputeCellGeometry"
8686 /*@C
8687   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8688 
8689   Collective on DM
8690 
8691   Input Arguments:
8692 + dm   - the DM
8693 - cell - the cell
8694 
8695   Output Arguments:
8696 + v0   - the translation part of this affine transform
8697 . J    - the Jacobian of the transform to the reference element
8698 . invJ - the inverse of the Jacobian
8699 - detJ - the Jacobian determinant
8700 
8701   Level: advanced
8702 
8703 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8704 @*/
8705 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
8706 {
8707   PetscInt       dim, coneSize;
8708   PetscErrorCode ierr;
8709 
8710   PetscFunctionBegin;
8711   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8712   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8713   switch (dim) {
8714   case 2:
8715     switch (coneSize) {
8716     case 3:
8717       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8718       break;
8719     case 4:
8720       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8721       break;
8722     default:
8723       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8724     }
8725     break;
8726   case 3:
8727     switch (coneSize) {
8728     case 4:
8729       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8730       break;
8731     case 8:
8732       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8733       break;
8734     default:
8735       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8736     }
8737     break;
8738   default:
8739     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8740   }
8741   PetscFunctionReturn(0);
8742 }
8743 
8744 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8745 {
8746   switch (i) {
8747   case 0:
8748     switch (j) {
8749     case 0: return 0;
8750     case 1:
8751       switch (k) {
8752       case 0: return 0;
8753       case 1: return 0;
8754       case 2: return 1;
8755       }
8756     case 2:
8757       switch (k) {
8758       case 0: return 0;
8759       case 1: return -1;
8760       case 2: return 0;
8761       }
8762     }
8763   case 1:
8764     switch (j) {
8765     case 0:
8766       switch (k) {
8767       case 0: return 0;
8768       case 1: return 0;
8769       case 2: return -1;
8770       }
8771     case 1: return 0;
8772     case 2:
8773       switch (k) {
8774       case 0: return 1;
8775       case 1: return 0;
8776       case 2: return 0;
8777       }
8778     }
8779   case 2:
8780     switch (j) {
8781     case 0:
8782       switch (k) {
8783       case 0: return 0;
8784       case 1: return 1;
8785       case 2: return 0;
8786       }
8787     case 1:
8788       switch (k) {
8789       case 0: return -1;
8790       case 1: return 0;
8791       case 2: return 0;
8792       }
8793     case 2: return 0;
8794     }
8795   }
8796   return 0;
8797 }
8798 
8799 #undef __FUNCT__
8800 #define __FUNCT__ "DMPlexCreateRigidBody"
8801 /*@C
8802   DMPlexCreateRigidBody - create rigid body modes from coordinates
8803 
8804   Collective on DM
8805 
8806   Input Arguments:
8807 + dm - the DM
8808 . section - the local section associated with the rigid field, or NULL for the default section
8809 - globalSection - the global section associated with the rigid field, or NULL for the default section
8810 
8811   Output Argument:
8812 . sp - the null space
8813 
8814   Note: This is necessary to take account of Dirichlet conditions on the displacements
8815 
8816   Level: advanced
8817 
8818 .seealso: MatNullSpaceCreate()
8819 @*/
8820 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8821 {
8822   MPI_Comm       comm;
8823   Vec            coordinates, localMode, mode[6];
8824   PetscSection   coordSection;
8825   PetscScalar   *coords;
8826   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8827   PetscErrorCode ierr;
8828 
8829   PetscFunctionBegin;
8830   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
8831   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8832   if (dim == 1) {
8833     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
8834     PetscFunctionReturn(0);
8835   }
8836   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8837   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8838   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8839   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8840   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8841   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8842   m    = (dim*(dim+1))/2;
8843   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8844   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8845   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8846   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8847   /* Assume P1 */
8848   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8849   for (d = 0; d < dim; ++d) {
8850     PetscScalar values[3] = {0.0, 0.0, 0.0};
8851 
8852     values[d] = 1.0;
8853     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
8854     for (v = vStart; v < vEnd; ++v) {
8855       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8856     }
8857     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8858     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8859   }
8860   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8861   for (d = dim; d < dim*(dim+1)/2; ++d) {
8862     PetscInt i, j, k = dim > 2 ? d - dim : d;
8863 
8864     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8865     for (v = vStart; v < vEnd; ++v) {
8866       PetscScalar values[3] = {0.0, 0.0, 0.0};
8867       PetscInt    off;
8868 
8869       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8870       for (i = 0; i < dim; ++i) {
8871         for (j = 0; j < dim; ++j) {
8872           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8873         }
8874       }
8875       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8876     }
8877     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8878     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8879   }
8880   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8881   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8882   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
8883   /* Orthonormalize system */
8884   for (i = dim; i < m; ++i) {
8885     PetscScalar dots[6];
8886 
8887     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8888     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8889     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8890     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
8891   }
8892   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
8893   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
8894   PetscFunctionReturn(0);
8895 }
8896 
8897 #undef __FUNCT__
8898 #define __FUNCT__ "DMPlexGetHybridBounds"
8899 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
8900 {
8901   DM_Plex       *mesh = (DM_Plex*) dm->data;
8902   PetscInt       dim;
8903   PetscErrorCode ierr;
8904 
8905   PetscFunctionBegin;
8906   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8907   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8908   if (cMax) *cMax = mesh->hybridPointMax[dim];
8909   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
8910   if (eMax) *eMax = mesh->hybridPointMax[1];
8911   if (vMax) *vMax = mesh->hybridPointMax[0];
8912   PetscFunctionReturn(0);
8913 }
8914 
8915 #undef __FUNCT__
8916 #define __FUNCT__ "DMPlexSetHybridBounds"
8917 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
8918 {
8919   DM_Plex       *mesh = (DM_Plex*) dm->data;
8920   PetscInt       dim;
8921   PetscErrorCode ierr;
8922 
8923   PetscFunctionBegin;
8924   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8925   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8926   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
8927   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
8928   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
8929   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
8930   PetscFunctionReturn(0);
8931 }
8932 
8933 #undef __FUNCT__
8934 #define __FUNCT__ "DMPlexGetVTKCellHeight"
8935 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8936 {
8937   DM_Plex *mesh = (DM_Plex*) dm->data;
8938 
8939   PetscFunctionBegin;
8940   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8941   PetscValidPointer(cellHeight, 2);
8942   *cellHeight = mesh->vtkCellHeight;
8943   PetscFunctionReturn(0);
8944 }
8945 
8946 #undef __FUNCT__
8947 #define __FUNCT__ "DMPlexSetVTKCellHeight"
8948 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8949 {
8950   DM_Plex *mesh = (DM_Plex*) dm->data;
8951 
8952   PetscFunctionBegin;
8953   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8954   mesh->vtkCellHeight = cellHeight;
8955   PetscFunctionReturn(0);
8956 }
8957 
8958 #undef __FUNCT__
8959 #define __FUNCT__ "DMPlexCreateNumbering_Private"
8960 /* We can easily have a form that takes an IS instead */
8961 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
8962 {
8963   PetscSection   section, globalSection;
8964   PetscInt      *numbers, p;
8965   PetscErrorCode ierr;
8966 
8967   PetscFunctionBegin;
8968   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
8969   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
8970   for (p = pStart; p < pEnd; ++p) {
8971     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
8972   }
8973   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
8974   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8975   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
8976   for (p = pStart; p < pEnd; ++p) {
8977     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
8978   }
8979   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
8980   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
8981   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8982   PetscFunctionReturn(0);
8983 }
8984 
8985 #undef __FUNCT__
8986 #define __FUNCT__ "DMPlexGetCellNumbering"
8987 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8988 {
8989   DM_Plex       *mesh = (DM_Plex*) dm->data;
8990   PetscInt       cellHeight, cStart, cEnd, cMax;
8991   PetscErrorCode ierr;
8992 
8993   PetscFunctionBegin;
8994   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8995   if (!mesh->globalCellNumbers) {
8996     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8997     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8998     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8999     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9000     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9001   }
9002   *globalCellNumbers = mesh->globalCellNumbers;
9003   PetscFunctionReturn(0);
9004 }
9005 
9006 #undef __FUNCT__
9007 #define __FUNCT__ "DMPlexGetVertexNumbering"
9008 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9009 {
9010   DM_Plex       *mesh = (DM_Plex*) dm->data;
9011   PetscInt       vStart, vEnd, vMax;
9012   PetscErrorCode ierr;
9013 
9014   PetscFunctionBegin;
9015   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9016   if (!mesh->globalVertexNumbers) {
9017     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9018     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9019     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9020     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9021   }
9022   *globalVertexNumbers = mesh->globalVertexNumbers;
9023   PetscFunctionReturn(0);
9024 }
9025 
9026 #undef __FUNCT__
9027 #define __FUNCT__ "DMPlexGetScale"
9028 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9029 {
9030   DM_Plex *mesh = (DM_Plex*) dm->data;
9031 
9032   PetscFunctionBegin;
9033   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9034   PetscValidPointer(scale, 3);
9035   *scale = mesh->scale[unit];
9036   PetscFunctionReturn(0);
9037 }
9038 
9039 #undef __FUNCT__
9040 #define __FUNCT__ "DMPlexSetScale"
9041 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9042 {
9043   DM_Plex *mesh = (DM_Plex*) dm->data;
9044 
9045   PetscFunctionBegin;
9046   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9047   mesh->scale[unit] = scale;
9048   PetscFunctionReturn(0);
9049 }
9050 
9051 
9052 /*******************************************************************************
9053 This should be in a separate Discretization object, but I am not sure how to lay
9054 it out yet, so I am stuffing things here while I experiment.
9055 *******************************************************************************/
9056 #undef __FUNCT__
9057 #define __FUNCT__ "DMPlexSetFEMIntegration"
9058 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9059                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9060                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9061                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9062                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9063                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9064                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9065                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9066                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9067                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9068                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9069                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9070                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9071                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9072                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9073                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9074                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9075 {
9076   DM_Plex *mesh = (DM_Plex*) dm->data;
9077 
9078   PetscFunctionBegin;
9079   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9080   mesh->integrateResidualFEM       = integrateResidualFEM;
9081   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9082   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9083   PetscFunctionReturn(0);
9084 }
9085 
9086 #undef __FUNCT__
9087 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9088 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9089 {
9090   Vec            coordinates;
9091   PetscSection   section, cSection;
9092   PetscInt       dim, vStart, vEnd, v, c, d;
9093   PetscScalar   *values, *cArray;
9094   PetscReal     *coords;
9095   PetscErrorCode ierr;
9096 
9097   PetscFunctionBegin;
9098   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9099   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9100   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9101   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9102   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9103   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9104   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9105   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9106   for (v = vStart; v < vEnd; ++v) {
9107     PetscInt dof, off;
9108 
9109     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9110     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9111     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9112     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9113     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9114     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9115   }
9116   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9117   /* Temporary, must be replaced by a projection on the finite element basis */
9118   {
9119     PetscInt eStart = 0, eEnd = 0, e, depth;
9120 
9121     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9122     --depth;
9123     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9124     for (e = eStart; e < eEnd; ++e) {
9125       const PetscInt *cone = NULL;
9126       PetscInt        coneSize, d;
9127       PetscScalar    *coordsA, *coordsB;
9128 
9129       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9130       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9131       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9132       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9133       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9134       for (d = 0; d < dim; ++d) {
9135         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9136       }
9137       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9138       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9139     }
9140   }
9141 
9142   ierr = PetscFree(coords);CHKERRQ(ierr);
9143   ierr = PetscFree(values);CHKERRQ(ierr);
9144 #if 0
9145   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9146   PetscReal      detJ;
9147 
9148   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9149   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9150   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9151 
9152   for (PetscInt c = cStart; c < cEnd; ++c) {
9153     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9154     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9155     const int                          oSize   = pV.getSize();
9156     int                                v       = 0;
9157 
9158     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9159     for (PetscInt cl = 0; cl < oSize; ++cl) {
9160       const PetscInt fDim;
9161 
9162       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9163       if (pointDim) {
9164         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9165           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9166         }
9167       }
9168     }
9169     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9170     pV.clear();
9171   }
9172   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9173   ierr = PetscFree(values);CHKERRQ(ierr);
9174 #endif
9175   PetscFunctionReturn(0);
9176 }
9177 
9178 #undef __FUNCT__
9179 #define __FUNCT__ "DMPlexProjectFunction"
9180 /*@C
9181   DMPlexProjectFunction - This projects the given function into the function space provided.
9182 
9183   Input Parameters:
9184 + dm      - The DM
9185 . numComp - The number of components (functions)
9186 . funcs   - The coordinate functions to evaluate
9187 - mode    - The insertion mode for values
9188 
9189   Output Parameter:
9190 . X - vector
9191 
9192   Level: developer
9193 
9194   Note:
9195   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9196   We will eventually fix it.
9197 
9198 ,seealso: DMPlexComputeL2Diff()
9199 */
9200 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9201 {
9202   Vec            localX;
9203   PetscErrorCode ierr;
9204 
9205   PetscFunctionBegin;
9206   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9207   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9208   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9209   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9210   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9211   PetscFunctionReturn(0);
9212 }
9213 
9214 #undef __FUNCT__
9215 #define __FUNCT__ "DMPlexComputeL2Diff"
9216 /*@C
9217   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9218 
9219   Input Parameters:
9220 + dm    - The DM
9221 . quad  - The PetscQuadrature object for each field
9222 . funcs - The functions to evaluate for each field component
9223 - X     - The coefficient vector u_h
9224 
9225   Output Parameter:
9226 . diff - The diff ||u - u_h||_2
9227 
9228   Level: developer
9229 
9230 .seealso: DMPlexProjectFunction()
9231 */
9232 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9233 {
9234   const PetscInt debug = 0;
9235   PetscSection   section;
9236   Vec            localX;
9237   PetscReal     *coords, *v0, *J, *invJ, detJ;
9238   PetscReal      localDiff = 0.0;
9239   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9240   PetscErrorCode ierr;
9241 
9242   PetscFunctionBegin;
9243   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9244   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9245   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9246   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9247   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9248   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9249   for (field = 0; field < numFields; ++field) {
9250     numComponents += quad[field].numComponents;
9251   }
9252   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9253   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9254   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9255   for (c = cStart; c < cEnd; ++c) {
9256     const PetscScalar *x;
9257     PetscReal          elemDiff = 0.0;
9258 
9259     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9260     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9261     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9262 
9263     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9264       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9265       const PetscReal *quadPoints    = quad[field].quadPoints;
9266       const PetscReal *quadWeights   = quad[field].quadWeights;
9267       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9268       const PetscInt   numBasisComps = quad[field].numComponents;
9269       const PetscReal *basis         = quad[field].basis;
9270       PetscInt         q, d, e, fc, f;
9271 
9272       if (debug) {
9273         char title[1024];
9274         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9275         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9276       }
9277       for (q = 0; q < numQuadPoints; ++q) {
9278         for (d = 0; d < dim; d++) {
9279           coords[d] = v0[d];
9280           for (e = 0; e < dim; e++) {
9281             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9282           }
9283         }
9284         for (fc = 0; fc < numBasisComps; ++fc) {
9285           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9286           PetscReal       interpolant = 0.0;
9287           for (f = 0; f < numBasisFuncs; ++f) {
9288             const PetscInt fidx = f*numBasisComps+fc;
9289             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9290           }
9291           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9292           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9293         }
9294       }
9295       comp        += numBasisComps;
9296       fieldOffset += numBasisFuncs*numBasisComps;
9297     }
9298     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9299     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9300     localDiff += elemDiff;
9301   }
9302   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9303   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9304   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9305   *diff = PetscSqrtReal(*diff);
9306   PetscFunctionReturn(0);
9307 }
9308 
9309 #undef __FUNCT__
9310 #define __FUNCT__ "DMPlexComputeResidualFEM"
9311 /*@
9312   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9313 
9314   Input Parameters:
9315 + dm - The mesh
9316 . X  - Local input vector
9317 - user - The user context
9318 
9319   Output Parameter:
9320 . F  - Local output vector
9321 
9322   Note:
9323   The second member of the user context must be an FEMContext.
9324 
9325   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9326   like a GPU, or vectorize on a multicore machine.
9327 
9328 .seealso: DMPlexComputeJacobianActionFEM()
9329 */
9330 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9331 {
9332   DM_Plex         *mesh = (DM_Plex*) dm->data;
9333   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9334   PetscQuadrature *quad = fem->quad;
9335   PetscSection     section;
9336   PetscReal       *v0, *J, *invJ, *detJ;
9337   PetscScalar     *elemVec, *u;
9338   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9339   PetscInt         cellDof = 0, numComponents = 0;
9340   PetscErrorCode   ierr;
9341 
9342   PetscFunctionBegin;
9343   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9344   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9345   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9346   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9347   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9348   numCells = cEnd - cStart;
9349   for (field = 0; field < numFields; ++field) {
9350     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9351     numComponents += quad[field].numComponents;
9352   }
9353   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9354   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9355   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
9356   for (c = cStart; c < cEnd; ++c) {
9357     const PetscScalar *x;
9358     PetscInt           i;
9359 
9360     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9361     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9362     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9363 
9364     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9365     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9366   }
9367   for (field = 0; field < numFields; ++field) {
9368     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9369     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9370     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9371     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9372     /* Conforming batches */
9373     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9374     PetscInt numBlocks  = 1;
9375     PetscInt batchSize  = numBlocks * blockSize;
9376     PetscInt numBatches = numBatchesTmp;
9377     PetscInt numChunks  = numCells / (numBatches*batchSize);
9378     /* Remainder */
9379     PetscInt numRemainder = numCells % (numBatches * batchSize);
9380     PetscInt offset       = numCells - numRemainder;
9381 
9382     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9383     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9384                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9385   }
9386   for (c = cStart; c < cEnd; ++c) {
9387     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9388     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9389   }
9390   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9391   if (mesh->printFEM) {
9392     PetscMPIInt rank, numProcs;
9393     PetscInt    p;
9394 
9395     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9396     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9397     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9398     for (p = 0; p < numProcs; ++p) {
9399       if (p == rank) {
9400         Vec f;
9401 
9402         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9403         ierr = VecCopy(F, f);CHKERRQ(ierr);
9404         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9405         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9406         ierr = VecDestroy(&f);CHKERRQ(ierr);
9407         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9408       }
9409       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9410     }
9411   }
9412   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9413   PetscFunctionReturn(0);
9414 }
9415 
9416 #undef __FUNCT__
9417 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9418 /*@C
9419   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9420 
9421   Input Parameters:
9422 + dm - The mesh
9423 . J  - The Jacobian shell matrix
9424 . X  - Local input vector
9425 - user - The user context
9426 
9427   Output Parameter:
9428 . F  - Local output vector
9429 
9430   Note:
9431   The second member of the user context must be an FEMContext.
9432 
9433   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9434   like a GPU, or vectorize on a multicore machine.
9435 
9436 .seealso: DMPlexComputeResidualFEM()
9437 */
9438 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9439 {
9440   DM_Plex         *mesh = (DM_Plex*) dm->data;
9441   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9442   PetscQuadrature *quad = fem->quad;
9443   PetscSection     section;
9444   JacActionCtx    *jctx;
9445   PetscReal       *v0, *J, *invJ, *detJ;
9446   PetscScalar     *elemVec, *u, *a;
9447   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9448   PetscInt         cellDof = 0;
9449   PetscErrorCode   ierr;
9450 
9451   PetscFunctionBegin;
9452   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9453   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9454   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9455   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9456   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9457   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9458   numCells = cEnd - cStart;
9459   for (field = 0; field < numFields; ++field) {
9460     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9461   }
9462   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9463   ierr = PetscMalloc7(numCells*cellDof,PetscScalar,&u,numCells*cellDof,PetscScalar,&a,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
9464   for (c = cStart; c < cEnd; ++c) {
9465     const PetscScalar *x;
9466     PetscInt           i;
9467 
9468     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9469     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9470     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9471     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9472     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9473     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9474     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9475     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9476   }
9477   for (field = 0; field < numFields; ++field) {
9478     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9479     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9480     /* Conforming batches */
9481     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9482     PetscInt numBlocks  = 1;
9483     PetscInt batchSize  = numBlocks * blockSize;
9484     PetscInt numBatches = numBatchesTmp;
9485     PetscInt numChunks  = numCells / (numBatches*batchSize);
9486     /* Remainder */
9487     PetscInt numRemainder = numCells % (numBatches * batchSize);
9488     PetscInt offset       = numCells - numRemainder;
9489 
9490     ierr = (*mesh->integrateJacobianActionFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, a, v0, J, invJ, detJ, fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, elemVec);CHKERRQ(ierr);
9491     ierr = (*mesh->integrateJacobianActionFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &a[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9492                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9493   }
9494   for (c = cStart; c < cEnd; ++c) {
9495     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9496     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9497   }
9498   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9499   if (mesh->printFEM) {
9500     PetscMPIInt rank, numProcs;
9501     PetscInt    p;
9502 
9503     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9504     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9505     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9506     for (p = 0; p < numProcs; ++p) {
9507       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9508       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9509     }
9510   }
9511   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9512   PetscFunctionReturn(0);
9513 }
9514 
9515 #undef __FUNCT__
9516 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9517 /*@
9518   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9519 
9520   Input Parameters:
9521 + dm - The mesh
9522 . X  - Local input vector
9523 - user - The user context
9524 
9525   Output Parameter:
9526 . Jac  - Jacobian matrix
9527 
9528   Note:
9529   The second member of the user context must be an FEMContext.
9530 
9531   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9532   like a GPU, or vectorize on a multicore machine.
9533 
9534 .seealso: FormFunctionLocal()
9535 */
9536 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9537 {
9538   DM_Plex         *mesh = (DM_Plex*) dm->data;
9539   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9540   PetscQuadrature *quad = fem->quad;
9541   PetscSection     section;
9542   PetscReal       *v0, *J, *invJ, *detJ;
9543   PetscScalar     *elemMat, *u;
9544   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9545   PetscInt         cellDof = 0, numComponents = 0;
9546   PetscBool        isShell;
9547   PetscErrorCode   ierr;
9548 
9549   PetscFunctionBegin;
9550   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9551   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9552   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9553   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9554   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9555   numCells = cEnd - cStart;
9556   for (field = 0; field < numFields; ++field) {
9557     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9558     numComponents += quad[field].numComponents;
9559   }
9560   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9561   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9562   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof*cellDof,PetscScalar,&elemMat);CHKERRQ(ierr);
9563   for (c = cStart; c < cEnd; ++c) {
9564     const PetscScalar *x;
9565     PetscInt           i;
9566 
9567     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9568     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9569     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9570 
9571     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9572     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9573   }
9574   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9575   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9576     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9577     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9578     PetscInt       fieldJ;
9579 
9580     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9581       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9582       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9583       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9584       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9585       /* Conforming batches */
9586       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9587       PetscInt numBlocks  = 1;
9588       PetscInt batchSize  = numBlocks * blockSize;
9589       PetscInt numBatches = numBatchesTmp;
9590       PetscInt numChunks  = numCells / (numBatches*batchSize);
9591       /* Remainder */
9592       PetscInt numRemainder = numCells % (numBatches * batchSize);
9593       PetscInt offset       = numCells - numRemainder;
9594 
9595       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9596       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9597                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9598     }
9599   }
9600   for (c = cStart; c < cEnd; ++c) {
9601     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9602     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9603   }
9604   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9605 
9606   /* Assemble matrix, using the 2-step process:
9607        MatAssemblyBegin(), MatAssemblyEnd(). */
9608   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9609   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9610 
9611   if (mesh->printFEM) {
9612     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9613     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9614     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9615   }
9616   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9617   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9618   if (isShell) {
9619     JacActionCtx *jctx;
9620 
9621     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9622     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9623   }
9624   *str = SAME_NONZERO_PATTERN;
9625   PetscFunctionReturn(0);
9626 }
9627 
9628 
9629 #undef __FUNCT__
9630 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9631 /*@C
9632   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9633   the local section and an SF describing the section point overlap.
9634 
9635   Input Parameters:
9636   + s - The PetscSection for the local field layout
9637   . sf - The SF describing parallel layout of the section points
9638   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9639   . label - The label specifying the points
9640   - labelValue - The label stratum specifying the points
9641 
9642   Output Parameter:
9643   . gsection - The PetscSection for the global field layout
9644 
9645   Note: This gives negative sizes and offsets to points not owned by this process
9646 
9647   Level: developer
9648 
9649 .seealso: PetscSectionCreate()
9650 @*/
9651 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9652 {
9653   PetscInt      *neg;
9654   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9655   PetscErrorCode ierr;
9656 
9657   PetscFunctionBegin;
9658   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9659   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9660   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9661   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9662   /* Mark ghost points with negative dof */
9663   for (p = pStart; p < pEnd; ++p) {
9664     PetscInt value;
9665 
9666     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9667     if (value != labelValue) continue;
9668     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9669     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9670     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9671     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9672     neg[p-pStart] = -(dof+1);
9673   }
9674   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9675   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
9676   if (nroots >= 0) {
9677     if (nroots > pEnd - pStart) {
9678       PetscInt *tmpDof;
9679       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9680       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9681       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9682       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9683       for (p = pStart; p < pEnd; ++p) {
9684         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
9685       }
9686       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9687     } else {
9688       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9689       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9690     }
9691   }
9692   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9693   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9694     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9695 
9696     (*gsection)->atlasOff[p] = off;
9697 
9698     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9699   }
9700   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9701   globalOff -= off;
9702   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9703     (*gsection)->atlasOff[p] += globalOff;
9704 
9705     neg[p] = -((*gsection)->atlasOff[p]+1);
9706   }
9707   /* Put in negative offsets for ghost points */
9708   if (nroots >= 0) {
9709     if (nroots > pEnd - pStart) {
9710       PetscInt *tmpOff;
9711       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9712       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9713       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9714       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9715       for (p = pStart; p < pEnd; ++p) {
9716         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
9717       }
9718       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9719     } else {
9720       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9721       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9722     }
9723   }
9724   ierr = PetscFree(neg);CHKERRQ(ierr);
9725   PetscFunctionReturn(0);
9726 }
9727