xref: /petsc/src/dm/impls/plex/plex.c (revision 210b54269ebe7adeae42df32e16934c9cbbd9482)
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 PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "VecView_Plex_Local"
14 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
15 {
16   DM             dm;
17   PetscBool      isvtk;
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
22   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
23   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
24   if (isvtk) {
25     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
26     PetscSection            section;
27     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
28 
29     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
30     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
31     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
32     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, NULL);CHKERRQ(ierr);
33     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, NULL);CHKERRQ(ierr);
34     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
35     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
36     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
37     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
38     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
39     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
40       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
41     } else if (cdof && vdof) {
42       SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
43     } else if (cdof) {
44       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
45        * vector or just happens to have the same number of dofs as the dimension. */
46       if (cdof == dim) {
47         ft = PETSC_VTK_CELL_VECTOR_FIELD;
48       } else {
49         ft = PETSC_VTK_CELL_FIELD;
50       }
51     } else if (vdof) {
52       if (vdof == dim) {
53         ft = PETSC_VTK_POINT_VECTOR_FIELD;
54       } else {
55         ft = PETSC_VTK_POINT_FIELD;
56       }
57     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
58 
59     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
60     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
61     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
62   } else {
63     PetscBool isseq;
64 
65     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
66     if (isseq) {
67       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
68     } else {
69       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
70     }
71   }
72   PetscFunctionReturn(0);
73 }
74 
75 #undef __FUNCT__
76 #define __FUNCT__ "VecView_Plex"
77 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
78 {
79   DM             dm;
80   PetscBool      isvtk;
81   PetscErrorCode ierr;
82 
83   PetscFunctionBegin;
84   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
85   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
86   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
87   if (isvtk) {
88     Vec         locv;
89     const char *name;
90 
91     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
92     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
93     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
94     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
95     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
96     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
97     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
98   } else {
99     PetscBool isseq;
100 
101     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
102     if (isseq) {
103       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
104     } else {
105       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
106     }
107   }
108   PetscFunctionReturn(0);
109 }
110 
111 #undef __FUNCT__
112 #define __FUNCT__ "DMPlexView_Ascii"
113 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
114 {
115   DM_Plex          *mesh = (DM_Plex*) dm->data;
116   DM                cdm;
117   DMLabel           markers;
118   PetscSection      coordSection;
119   Vec               coordinates;
120   PetscViewerFormat format;
121   PetscErrorCode    ierr;
122 
123   PetscFunctionBegin;
124   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
125   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
126   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
127   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
128   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
129     const char *name;
130     PetscInt    maxConeSize, maxSupportSize;
131     PetscInt    pStart, pEnd, p;
132     PetscMPIInt rank, size;
133 
134     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
135     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
136     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
137     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
138     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
142     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
143     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
144     for (p = pStart; p < pEnd; ++p) {
145       PetscInt dof, off, s;
146 
147       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
148       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
149       for (s = off; s < off+dof; ++s) {
150         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
151       }
152     }
153     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
154     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
155     for (p = pStart; p < pEnd; ++p) {
156       PetscInt dof, off, c;
157 
158       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
159       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
160       for (c = off; c < off+dof; ++c) {
161         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
162       }
163     }
164     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
165     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
166     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
167     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
168     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors  = 3;
180     PetscReal    scale      = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscInt    numLabels, l;
282     PetscMPIInt size;
283 
284     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
285     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
286     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
287     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
288     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
289     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
290     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
291     if (depth == 1) {
292       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
293       pEnd = pEnd - pStart;
294       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
295       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
296       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
297       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
298       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
299       pEnd = pEnd - pStart;
300       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
301       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
302       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
303       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
304     } else {
305       for (d = 0; d <= dim; d++) {
306         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
307         pEnd = pEnd - pStart;
308         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
309         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
310         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
311         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
312       }
313     }
314     ierr = PetscFree(sizes);CHKERRQ(ierr);
315     ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
316     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
317     for (l = 0; l < numLabels; ++l) {
318       DMLabel         label;
319       const char     *name;
320       IS              valueIS;
321       const PetscInt *values;
322       PetscInt        numValues, v;
323 
324       ierr = DMPlexGetLabelName(dm, l, &name);CHKERRQ(ierr);
325       ierr = DMPlexGetLabel(dm, name, &label);CHKERRQ(ierr);
326       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
327       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);CHKERRQ(ierr);
328       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
329       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
330       for (v = 0; v < numValues; ++v) {
331         PetscInt size;
332 
333         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
334         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
335         ierr = PetscViewerASCIIPrintf(viewer, "%d", size);CHKERRQ(ierr);
336       }
337       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
338       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
339     }
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   Fortran Notes:
1260   Since it returns an array, this routine is only available in Fortran 90, and you must
1261   include petsc.h90 in your code.
1262 
1263   You must also call DMPlexRestoreCone() after you finish using the returned array.
1264 
1265 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1266 @*/
1267 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1268 {
1269   DM_Plex       *mesh = (DM_Plex*) dm->data;
1270   PetscInt       off;
1271   PetscErrorCode ierr;
1272 
1273   PetscFunctionBegin;
1274   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1275   PetscValidPointer(cone, 3);
1276   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1277   *cone = &mesh->cones[off];
1278   PetscFunctionReturn(0);
1279 }
1280 
1281 #undef __FUNCT__
1282 #define __FUNCT__ "DMPlexSetCone"
1283 /*@
1284   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1285 
1286   Not collective
1287 
1288   Input Parameters:
1289 + mesh - The DMPlex
1290 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1291 - cone - An array of points which are on the in-edges for point p
1292 
1293   Output Parameter:
1294 
1295   Note:
1296   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1297 
1298   Level: beginner
1299 
1300 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1301 @*/
1302 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1303 {
1304   DM_Plex       *mesh = (DM_Plex*) dm->data;
1305   PetscInt       pStart, pEnd;
1306   PetscInt       dof, off, c;
1307   PetscErrorCode ierr;
1308 
1309   PetscFunctionBegin;
1310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1311   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1312   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1313   if (dof) PetscValidPointer(cone, 3);
1314   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1315   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);
1316   for (c = 0; c < dof; ++c) {
1317     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);
1318     mesh->cones[off+c] = cone[c];
1319   }
1320   PetscFunctionReturn(0);
1321 }
1322 
1323 #undef __FUNCT__
1324 #define __FUNCT__ "DMPlexGetConeOrientation"
1325 /*@C
1326   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1327 
1328   Not collective
1329 
1330   Input Parameters:
1331 + mesh - The DMPlex
1332 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1333 
1334   Output Parameter:
1335 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1336                     integer giving the prescription for cone traversal. If it is negative, the cone is
1337                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1338                     the index of the cone point on which to start.
1339 
1340   Level: beginner
1341 
1342   Fortran Notes:
1343   Since it returns an array, this routine is only available in Fortran 90, and you must
1344   include petsc.h90 in your code.
1345 
1346   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1347 
1348 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1349 @*/
1350 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1351 {
1352   DM_Plex       *mesh = (DM_Plex*) dm->data;
1353   PetscInt       off;
1354   PetscErrorCode ierr;
1355 
1356   PetscFunctionBegin;
1357   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1358 #if defined(PETSC_USE_DEBUG)
1359   {
1360     PetscInt dof;
1361     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1362     if (dof) PetscValidPointer(coneOrientation, 3);
1363   }
1364 #endif
1365   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1366 
1367   *coneOrientation = &mesh->coneOrientations[off];
1368   PetscFunctionReturn(0);
1369 }
1370 
1371 #undef __FUNCT__
1372 #define __FUNCT__ "DMPlexSetConeOrientation"
1373 /*@
1374   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1375 
1376   Not collective
1377 
1378   Input Parameters:
1379 + mesh - The DMPlex
1380 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1381 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1382                     integer giving the prescription for cone traversal. If it is negative, the cone is
1383                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1384                     the index of the cone point on which to start.
1385 
1386   Output Parameter:
1387 
1388   Note:
1389   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1390 
1391   Level: beginner
1392 
1393 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1394 @*/
1395 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1396 {
1397   DM_Plex       *mesh = (DM_Plex*) dm->data;
1398   PetscInt       pStart, pEnd;
1399   PetscInt       dof, off, c;
1400   PetscErrorCode ierr;
1401 
1402   PetscFunctionBegin;
1403   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1404   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1405   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1406   if (dof) PetscValidPointer(coneOrientation, 3);
1407   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1408   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);
1409   for (c = 0; c < dof; ++c) {
1410     PetscInt cdof, o = coneOrientation[c];
1411 
1412     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1413     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);
1414     mesh->coneOrientations[off+c] = o;
1415   }
1416   PetscFunctionReturn(0);
1417 }
1418 
1419 #undef __FUNCT__
1420 #define __FUNCT__ "DMPlexInsertCone"
1421 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1422 {
1423   DM_Plex       *mesh = (DM_Plex*) dm->data;
1424   PetscInt       pStart, pEnd;
1425   PetscInt       dof, off;
1426   PetscErrorCode ierr;
1427 
1428   PetscFunctionBegin;
1429   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1430   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1431   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);
1432   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);
1433   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1434   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1435   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);
1436   mesh->cones[off+conePos] = conePoint;
1437   PetscFunctionReturn(0);
1438 }
1439 
1440 #undef __FUNCT__
1441 #define __FUNCT__ "DMPlexInsertConeOrientation"
1442 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1443 {
1444   DM_Plex       *mesh = (DM_Plex*) dm->data;
1445   PetscInt       pStart, pEnd;
1446   PetscInt       dof, off;
1447   PetscErrorCode ierr;
1448 
1449   PetscFunctionBegin;
1450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1451   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1452   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);
1453   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1454   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1455   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);
1456   mesh->coneOrientations[off+conePos] = coneOrientation;
1457   PetscFunctionReturn(0);
1458 }
1459 
1460 #undef __FUNCT__
1461 #define __FUNCT__ "DMPlexGetSupportSize"
1462 /*@
1463   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1464 
1465   Not collective
1466 
1467   Input Parameters:
1468 + mesh - The DMPlex
1469 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1470 
1471   Output Parameter:
1472 . size - The support size for point p
1473 
1474   Level: beginner
1475 
1476 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1477 @*/
1478 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1479 {
1480   DM_Plex       *mesh = (DM_Plex*) dm->data;
1481   PetscErrorCode ierr;
1482 
1483   PetscFunctionBegin;
1484   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1485   PetscValidPointer(size, 3);
1486   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1487   PetscFunctionReturn(0);
1488 }
1489 
1490 #undef __FUNCT__
1491 #define __FUNCT__ "DMPlexSetSupportSize"
1492 /*@
1493   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1494 
1495   Not collective
1496 
1497   Input Parameters:
1498 + mesh - The DMPlex
1499 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1500 - size - The support size for point p
1501 
1502   Output Parameter:
1503 
1504   Note:
1505   This should be called after DMPlexSetChart().
1506 
1507   Level: beginner
1508 
1509 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1510 @*/
1511 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1512 {
1513   DM_Plex       *mesh = (DM_Plex*) dm->data;
1514   PetscErrorCode ierr;
1515 
1516   PetscFunctionBegin;
1517   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1518   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1519 
1520   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1521   PetscFunctionReturn(0);
1522 }
1523 
1524 #undef __FUNCT__
1525 #define __FUNCT__ "DMPlexGetSupport"
1526 /*@C
1527   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1528 
1529   Not collective
1530 
1531   Input Parameters:
1532 + mesh - The DMPlex
1533 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1534 
1535   Output Parameter:
1536 . support - An array of points which are on the out-edges for point p
1537 
1538   Level: beginner
1539 
1540   Fortran Notes:
1541   Since it returns an array, this routine is only available in Fortran 90, and you must
1542   include petsc.h90 in your code.
1543 
1544   You must also call DMPlexRestoreSupport() after you finish using the returned array.
1545 
1546 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1547 @*/
1548 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1549 {
1550   DM_Plex       *mesh = (DM_Plex*) dm->data;
1551   PetscInt       off;
1552   PetscErrorCode ierr;
1553 
1554   PetscFunctionBegin;
1555   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1556   PetscValidPointer(support, 3);
1557   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1558   *support = &mesh->supports[off];
1559   PetscFunctionReturn(0);
1560 }
1561 
1562 #undef __FUNCT__
1563 #define __FUNCT__ "DMPlexSetSupport"
1564 /*@
1565   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1566 
1567   Not collective
1568 
1569   Input Parameters:
1570 + mesh - The DMPlex
1571 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1572 - support - An array of points which are on the in-edges for point p
1573 
1574   Output Parameter:
1575 
1576   Note:
1577   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1578 
1579   Level: beginner
1580 
1581 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1582 @*/
1583 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1584 {
1585   DM_Plex       *mesh = (DM_Plex*) dm->data;
1586   PetscInt       pStart, pEnd;
1587   PetscInt       dof, off, c;
1588   PetscErrorCode ierr;
1589 
1590   PetscFunctionBegin;
1591   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1592   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1593   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1594   if (dof) PetscValidPointer(support, 3);
1595   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1596   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);
1597   for (c = 0; c < dof; ++c) {
1598     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);
1599     mesh->supports[off+c] = support[c];
1600   }
1601   PetscFunctionReturn(0);
1602 }
1603 
1604 #undef __FUNCT__
1605 #define __FUNCT__ "DMPlexInsertSupport"
1606 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1607 {
1608   DM_Plex       *mesh = (DM_Plex*) dm->data;
1609   PetscInt       pStart, pEnd;
1610   PetscInt       dof, off;
1611   PetscErrorCode ierr;
1612 
1613   PetscFunctionBegin;
1614   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1615   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1616   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1617   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1618   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);
1619   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);
1620   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);
1621   mesh->supports[off+supportPos] = supportPoint;
1622   PetscFunctionReturn(0);
1623 }
1624 
1625 #undef __FUNCT__
1626 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1627 /*@C
1628   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1629 
1630   Not collective
1631 
1632   Input Parameters:
1633 + mesh - The DMPlex
1634 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1635 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1636 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1637 
1638   Output Parameters:
1639 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1640 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1641 
1642   Note:
1643   If using internal storage (points is NULL on input), each call overwrites the last output.
1644 
1645   Fortran Notes:
1646   Since it returns an array, this routine is only available in Fortran 90, and you must
1647   include petsc.h90 in your code.
1648 
1649   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1650 
1651   Level: beginner
1652 
1653 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1654 @*/
1655 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1656 {
1657   DM_Plex        *mesh = (DM_Plex*) dm->data;
1658   PetscInt       *closure, *fifo;
1659   const PetscInt *tmp = NULL, *tmpO = NULL;
1660   PetscInt        tmpSize, t;
1661   PetscInt        depth       = 0, maxSize;
1662   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1663   PetscErrorCode  ierr;
1664 
1665   PetscFunctionBegin;
1666   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1667   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1668   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1669   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1670   if (*points) {
1671     closure = *points;
1672   } else {
1673     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1674   }
1675   closure[0] = p; closure[1] = 0;
1676   /* This is only 1-level */
1677   if (useCone) {
1678     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1679     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1680     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1681   } else {
1682     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1683     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1684   }
1685   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1686     const PetscInt cp = tmp[t];
1687     const PetscInt co = tmpO ? tmpO[t] : 0;
1688 
1689     closure[closureSize]   = cp;
1690     closure[closureSize+1] = co;
1691     fifo[fifoSize]         = cp;
1692     fifo[fifoSize+1]       = co;
1693   }
1694   while (fifoSize - fifoStart) {
1695     const PetscInt q   = fifo[fifoStart];
1696     const PetscInt o   = fifo[fifoStart+1];
1697     const PetscInt rev = o >= 0 ? 0 : 1;
1698     const PetscInt off = rev ? -(o+1) : o;
1699 
1700     if (useCone) {
1701       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1702       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1703       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1704     } else {
1705       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1706       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1707       tmpO = NULL;
1708     }
1709     for (t = 0; t < tmpSize; ++t) {
1710       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1711       const PetscInt cp = tmp[i];
1712       /* Must propogate orientation */
1713       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1714       PetscInt       c;
1715 
1716       /* Check for duplicate */
1717       for (c = 0; c < closureSize; c += 2) {
1718         if (closure[c] == cp) break;
1719       }
1720       if (c == closureSize) {
1721         closure[closureSize]   = cp;
1722         closure[closureSize+1] = co;
1723         fifo[fifoSize]         = cp;
1724         fifo[fifoSize+1]       = co;
1725         closureSize           += 2;
1726         fifoSize              += 2;
1727       }
1728     }
1729     fifoStart += 2;
1730   }
1731   if (numPoints) *numPoints = closureSize/2;
1732   if (points)    *points    = closure;
1733   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1734   PetscFunctionReturn(0);
1735 }
1736 
1737 #undef __FUNCT__
1738 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1739 /*@C
1740   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1741 
1742   Not collective
1743 
1744   Input Parameters:
1745 + mesh - The DMPlex
1746 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1747 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1748 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1749 
1750   Output Parameters:
1751 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1752 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1753 
1754   Note:
1755   If not using internal storage (points is not NULL on input), this call is unnecessary
1756 
1757   Fortran Notes:
1758   Since it returns an array, this routine is only available in Fortran 90, and you must
1759   include petsc.h90 in your code.
1760 
1761   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1762 
1763   Level: beginner
1764 
1765 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1766 @*/
1767 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1768 {
1769   PetscErrorCode ierr;
1770 
1771   PetscFunctionBegin;
1772   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1773   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1774   PetscFunctionReturn(0);
1775 }
1776 
1777 #undef __FUNCT__
1778 #define __FUNCT__ "DMPlexGetMaxSizes"
1779 /*@
1780   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1781 
1782   Not collective
1783 
1784   Input Parameter:
1785 . mesh - The DMPlex
1786 
1787   Output Parameters:
1788 + maxConeSize - The maximum number of in-edges
1789 - maxSupportSize - The maximum number of out-edges
1790 
1791   Level: beginner
1792 
1793 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1794 @*/
1795 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1796 {
1797   DM_Plex *mesh = (DM_Plex*) dm->data;
1798 
1799   PetscFunctionBegin;
1800   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1801   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1802   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1803   PetscFunctionReturn(0);
1804 }
1805 
1806 #undef __FUNCT__
1807 #define __FUNCT__ "DMSetUp_Plex"
1808 PetscErrorCode DMSetUp_Plex(DM dm)
1809 {
1810   DM_Plex       *mesh = (DM_Plex*) dm->data;
1811   PetscInt       size;
1812   PetscErrorCode ierr;
1813 
1814   PetscFunctionBegin;
1815   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1816   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1817   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1818   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1819   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1820   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1821   if (mesh->maxSupportSize) {
1822     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1823     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1824     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1825   }
1826   PetscFunctionReturn(0);
1827 }
1828 
1829 #undef __FUNCT__
1830 #define __FUNCT__ "DMCreateSubDM_Plex"
1831 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1832 {
1833   PetscSection   section, sectionGlobal;
1834   PetscInt      *subIndices;
1835   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1836   PetscErrorCode ierr;
1837 
1838   PetscFunctionBegin;
1839   if (!numFields) PetscFunctionReturn(0);
1840   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1841   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1842   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1843   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1844   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1845   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);
1846   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1847   for (p = pStart; p < pEnd; ++p) {
1848     PetscInt gdof;
1849 
1850     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1851     if (gdof > 0) {
1852       for (f = 0; f < numFields; ++f) {
1853         PetscInt fdof, fcdof;
1854 
1855         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1856         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1857         subSize += fdof-fcdof;
1858       }
1859     }
1860   }
1861   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1862   for (p = pStart; p < pEnd; ++p) {
1863     PetscInt gdof, goff;
1864 
1865     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1866     if (gdof > 0) {
1867       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1868       for (f = 0; f < numFields; ++f) {
1869         PetscInt fdof, fcdof, fc, f2, poff = 0;
1870 
1871         /* Can get rid of this loop by storing field information in the global section */
1872         for (f2 = 0; f2 < fields[f]; ++f2) {
1873           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1874           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1875           poff += fdof-fcdof;
1876         }
1877         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1878         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1879         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1880           subIndices[subOff] = goff+poff+fc;
1881         }
1882       }
1883     }
1884   }
1885   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1886   if (subdm) {
1887     PetscSection subsection;
1888     PetscBool    haveNull = PETSC_FALSE;
1889     PetscInt     f, nf = 0;
1890 
1891     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1892     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1893     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1894     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1895     for (f = 0; f < numFields; ++f) {
1896       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1897       if ((*subdm)->nullspaceConstructors[f]) {
1898         haveNull = PETSC_TRUE;
1899         nf       = f;
1900       }
1901     }
1902     if (haveNull) {
1903       MatNullSpace nullSpace;
1904 
1905       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1906       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1907       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1908     }
1909     if (dm->fields) {
1910       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);
1911       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1912       for (f = 0; f < numFields; ++f) {
1913         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1914       }
1915       if (numFields == 1) {
1916         MatNullSpace space;
1917         Mat          pmat;
1918 
1919         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1920         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1921         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1922         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1923         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1924         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1925       }
1926     }
1927   }
1928   PetscFunctionReturn(0);
1929 }
1930 
1931 #undef __FUNCT__
1932 #define __FUNCT__ "DMPlexSymmetrize"
1933 /*@
1934   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1935 
1936   Not collective
1937 
1938   Input Parameter:
1939 . mesh - The DMPlex
1940 
1941   Output Parameter:
1942 
1943   Note:
1944   This should be called after all calls to DMPlexSetCone()
1945 
1946   Level: beginner
1947 
1948 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1949 @*/
1950 PetscErrorCode DMPlexSymmetrize(DM dm)
1951 {
1952   DM_Plex       *mesh = (DM_Plex*) dm->data;
1953   PetscInt      *offsets;
1954   PetscInt       supportSize;
1955   PetscInt       pStart, pEnd, p;
1956   PetscErrorCode ierr;
1957 
1958   PetscFunctionBegin;
1959   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1960   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1961   /* Calculate support sizes */
1962   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1963   for (p = pStart; p < pEnd; ++p) {
1964     PetscInt dof, off, c;
1965 
1966     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1967     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1968     for (c = off; c < off+dof; ++c) {
1969       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1970     }
1971   }
1972   for (p = pStart; p < pEnd; ++p) {
1973     PetscInt dof;
1974 
1975     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1976 
1977     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1978   }
1979   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1980   /* Calculate supports */
1981   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1982   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1983   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1984   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1985   for (p = pStart; p < pEnd; ++p) {
1986     PetscInt dof, off, c;
1987 
1988     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1989     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1990     for (c = off; c < off+dof; ++c) {
1991       const PetscInt q = mesh->cones[c];
1992       PetscInt       offS;
1993 
1994       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1995 
1996       mesh->supports[offS+offsets[q]] = p;
1997       ++offsets[q];
1998     }
1999   }
2000   ierr = PetscFree(offsets);CHKERRQ(ierr);
2001   PetscFunctionReturn(0);
2002 }
2003 
2004 #undef __FUNCT__
2005 #define __FUNCT__ "DMPlexSetDepth_Private"
2006 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
2007 {
2008   PetscInt       d;
2009   PetscErrorCode ierr;
2010 
2011   PetscFunctionBegin;
2012   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2013   if (d < 0) {
2014     /* We are guaranteed that the point has a cone since the depth was not yet set */
2015     const PetscInt *cone = NULL;
2016     PetscInt        dCone;
2017 
2018     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2019     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2020     d    = dCone+1;
2021     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2022   }
2023   *depth = d;
2024   PetscFunctionReturn(0);
2025 }
2026 
2027 #undef __FUNCT__
2028 #define __FUNCT__ "DMPlexStratify"
2029 /*@
2030   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2031   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2032   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2033   the DAG.
2034 
2035   Not collective
2036 
2037   Input Parameter:
2038 . mesh - The DMPlex
2039 
2040   Output Parameter:
2041 
2042   Notes:
2043   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2044   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2045 
2046   This should be called after all calls to DMPlexSymmetrize()
2047 
2048   Level: beginner
2049 
2050 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2051 @*/
2052 PetscErrorCode DMPlexStratify(DM dm)
2053 {
2054   DM_Plex       *mesh = (DM_Plex*) dm->data;
2055   PetscInt       pStart, pEnd, p;
2056   PetscInt       numRoots = 0, numLeaves = 0;
2057   PetscErrorCode ierr;
2058 
2059   PetscFunctionBegin;
2060   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2061   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2062   /* Calculate depth */
2063   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2064   /* Initialize roots and count leaves */
2065   for (p = pStart; p < pEnd; ++p) {
2066     PetscInt coneSize, supportSize;
2067 
2068     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2069     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2070     if (!coneSize && supportSize) {
2071       ++numRoots;
2072       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2073     } else if (!supportSize && coneSize) {
2074       ++numLeaves;
2075     } else if (!supportSize && !coneSize) {
2076       /* Isolated points */
2077       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2078     }
2079   }
2080   if (numRoots + numLeaves == (pEnd - pStart)) {
2081     for (p = pStart; p < pEnd; ++p) {
2082       PetscInt coneSize, supportSize;
2083 
2084       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2085       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2086       if (!supportSize && coneSize) {
2087         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2088       }
2089     }
2090   } else {
2091     /* This might be slow since lookup is not fast */
2092     for (p = pStart; p < pEnd; ++p) {
2093       PetscInt depth;
2094 
2095       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2096     }
2097   }
2098   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2099   PetscFunctionReturn(0);
2100 }
2101 
2102 #undef __FUNCT__
2103 #define __FUNCT__ "DMPlexGetJoin"
2104 /*@C
2105   DMPlexGetJoin - Get an array for the join of the set of points
2106 
2107   Not Collective
2108 
2109   Input Parameters:
2110 + dm - The DMPlex object
2111 . numPoints - The number of input points for the join
2112 - points - The input points
2113 
2114   Output Parameters:
2115 + numCoveredPoints - The number of points in the join
2116 - coveredPoints - The points in the join
2117 
2118   Level: intermediate
2119 
2120   Note: Currently, this is restricted to a single level join
2121 
2122   Fortran Notes:
2123   Since it returns an array, this routine is only available in Fortran 90, and you must
2124   include petsc.h90 in your code.
2125 
2126   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2127 
2128 .keywords: mesh
2129 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2130 @*/
2131 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2132 {
2133   DM_Plex       *mesh = (DM_Plex*) dm->data;
2134   PetscInt      *join[2];
2135   PetscInt       joinSize, i = 0;
2136   PetscInt       dof, off, p, c, m;
2137   PetscErrorCode ierr;
2138 
2139   PetscFunctionBegin;
2140   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2141   PetscValidPointer(points, 2);
2142   PetscValidPointer(numCoveredPoints, 3);
2143   PetscValidPointer(coveredPoints, 4);
2144   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2145   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2146   /* Copy in support of first point */
2147   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2148   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2149   for (joinSize = 0; joinSize < dof; ++joinSize) {
2150     join[i][joinSize] = mesh->supports[off+joinSize];
2151   }
2152   /* Check each successive support */
2153   for (p = 1; p < numPoints; ++p) {
2154     PetscInt newJoinSize = 0;
2155 
2156     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2157     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2158     for (c = 0; c < dof; ++c) {
2159       const PetscInt point = mesh->supports[off+c];
2160 
2161       for (m = 0; m < joinSize; ++m) {
2162         if (point == join[i][m]) {
2163           join[1-i][newJoinSize++] = point;
2164           break;
2165         }
2166       }
2167     }
2168     joinSize = newJoinSize;
2169     i        = 1-i;
2170   }
2171   *numCoveredPoints = joinSize;
2172   *coveredPoints    = join[i];
2173   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2174   PetscFunctionReturn(0);
2175 }
2176 
2177 #undef __FUNCT__
2178 #define __FUNCT__ "DMPlexRestoreJoin"
2179 /*@C
2180   DMPlexRestoreJoin - Restore an array for the join of the set of points
2181 
2182   Not Collective
2183 
2184   Input Parameters:
2185 + dm - The DMPlex object
2186 . numPoints - The number of input points for the join
2187 - points - The input points
2188 
2189   Output Parameters:
2190 + numCoveredPoints - The number of points in the join
2191 - coveredPoints - The points in the join
2192 
2193   Fortran Notes:
2194   Since it returns an array, this routine is only available in Fortran 90, and you must
2195   include petsc.h90 in your code.
2196 
2197   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2198 
2199   Level: intermediate
2200 
2201 .keywords: mesh
2202 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2203 @*/
2204 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2205 {
2206   PetscErrorCode ierr;
2207 
2208   PetscFunctionBegin;
2209   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2210   PetscValidPointer(coveredPoints, 4);
2211   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2212   PetscFunctionReturn(0);
2213 }
2214 
2215 #undef __FUNCT__
2216 #define __FUNCT__ "DMPlexGetFullJoin"
2217 /*@C
2218   DMPlexGetFullJoin - Get an array for the join of the set of points
2219 
2220   Not Collective
2221 
2222   Input Parameters:
2223 + dm - The DMPlex object
2224 . numPoints - The number of input points for the join
2225 - points - The input points
2226 
2227   Output Parameters:
2228 + numCoveredPoints - The number of points in the join
2229 - coveredPoints - The points in the join
2230 
2231   Fortran Notes:
2232   Since it returns an array, this routine is only available in Fortran 90, and you must
2233   include petsc.h90 in your code.
2234 
2235   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2236 
2237   Level: intermediate
2238 
2239 .keywords: mesh
2240 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2241 @*/
2242 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2243 {
2244   DM_Plex       *mesh = (DM_Plex*) dm->data;
2245   PetscInt      *offsets, **closures;
2246   PetscInt      *join[2];
2247   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2248   PetscInt       p, d, c, m;
2249   PetscErrorCode ierr;
2250 
2251   PetscFunctionBegin;
2252   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2253   PetscValidPointer(points, 2);
2254   PetscValidPointer(numCoveredPoints, 3);
2255   PetscValidPointer(coveredPoints, 4);
2256 
2257   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2258   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2259   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2260   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2261   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2262   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2263   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2264 
2265   for (p = 0; p < numPoints; ++p) {
2266     PetscInt closureSize;
2267 
2268     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2269 
2270     offsets[p*(depth+2)+0] = 0;
2271     for (d = 0; d < depth+1; ++d) {
2272       PetscInt pStart, pEnd, i;
2273 
2274       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2275       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2276         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2277           offsets[p*(depth+2)+d+1] = i;
2278           break;
2279         }
2280       }
2281       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2282     }
2283     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);
2284   }
2285   for (d = 0; d < depth+1; ++d) {
2286     PetscInt dof;
2287 
2288     /* Copy in support of first point */
2289     dof = offsets[d+1] - offsets[d];
2290     for (joinSize = 0; joinSize < dof; ++joinSize) {
2291       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2292     }
2293     /* Check each successive cone */
2294     for (p = 1; p < numPoints && joinSize; ++p) {
2295       PetscInt newJoinSize = 0;
2296 
2297       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2298       for (c = 0; c < dof; ++c) {
2299         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2300 
2301         for (m = 0; m < joinSize; ++m) {
2302           if (point == join[i][m]) {
2303             join[1-i][newJoinSize++] = point;
2304             break;
2305           }
2306         }
2307       }
2308       joinSize = newJoinSize;
2309       i        = 1-i;
2310     }
2311     if (joinSize) break;
2312   }
2313   *numCoveredPoints = joinSize;
2314   *coveredPoints    = join[i];
2315   for (p = 0; p < numPoints; ++p) {
2316     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2317   }
2318   ierr = PetscFree(closures);CHKERRQ(ierr);
2319   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2320   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2321   PetscFunctionReturn(0);
2322 }
2323 
2324 #undef __FUNCT__
2325 #define __FUNCT__ "DMPlexGetMeet"
2326 /*@C
2327   DMPlexGetMeet - Get an array for the meet of the set of points
2328 
2329   Not Collective
2330 
2331   Input Parameters:
2332 + dm - The DMPlex object
2333 . numPoints - The number of input points for the meet
2334 - points - The input points
2335 
2336   Output Parameters:
2337 + numCoveredPoints - The number of points in the meet
2338 - coveredPoints - The points in the meet
2339 
2340   Level: intermediate
2341 
2342   Note: Currently, this is restricted to a single level meet
2343 
2344   Fortran Notes:
2345   Since it returns an array, this routine is only available in Fortran 90, and you must
2346   include petsc.h90 in your code.
2347 
2348   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2349 
2350 .keywords: mesh
2351 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2352 @*/
2353 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2354 {
2355   DM_Plex       *mesh = (DM_Plex*) dm->data;
2356   PetscInt      *meet[2];
2357   PetscInt       meetSize, i = 0;
2358   PetscInt       dof, off, p, c, m;
2359   PetscErrorCode ierr;
2360 
2361   PetscFunctionBegin;
2362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2363   PetscValidPointer(points, 2);
2364   PetscValidPointer(numCoveringPoints, 3);
2365   PetscValidPointer(coveringPoints, 4);
2366   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2367   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2368   /* Copy in cone of first point */
2369   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2370   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2371   for (meetSize = 0; meetSize < dof; ++meetSize) {
2372     meet[i][meetSize] = mesh->cones[off+meetSize];
2373   }
2374   /* Check each successive cone */
2375   for (p = 1; p < numPoints; ++p) {
2376     PetscInt newMeetSize = 0;
2377 
2378     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2379     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2380     for (c = 0; c < dof; ++c) {
2381       const PetscInt point = mesh->cones[off+c];
2382 
2383       for (m = 0; m < meetSize; ++m) {
2384         if (point == meet[i][m]) {
2385           meet[1-i][newMeetSize++] = point;
2386           break;
2387         }
2388       }
2389     }
2390     meetSize = newMeetSize;
2391     i        = 1-i;
2392   }
2393   *numCoveringPoints = meetSize;
2394   *coveringPoints    = meet[i];
2395   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2396   PetscFunctionReturn(0);
2397 }
2398 
2399 #undef __FUNCT__
2400 #define __FUNCT__ "DMPlexRestoreMeet"
2401 /*@C
2402   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2403 
2404   Not Collective
2405 
2406   Input Parameters:
2407 + dm - The DMPlex object
2408 . numPoints - The number of input points for the meet
2409 - points - The input points
2410 
2411   Output Parameters:
2412 + numCoveredPoints - The number of points in the meet
2413 - coveredPoints - The points in the meet
2414 
2415   Level: intermediate
2416 
2417   Fortran Notes:
2418   Since it returns an array, this routine is only available in Fortran 90, and you must
2419   include petsc.h90 in your code.
2420 
2421   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2422 
2423 .keywords: mesh
2424 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2425 @*/
2426 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2427 {
2428   PetscErrorCode ierr;
2429 
2430   PetscFunctionBegin;
2431   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2432   PetscValidPointer(coveredPoints, 4);
2433   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2434   PetscFunctionReturn(0);
2435 }
2436 
2437 #undef __FUNCT__
2438 #define __FUNCT__ "DMPlexGetFullMeet"
2439 /*@C
2440   DMPlexGetFullMeet - Get an array for the meet of the set of points
2441 
2442   Not Collective
2443 
2444   Input Parameters:
2445 + dm - The DMPlex object
2446 . numPoints - The number of input points for the meet
2447 - points - The input points
2448 
2449   Output Parameters:
2450 + numCoveredPoints - The number of points in the meet
2451 - coveredPoints - The points in the meet
2452 
2453   Level: intermediate
2454 
2455   Fortran Notes:
2456   Since it returns an array, this routine is only available in Fortran 90, and you must
2457   include petsc.h90 in your code.
2458 
2459   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2460 
2461 .keywords: mesh
2462 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2463 @*/
2464 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2465 {
2466   DM_Plex       *mesh = (DM_Plex*) dm->data;
2467   PetscInt      *offsets, **closures;
2468   PetscInt      *meet[2];
2469   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2470   PetscInt       p, h, c, m;
2471   PetscErrorCode ierr;
2472 
2473   PetscFunctionBegin;
2474   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2475   PetscValidPointer(points, 2);
2476   PetscValidPointer(numCoveredPoints, 3);
2477   PetscValidPointer(coveredPoints, 4);
2478 
2479   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2480   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2481   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2482   maxSize = PetscPowInt(mesh->maxConeSize,height);
2483   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2484   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2485 
2486   for (p = 0; p < numPoints; ++p) {
2487     PetscInt closureSize;
2488 
2489     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2490 
2491     offsets[p*(height+2)+0] = 0;
2492     for (h = 0; h < height+1; ++h) {
2493       PetscInt pStart, pEnd, i;
2494 
2495       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2496       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2497         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2498           offsets[p*(height+2)+h+1] = i;
2499           break;
2500         }
2501       }
2502       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2503     }
2504     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);
2505   }
2506   for (h = 0; h < height+1; ++h) {
2507     PetscInt dof;
2508 
2509     /* Copy in cone of first point */
2510     dof = offsets[h+1] - offsets[h];
2511     for (meetSize = 0; meetSize < dof; ++meetSize) {
2512       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2513     }
2514     /* Check each successive cone */
2515     for (p = 1; p < numPoints && meetSize; ++p) {
2516       PetscInt newMeetSize = 0;
2517 
2518       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2519       for (c = 0; c < dof; ++c) {
2520         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2521 
2522         for (m = 0; m < meetSize; ++m) {
2523           if (point == meet[i][m]) {
2524             meet[1-i][newMeetSize++] = point;
2525             break;
2526           }
2527         }
2528       }
2529       meetSize = newMeetSize;
2530       i        = 1-i;
2531     }
2532     if (meetSize) break;
2533   }
2534   *numCoveredPoints = meetSize;
2535   *coveredPoints    = meet[i];
2536   for (p = 0; p < numPoints; ++p) {
2537     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2538   }
2539   ierr = PetscFree(closures);CHKERRQ(ierr);
2540   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2541   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2542   PetscFunctionReturn(0);
2543 }
2544 
2545 #undef __FUNCT__
2546 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2547 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2548 {
2549   MPI_Comm       comm;
2550   PetscErrorCode ierr;
2551 
2552   PetscFunctionBegin;
2553   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2554   PetscValidPointer(numFaceVertices,3);
2555   switch (cellDim) {
2556   case 0:
2557     *numFaceVertices = 0;
2558     break;
2559   case 1:
2560     *numFaceVertices = 1;
2561     break;
2562   case 2:
2563     switch (numCorners) {
2564     case 3: /* triangle */
2565       *numFaceVertices = 2; /* Edge has 2 vertices */
2566       break;
2567     case 4: /* quadrilateral */
2568       *numFaceVertices = 2; /* Edge has 2 vertices */
2569       break;
2570     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2571       *numFaceVertices = 3; /* Edge has 3 vertices */
2572       break;
2573     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2574       *numFaceVertices = 3; /* Edge has 3 vertices */
2575       break;
2576     default:
2577       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2578     }
2579     break;
2580   case 3:
2581     switch (numCorners) {
2582     case 4: /* tetradehdron */
2583       *numFaceVertices = 3; /* Face has 3 vertices */
2584       break;
2585     case 6: /* tet cohesive cells */
2586       *numFaceVertices = 4; /* Face has 4 vertices */
2587       break;
2588     case 8: /* hexahedron */
2589       *numFaceVertices = 4; /* Face has 4 vertices */
2590       break;
2591     case 9: /* tet cohesive Lagrange cells */
2592       *numFaceVertices = 6; /* Face has 6 vertices */
2593       break;
2594     case 10: /* quadratic tetrahedron */
2595       *numFaceVertices = 6; /* Face has 6 vertices */
2596       break;
2597     case 12: /* hex cohesive Lagrange cells */
2598       *numFaceVertices = 6; /* Face has 6 vertices */
2599       break;
2600     case 18: /* quadratic tet cohesive Lagrange cells */
2601       *numFaceVertices = 6; /* Face has 6 vertices */
2602       break;
2603     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2604       *numFaceVertices = 9; /* Face has 9 vertices */
2605       break;
2606     default:
2607       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2608     }
2609     break;
2610   default:
2611     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2612   }
2613   PetscFunctionReturn(0);
2614 }
2615 
2616 #undef __FUNCT__
2617 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2618 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2619 {
2620   const PetscInt maxFaceCases = 30;
2621   PetscInt       numFaceCases = 0;
2622   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2623   PetscInt      *off, *adj;
2624   PetscInt      *neighborCells, *tmpClosure;
2625   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2626   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2627   PetscErrorCode ierr;
2628 
2629   PetscFunctionBegin;
2630   /* For parallel partitioning, I think you have to communicate supports */
2631   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2632   cellDim = dim - cellHeight;
2633   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2634   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2635   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2636   if (cEnd - cStart == 0) {
2637     if (numVertices) *numVertices = 0;
2638     if (offsets)   *offsets   = NULL;
2639     if (adjacency) *adjacency = NULL;
2640     PetscFunctionReturn(0);
2641   }
2642   numCells  = cEnd - cStart;
2643   faceDepth = depth - cellHeight;
2644   /* Setup face recognition */
2645   if (faceDepth == 1) {
2646     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 */
2647 
2648     for (c = cStart; c < cEnd; ++c) {
2649       PetscInt corners;
2650 
2651       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2652       if (!cornersSeen[corners]) {
2653         PetscInt nFV;
2654 
2655         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2656         cornersSeen[corners] = 1;
2657 
2658         ierr = DMPlexGetNumFaceVertices_Internal(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2659 
2660         numFaceVertices[numFaceCases++] = nFV;
2661       }
2662     }
2663   }
2664   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2665   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2666   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2667   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2668   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2669   /* Count neighboring cells */
2670   for (cell = cStart; cell < cEnd; ++cell) {
2671     PetscInt numNeighbors = maxNeighbors, n;
2672 
2673     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2674     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2675     for (n = 0; n < numNeighbors; ++n) {
2676       PetscInt        cellPair[2];
2677       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2678       PetscInt        meetSize = 0;
2679       const PetscInt *meet    = NULL;
2680 
2681       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2682       if (cellPair[0] == cellPair[1]) continue;
2683       if (!found) {
2684         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2685         if (meetSize) {
2686           PetscInt f;
2687 
2688           for (f = 0; f < numFaceCases; ++f) {
2689             if (numFaceVertices[f] == meetSize) {
2690               found = PETSC_TRUE;
2691               break;
2692             }
2693           }
2694         }
2695         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2696       }
2697       if (found) ++off[cell-cStart+1];
2698     }
2699   }
2700   /* Prefix sum */
2701   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2702 
2703   if (adjacency) {
2704     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2705     /* Get neighboring cells */
2706     for (cell = cStart; cell < cEnd; ++cell) {
2707       PetscInt numNeighbors = maxNeighbors, n;
2708       PetscInt cellOffset   = 0;
2709 
2710       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2711       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2712       for (n = 0; n < numNeighbors; ++n) {
2713         PetscInt        cellPair[2];
2714         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2715         PetscInt        meetSize = 0;
2716         const PetscInt *meet    = NULL;
2717 
2718         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2719         if (cellPair[0] == cellPair[1]) continue;
2720         if (!found) {
2721           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2722           if (meetSize) {
2723             PetscInt f;
2724 
2725             for (f = 0; f < numFaceCases; ++f) {
2726               if (numFaceVertices[f] == meetSize) {
2727                 found = PETSC_TRUE;
2728                 break;
2729               }
2730             }
2731           }
2732           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2733         }
2734         if (found) {
2735           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2736           ++cellOffset;
2737         }
2738       }
2739     }
2740   }
2741   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2742   if (numVertices) *numVertices = numCells;
2743   if (offsets)   *offsets   = off;
2744   if (adjacency) *adjacency = adj;
2745   PetscFunctionReturn(0);
2746 }
2747 
2748 #if defined(PETSC_HAVE_CHACO)
2749 #if defined(PETSC_HAVE_UNISTD_H)
2750 #include <unistd.h>
2751 #endif
2752 /* Chaco does not have an include file */
2753 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2754                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2755                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2756                        int mesh_dims[3], double *goal, int global_method, int local_method,
2757                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2758 
2759 extern int FREE_GRAPH;
2760 
2761 #undef __FUNCT__
2762 #define __FUNCT__ "DMPlexPartition_Chaco"
2763 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2764 {
2765   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2766   MPI_Comm       comm;
2767   int            nvtxs          = numVertices; /* number of vertices in full graph */
2768   int           *vwgts          = NULL;   /* weights for all vertices */
2769   float         *ewgts          = NULL;   /* weights for all edges */
2770   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2771   char          *outassignname  = NULL;   /*  name of assignment output file */
2772   char          *outfilename    = NULL;   /* output file name */
2773   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2774   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2775   int            mesh_dims[3];            /* dimensions of mesh of processors */
2776   double        *goal          = NULL;    /* desired set sizes for each set */
2777   int            global_method = 1;       /* global partitioning algorithm */
2778   int            local_method  = 1;       /* local partitioning algorithm */
2779   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2780   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2781   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2782   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2783   long           seed          = 123636512; /* for random graph mutations */
2784   short int     *assignment;              /* Output partition */
2785   int            fd_stdout, fd_pipe[2];
2786   PetscInt      *points;
2787   PetscMPIInt    commSize;
2788   int            i, v, p;
2789   PetscErrorCode ierr;
2790 
2791   PetscFunctionBegin;
2792   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2793   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2794   if (!numVertices) {
2795     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2796     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2797     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2798     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2799     PetscFunctionReturn(0);
2800   }
2801   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2802   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2803 
2804   if (global_method == INERTIAL_METHOD) {
2805     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2806     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2807   }
2808   mesh_dims[0] = commSize;
2809   mesh_dims[1] = 1;
2810   mesh_dims[2] = 1;
2811   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2812   /* Chaco outputs to stdout. We redirect this to a buffer. */
2813   /* TODO: check error codes for UNIX calls */
2814 #if defined(PETSC_HAVE_UNISTD_H)
2815   {
2816     int piperet;
2817     piperet = pipe(fd_pipe);
2818     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2819     fd_stdout = dup(1);
2820     close(1);
2821     dup2(fd_pipe[1], 1);
2822   }
2823 #endif
2824   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2825                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2826                    vmax, ndims, eigtol, seed);
2827 #if defined(PETSC_HAVE_UNISTD_H)
2828   {
2829     char msgLog[10000];
2830     int  count;
2831 
2832     fflush(stdout);
2833     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2834     if (count < 0) count = 0;
2835     msgLog[count] = 0;
2836     close(1);
2837     dup2(fd_stdout, 1);
2838     close(fd_stdout);
2839     close(fd_pipe[0]);
2840     close(fd_pipe[1]);
2841     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2842   }
2843 #endif
2844   /* Convert to PetscSection+IS */
2845   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2846   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2847   for (v = 0; v < nvtxs; ++v) {
2848     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2849   }
2850   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2851   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2852   for (p = 0, i = 0; p < commSize; ++p) {
2853     for (v = 0; v < nvtxs; ++v) {
2854       if (assignment[v] == p) points[i++] = v;
2855     }
2856   }
2857   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2858   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2859   if (global_method == INERTIAL_METHOD) {
2860     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2861   }
2862   ierr = PetscFree(assignment);CHKERRQ(ierr);
2863   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2864   PetscFunctionReturn(0);
2865 }
2866 #endif
2867 
2868 #if defined(PETSC_HAVE_PARMETIS)
2869 #undef __FUNCT__
2870 #define __FUNCT__ "DMPlexPartition_ParMetis"
2871 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2872 {
2873   PetscFunctionBegin;
2874   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2875   PetscFunctionReturn(0);
2876 }
2877 #endif
2878 
2879 #undef __FUNCT__
2880 #define __FUNCT__ "DMPlexEnlargePartition"
2881 /* Expand the partition by BFS on the adjacency graph */
2882 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2883 {
2884   PetscHashI      h;
2885   const PetscInt *points;
2886   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2887   PetscInt        pStart, pEnd, part, q;
2888   PetscErrorCode  ierr;
2889 
2890   PetscFunctionBegin;
2891   PetscHashICreate(h);
2892   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2893   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2894   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2895   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2896   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2897   for (part = pStart; part < pEnd; ++part) {
2898     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2899 
2900     PetscHashIClear(h);
2901     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2902     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2903     /* Add all existing points to h */
2904     for (p = 0; p < numPoints; ++p) {
2905       const PetscInt point = points[off+p];
2906       PetscHashIAdd(h, point, 1);
2907     }
2908     PetscHashISize(h, nP);
2909     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2910     /* Add all points in next BFS level */
2911     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2912     for (p = 0; p < numPoints; ++p) {
2913       const PetscInt point = points[off+p];
2914       PetscInt       s     = start[point], e = start[point+1], a;
2915 
2916       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2917     }
2918     PetscHashISize(h, numNewPoints);
2919     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2920     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2921     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2922     totPoints += numNewPoints;
2923   }
2924   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2925   PetscHashIDestroy(h);
2926   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2927   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2928   for (part = pStart, q = 0; part < pEnd; ++part) {
2929     PetscInt numPoints, p;
2930 
2931     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2932     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2933     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2934   }
2935   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2936   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2937   PetscFunctionReturn(0);
2938 }
2939 
2940 #undef __FUNCT__
2941 #define __FUNCT__ "DMPlexCreatePartition"
2942 /*
2943   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2944 
2945   Collective on DM
2946 
2947   Input Parameters:
2948   + dm - The DM
2949   . height - The height for points in the partition
2950   - enlarge - Expand each partition with neighbors
2951 
2952   Output Parameters:
2953   + partSection - The PetscSection giving the division of points by partition
2954   . partition - The list of points by partition
2955   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2956   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2957 
2958   Level: developer
2959 
2960 .seealso DMPlexDistribute()
2961 */
2962 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2963 {
2964   PetscMPIInt    size;
2965   PetscErrorCode ierr;
2966 
2967   PetscFunctionBegin;
2968   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2969 
2970   *origPartSection = NULL;
2971   *origPartition   = NULL;
2972   if (size == 1) {
2973     PetscInt *points;
2974     PetscInt  cStart, cEnd, c;
2975 
2976     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2977     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2978     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2979     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2980     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2981     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2982     for (c = cStart; c < cEnd; ++c) points[c] = c;
2983     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2984     PetscFunctionReturn(0);
2985   }
2986   if (height == 0) {
2987     PetscInt  numVertices;
2988     PetscInt *start     = NULL;
2989     PetscInt *adjacency = NULL;
2990 
2991     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2992     if (1) {
2993 #if defined(PETSC_HAVE_CHACO)
2994       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2995 #endif
2996     } else {
2997 #if defined(PETSC_HAVE_PARMETIS)
2998       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2999 #endif
3000     }
3001     if (enlarge) {
3002       *origPartSection = *partSection;
3003       *origPartition   = *partition;
3004 
3005       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
3006     }
3007     ierr = PetscFree(start);CHKERRQ(ierr);
3008     ierr = PetscFree(adjacency);CHKERRQ(ierr);
3009 # if 0
3010   } else if (height == 1) {
3011     /* Build the dual graph for faces and partition the hypergraph */
3012     PetscInt numEdges;
3013 
3014     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
3015     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
3016     destroyCSR(numEdges, start, adjacency);
3017 #endif
3018   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
3019   PetscFunctionReturn(0);
3020 }
3021 
3022 #undef __FUNCT__
3023 #define __FUNCT__ "DMPlexCreatePartitionClosure"
3024 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
3025 {
3026   /* const PetscInt  height = 0; */
3027   const PetscInt *partArray;
3028   PetscInt       *allPoints, *partPoints = NULL;
3029   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
3030   PetscErrorCode  ierr;
3031 
3032   PetscFunctionBegin;
3033   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
3034   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
3035   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
3036   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
3037   for (rank = rStart; rank < rEnd; ++rank) {
3038     PetscInt partSize = 0;
3039     PetscInt numPoints, offset, p;
3040 
3041     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3042     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3043     for (p = 0; p < numPoints; ++p) {
3044       PetscInt  point   = partArray[offset+p], closureSize, c;
3045       PetscInt *closure = NULL;
3046 
3047       /* TODO Include support for height > 0 case */
3048       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3049       /* Merge into existing points */
3050       if (partSize+closureSize > maxPartSize) {
3051         PetscInt *tmpPoints;
3052 
3053         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3054         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3055         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3056         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3057 
3058         partPoints = tmpPoints;
3059       }
3060       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3061       partSize += closureSize;
3062 
3063       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3064       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3065     }
3066     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3067   }
3068   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3069   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3070   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3071 
3072   for (rank = rStart; rank < rEnd; ++rank) {
3073     PetscInt partSize = 0, newOffset;
3074     PetscInt numPoints, offset, p;
3075 
3076     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3077     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3078     for (p = 0; p < numPoints; ++p) {
3079       PetscInt  point   = partArray[offset+p], closureSize, c;
3080       PetscInt *closure = NULL;
3081 
3082       /* TODO Include support for height > 0 case */
3083       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3084       /* Merge into existing points */
3085       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3086       partSize += closureSize;
3087 
3088       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3089       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3090     }
3091     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3092     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3093   }
3094   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3095   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3096   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3097   PetscFunctionReturn(0);
3098 }
3099 
3100 #undef __FUNCT__
3101 #define __FUNCT__ "DMPlexDistributeField"
3102 /*
3103   Input Parameters:
3104 . originalSection
3105 , originalVec
3106 
3107   Output Parameters:
3108 . newSection
3109 . newVec
3110 */
3111 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3112 {
3113   PetscSF        fieldSF;
3114   PetscInt      *remoteOffsets, fieldSize;
3115   PetscScalar   *originalValues, *newValues;
3116   PetscErrorCode ierr;
3117 
3118   PetscFunctionBegin;
3119   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3120 
3121   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3122   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3123   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3124 
3125   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3126   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3127   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3128   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3129   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3130   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3131   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3132   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3133   PetscFunctionReturn(0);
3134 }
3135 
3136 #undef __FUNCT__
3137 #define __FUNCT__ "DMPlexDistribute"
3138 /*@C
3139   DMPlexDistribute - Distributes the mesh and any associated sections.
3140 
3141   Not Collective
3142 
3143   Input Parameter:
3144 + dm  - The original DMPlex object
3145 . partitioner - The partitioning package, or NULL for the default
3146 - overlap - The overlap of partitions, 0 is the default
3147 
3148   Output Parameter:
3149 . parallelMesh - The distributed DMPlex object, or NULL
3150 
3151   Note: If the mesh was not distributed, the return value is NULL
3152 
3153   Level: intermediate
3154 
3155 .keywords: mesh, elements
3156 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3157 @*/
3158 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3159 {
3160   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3161   MPI_Comm               comm;
3162   const PetscInt         height = 0;
3163   PetscInt               dim, numRemoteRanks;
3164   IS                     origCellPart,        cellPart,        part;
3165   PetscSection           origCellPartSection, cellPartSection, partSection;
3166   PetscSFNode           *remoteRanks;
3167   PetscSF                partSF, pointSF, coneSF;
3168   ISLocalToGlobalMapping renumbering;
3169   PetscSection           originalConeSection, newConeSection;
3170   PetscInt              *remoteOffsets;
3171   PetscInt              *cones, *newCones, newConesSize;
3172   PetscBool              flg;
3173   PetscMPIInt            rank, numProcs, p;
3174   PetscErrorCode         ierr;
3175 
3176   PetscFunctionBegin;
3177   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3178   PetscValidPointer(dmParallel,4);
3179 
3180   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3181   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3182   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3183   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3184 
3185   *dmParallel = NULL;
3186   if (numProcs == 1) PetscFunctionReturn(0);
3187 
3188   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3189   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3190   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3191   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3192   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3193   if (!rank) numRemoteRanks = numProcs;
3194   else       numRemoteRanks = 0;
3195   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3196   for (p = 0; p < numRemoteRanks; ++p) {
3197     remoteRanks[p].rank  = p;
3198     remoteRanks[p].index = 0;
3199   }
3200   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3201   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3202   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3203   if (flg) {
3204     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3205     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3206     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3207     if (origCellPart) {
3208       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3209       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3210       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3211     }
3212     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3213   }
3214   /* Close the partition over the mesh */
3215   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3216   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3217   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3218   /* Create new mesh */
3219   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3220   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3221   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3222   pmesh = (DM_Plex*) (*dmParallel)->data;
3223   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3224   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3225   if (flg) {
3226     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3227     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3228     ierr = ISView(part, NULL);CHKERRQ(ierr);
3229     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3230     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3231     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3232   }
3233   /* Distribute cone section */
3234   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3235   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3236   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3237   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3238   {
3239     PetscInt pStart, pEnd, p;
3240 
3241     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3242     for (p = pStart; p < pEnd; ++p) {
3243       PetscInt coneSize;
3244       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3245       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3246     }
3247   }
3248   /* Communicate and renumber cones */
3249   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3250   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3251   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3252   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3253   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3254   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3255   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3256   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3257   if (flg) {
3258     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3259     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3260     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3261     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3262     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3263   }
3264   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3265   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3266   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3267   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3268   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3269   /* Create supports and stratify sieve */
3270   {
3271     PetscInt pStart, pEnd;
3272 
3273     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3274     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3275   }
3276   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3277   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3278   /* Distribute Coordinates */
3279   {
3280     PetscSection originalCoordSection, newCoordSection;
3281     Vec          originalCoordinates, newCoordinates;
3282     const char  *name;
3283 
3284     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3285     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3286     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3287     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3288     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3289     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3290 
3291     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3292     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3293     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3294   }
3295   /* Distribute labels */
3296   {
3297     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3298     PetscInt numLabels = 0, l;
3299 
3300     /* Bcast number of labels */
3301     while (next) {
3302       ++numLabels; next = next->next;
3303     }
3304     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3305     next = mesh->labels;
3306     for (l = 0; l < numLabels; ++l) {
3307       DMLabel         newLabel;
3308       const PetscInt *partArray;
3309       char           *name;
3310       PetscInt       *stratumSizes = NULL, *points = NULL;
3311       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3312       PetscInt        nameSize, s, p;
3313       PetscBool       isdepth;
3314       size_t          len = 0;
3315 
3316       /* Bcast name (could filter for no points) */
3317       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3318       nameSize = len;
3319       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3320       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3321       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3322       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3323       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3324       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3325       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3326       newLabel->name = name;
3327       /* Bcast numStrata (could filter for no points in stratum) */
3328       if (!rank) newLabel->numStrata = next->numStrata;
3329       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3330       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3331                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3332                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3333       /* Bcast stratumValues (could filter for no points in stratum) */
3334       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3335       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3336       /* Find size on each process and Scatter */
3337       if (!rank) {
3338         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3339         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3340         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3341         for (s = 0; s < next->numStrata; ++s) {
3342           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3343             const PetscInt point = next->points[p];
3344             PetscInt       proc;
3345 
3346             for (proc = 0; proc < numProcs; ++proc) {
3347               PetscInt dof, off, pPart;
3348 
3349               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3350               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3351               for (pPart = off; pPart < off+dof; ++pPart) {
3352                 if (partArray[pPart] == point) {
3353                   ++stratumSizes[proc*next->numStrata+s];
3354                   break;
3355                 }
3356               }
3357             }
3358           }
3359         }
3360         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3361       }
3362       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3363       /* Calculate stratumOffsets */
3364       newLabel->stratumOffsets[0] = 0;
3365       for (s = 0; s < newLabel->numStrata; ++s) {
3366         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3367       }
3368       /* Pack points and Scatter */
3369       if (!rank) {
3370         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3371         displs[0] = 0;
3372         for (p = 0; p < numProcs; ++p) {
3373           sendcnts[p] = 0;
3374           for (s = 0; s < next->numStrata; ++s) {
3375             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3376           }
3377           offsets[p]  = displs[p];
3378           displs[p+1] = displs[p] + sendcnts[p];
3379         }
3380         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3381         for (s = 0; s < next->numStrata; ++s) {
3382           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3383             const PetscInt point = next->points[p];
3384             PetscInt       proc;
3385 
3386             for (proc = 0; proc < numProcs; ++proc) {
3387               PetscInt dof, off, pPart;
3388 
3389               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3390               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3391               for (pPart = off; pPart < off+dof; ++pPart) {
3392                 if (partArray[pPart] == point) {
3393                   points[offsets[proc]++] = point;
3394                   break;
3395                 }
3396               }
3397             }
3398           }
3399         }
3400       }
3401       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3402       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3403       ierr = PetscFree(points);CHKERRQ(ierr);
3404       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3405       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3406       /* Renumber points */
3407       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3408       /* Sort points */
3409       for (s = 0; s < newLabel->numStrata; ++s) {
3410         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3411       }
3412       /* Insert into list */
3413       if (newNext) newNext->next = newLabel;
3414       else pmesh->labels = newLabel;
3415       newNext = newLabel;
3416       if (!rank) next = next->next;
3417     }
3418   }
3419   /* Cleanup Partition */
3420   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3421   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3422   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3423   ierr = ISDestroy(&part);CHKERRQ(ierr);
3424   /* Create point SF for parallel mesh */
3425   {
3426     const PetscInt *leaves;
3427     PetscSFNode    *remotePoints, *rowners, *lowners;
3428     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3429     PetscInt        pStart, pEnd;
3430 
3431     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3432     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3433     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3434     for (p=0; p<numRoots; p++) {
3435       rowners[p].rank  = -1;
3436       rowners[p].index = -1;
3437     }
3438     if (origCellPart) {
3439       /* Make sure cells in the original partition are not assigned to other procs */
3440       const PetscInt *origCells;
3441 
3442       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3443       for (p = 0; p < numProcs; ++p) {
3444         PetscInt dof, off, d;
3445 
3446         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3447         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3448         for (d = off; d < off+dof; ++d) {
3449           rowners[origCells[d]].rank = p;
3450         }
3451       }
3452       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3453     }
3454     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3455     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3456 
3457     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3458     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3459     for (p = 0; p < numLeaves; ++p) {
3460       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3461         lowners[p].rank  = rank;
3462         lowners[p].index = leaves ? leaves[p] : p;
3463       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3464         lowners[p].rank  = -2;
3465         lowners[p].index = -2;
3466       }
3467     }
3468     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3469       rowners[p].rank  = -3;
3470       rowners[p].index = -3;
3471     }
3472     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3473     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3474     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3475     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3476     for (p = 0; p < numLeaves; ++p) {
3477       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3478       if (lowners[p].rank != rank) ++numGhostPoints;
3479     }
3480     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3481     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3482     for (p = 0, gp = 0; p < numLeaves; ++p) {
3483       if (lowners[p].rank != rank) {
3484         ghostPoints[gp]        = leaves ? leaves[p] : p;
3485         remotePoints[gp].rank  = lowners[p].rank;
3486         remotePoints[gp].index = lowners[p].index;
3487         ++gp;
3488       }
3489     }
3490     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3491     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3492     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3493   }
3494   /* Cleanup */
3495   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3496   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3497   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3498   PetscFunctionReturn(0);
3499 }
3500 
3501 #if defined(PETSC_HAVE_TRIANGLE)
3502 #include <triangle.h>
3503 
3504 #undef __FUNCT__
3505 #define __FUNCT__ "InitInput_Triangle"
3506 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3507 {
3508   PetscFunctionBegin;
3509   inputCtx->numberofpoints             = 0;
3510   inputCtx->numberofpointattributes    = 0;
3511   inputCtx->pointlist                  = NULL;
3512   inputCtx->pointattributelist         = NULL;
3513   inputCtx->pointmarkerlist            = NULL;
3514   inputCtx->numberofsegments           = 0;
3515   inputCtx->segmentlist                = NULL;
3516   inputCtx->segmentmarkerlist          = NULL;
3517   inputCtx->numberoftriangleattributes = 0;
3518   inputCtx->trianglelist               = NULL;
3519   inputCtx->numberofholes              = 0;
3520   inputCtx->holelist                   = NULL;
3521   inputCtx->numberofregions            = 0;
3522   inputCtx->regionlist                 = NULL;
3523   PetscFunctionReturn(0);
3524 }
3525 
3526 #undef __FUNCT__
3527 #define __FUNCT__ "InitOutput_Triangle"
3528 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3529 {
3530   PetscFunctionBegin;
3531   outputCtx->numberofpoints        = 0;
3532   outputCtx->pointlist             = NULL;
3533   outputCtx->pointattributelist    = NULL;
3534   outputCtx->pointmarkerlist       = NULL;
3535   outputCtx->numberoftriangles     = 0;
3536   outputCtx->trianglelist          = NULL;
3537   outputCtx->triangleattributelist = NULL;
3538   outputCtx->neighborlist          = NULL;
3539   outputCtx->segmentlist           = NULL;
3540   outputCtx->segmentmarkerlist     = NULL;
3541   outputCtx->numberofedges         = 0;
3542   outputCtx->edgelist              = NULL;
3543   outputCtx->edgemarkerlist        = NULL;
3544   PetscFunctionReturn(0);
3545 }
3546 
3547 #undef __FUNCT__
3548 #define __FUNCT__ "FiniOutput_Triangle"
3549 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3550 {
3551   PetscFunctionBegin;
3552   free(outputCtx->pointmarkerlist);
3553   free(outputCtx->edgelist);
3554   free(outputCtx->edgemarkerlist);
3555   free(outputCtx->trianglelist);
3556   free(outputCtx->neighborlist);
3557   PetscFunctionReturn(0);
3558 }
3559 
3560 #undef __FUNCT__
3561 #define __FUNCT__ "DMPlexGenerate_Triangle"
3562 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3563 {
3564   MPI_Comm             comm;
3565   PetscInt             dim              = 2;
3566   const PetscBool      createConvexHull = PETSC_FALSE;
3567   const PetscBool      constrained      = PETSC_FALSE;
3568   struct triangulateio in;
3569   struct triangulateio out;
3570   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3571   PetscMPIInt          rank;
3572   PetscErrorCode       ierr;
3573 
3574   PetscFunctionBegin;
3575   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3576   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3577   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3578   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3579   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3580 
3581   in.numberofpoints = vEnd - vStart;
3582   if (in.numberofpoints > 0) {
3583     PetscSection coordSection;
3584     Vec          coordinates;
3585     PetscScalar *array;
3586 
3587     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3588     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3589     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3590     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3591     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3592     for (v = vStart; v < vEnd; ++v) {
3593       const PetscInt idx = v - vStart;
3594       PetscInt       off, d;
3595 
3596       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3597       for (d = 0; d < dim; ++d) {
3598         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3599       }
3600       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3601     }
3602     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3603   }
3604   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3605   in.numberofsegments = eEnd - eStart;
3606   if (in.numberofsegments > 0) {
3607     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3608     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3609     for (e = eStart; e < eEnd; ++e) {
3610       const PetscInt  idx = e - eStart;
3611       const PetscInt *cone;
3612 
3613       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3614 
3615       in.segmentlist[idx*2+0] = cone[0] - vStart;
3616       in.segmentlist[idx*2+1] = cone[1] - vStart;
3617 
3618       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3619     }
3620   }
3621 #if 0 /* Do not currently support holes */
3622   PetscReal *holeCoords;
3623   PetscInt   h, d;
3624 
3625   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3626   if (in.numberofholes > 0) {
3627     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3628     for (h = 0; h < in.numberofholes; ++h) {
3629       for (d = 0; d < dim; ++d) {
3630         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3631       }
3632     }
3633   }
3634 #endif
3635   if (!rank) {
3636     char args[32];
3637 
3638     /* Take away 'Q' for verbose output */
3639     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3640     if (createConvexHull) {
3641       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3642     }
3643     if (constrained) {
3644       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3645     }
3646     triangulate(args, &in, &out, NULL);
3647   }
3648   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3649   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3650   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3651   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3652   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3653 
3654   {
3655     const PetscInt numCorners  = 3;
3656     const PetscInt numCells    = out.numberoftriangles;
3657     const PetscInt numVertices = out.numberofpoints;
3658     const int     *cells      = out.trianglelist;
3659     const double  *meshCoords = out.pointlist;
3660 
3661     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3662     /* Set labels */
3663     for (v = 0; v < numVertices; ++v) {
3664       if (out.pointmarkerlist[v]) {
3665         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3666       }
3667     }
3668     if (interpolate) {
3669       for (e = 0; e < out.numberofedges; e++) {
3670         if (out.edgemarkerlist[e]) {
3671           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3672           const PetscInt *edges;
3673           PetscInt        numEdges;
3674 
3675           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3676           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3677           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3678           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3679         }
3680       }
3681     }
3682     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3683   }
3684 #if 0 /* Do not currently support holes */
3685   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3686 #endif
3687   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3688   PetscFunctionReturn(0);
3689 }
3690 
3691 #undef __FUNCT__
3692 #define __FUNCT__ "DMPlexRefine_Triangle"
3693 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3694 {
3695   MPI_Comm             comm;
3696   PetscInt             dim  = 2;
3697   struct triangulateio in;
3698   struct triangulateio out;
3699   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3700   PetscMPIInt          rank;
3701   PetscErrorCode       ierr;
3702 
3703   PetscFunctionBegin;
3704   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3705   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3706   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3707   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3708   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3709   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3710   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3711 
3712   in.numberofpoints = vEnd - vStart;
3713   if (in.numberofpoints > 0) {
3714     PetscSection coordSection;
3715     Vec          coordinates;
3716     PetscScalar *array;
3717 
3718     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3719     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3720     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3721     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3722     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3723     for (v = vStart; v < vEnd; ++v) {
3724       const PetscInt idx = v - vStart;
3725       PetscInt       off, d;
3726 
3727       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3728       for (d = 0; d < dim; ++d) {
3729         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3730       }
3731       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3732     }
3733     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3734   }
3735   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3736 
3737   in.numberofcorners   = 3;
3738   in.numberoftriangles = cEnd - cStart;
3739 
3740   in.trianglearealist  = (double*) maxVolumes;
3741   if (in.numberoftriangles > 0) {
3742     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3743     for (c = cStart; c < cEnd; ++c) {
3744       const PetscInt idx      = c - cStart;
3745       PetscInt      *closure = NULL;
3746       PetscInt       closureSize;
3747 
3748       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3749       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3750       for (v = 0; v < 3; ++v) {
3751         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3752       }
3753       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3754     }
3755   }
3756   /* TODO: Segment markers are missing on input */
3757 #if 0 /* Do not currently support holes */
3758   PetscReal *holeCoords;
3759   PetscInt   h, d;
3760 
3761   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3762   if (in.numberofholes > 0) {
3763     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3764     for (h = 0; h < in.numberofholes; ++h) {
3765       for (d = 0; d < dim; ++d) {
3766         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3767       }
3768     }
3769   }
3770 #endif
3771   if (!rank) {
3772     char args[32];
3773 
3774     /* Take away 'Q' for verbose output */
3775     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3776     triangulate(args, &in, &out, NULL);
3777   }
3778   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3779   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3780   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3781   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3782   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3783 
3784   {
3785     const PetscInt numCorners  = 3;
3786     const PetscInt numCells    = out.numberoftriangles;
3787     const PetscInt numVertices = out.numberofpoints;
3788     const int     *cells      = out.trianglelist;
3789     const double  *meshCoords = out.pointlist;
3790     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3791 
3792     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3793     /* Set labels */
3794     for (v = 0; v < numVertices; ++v) {
3795       if (out.pointmarkerlist[v]) {
3796         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3797       }
3798     }
3799     if (interpolate) {
3800       PetscInt e;
3801 
3802       for (e = 0; e < out.numberofedges; e++) {
3803         if (out.edgemarkerlist[e]) {
3804           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3805           const PetscInt *edges;
3806           PetscInt        numEdges;
3807 
3808           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3809           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3810           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3811           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3812         }
3813       }
3814     }
3815     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3816   }
3817 #if 0 /* Do not currently support holes */
3818   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3819 #endif
3820   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3821   PetscFunctionReturn(0);
3822 }
3823 #endif
3824 
3825 #if defined(PETSC_HAVE_TETGEN)
3826 #include <tetgen.h>
3827 #undef __FUNCT__
3828 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3829 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3830 {
3831   MPI_Comm       comm;
3832   const PetscInt dim  = 3;
3833   ::tetgenio     in;
3834   ::tetgenio     out;
3835   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3836   PetscMPIInt    rank;
3837   PetscErrorCode ierr;
3838 
3839   PetscFunctionBegin;
3840   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3841   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3842   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3843   in.numberofpoints = vEnd - vStart;
3844   if (in.numberofpoints > 0) {
3845     PetscSection coordSection;
3846     Vec          coordinates;
3847     PetscScalar *array;
3848 
3849     in.pointlist       = new double[in.numberofpoints*dim];
3850     in.pointmarkerlist = new int[in.numberofpoints];
3851 
3852     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3853     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3854     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3855     for (v = vStart; v < vEnd; ++v) {
3856       const PetscInt idx = v - vStart;
3857       PetscInt       off, d;
3858 
3859       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3860       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3861       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3862     }
3863     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3864   }
3865   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3866 
3867   in.numberoffacets = fEnd - fStart;
3868   if (in.numberoffacets > 0) {
3869     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3870     in.facetmarkerlist = new int[in.numberoffacets];
3871     for (f = fStart; f < fEnd; ++f) {
3872       const PetscInt idx     = f - fStart;
3873       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3874 
3875       in.facetlist[idx].numberofpolygons = 1;
3876       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3877       in.facetlist[idx].numberofholes    = 0;
3878       in.facetlist[idx].holelist         = NULL;
3879 
3880       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3881       for (p = 0; p < numPoints*2; p += 2) {
3882         const PetscInt point = points[p];
3883         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3884       }
3885 
3886       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3887       poly->numberofvertices = numVertices;
3888       poly->vertexlist       = new int[poly->numberofvertices];
3889       for (v = 0; v < numVertices; ++v) {
3890         const PetscInt vIdx = points[v] - vStart;
3891         poly->vertexlist[v] = vIdx;
3892       }
3893       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3894       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3895     }
3896   }
3897   if (!rank) {
3898     char args[32];
3899 
3900     /* Take away 'Q' for verbose output */
3901     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3902     ::tetrahedralize(args, &in, &out);
3903   }
3904   {
3905     const PetscInt numCorners  = 4;
3906     const PetscInt numCells    = out.numberoftetrahedra;
3907     const PetscInt numVertices = out.numberofpoints;
3908     const int     *cells      = out.tetrahedronlist;
3909     const double  *meshCoords = out.pointlist;
3910 
3911     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3912     /* Set labels */
3913     for (v = 0; v < numVertices; ++v) {
3914       if (out.pointmarkerlist[v]) {
3915         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3916       }
3917     }
3918     if (interpolate) {
3919       PetscInt e;
3920 
3921       for (e = 0; e < out.numberofedges; e++) {
3922         if (out.edgemarkerlist[e]) {
3923           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3924           const PetscInt *edges;
3925           PetscInt        numEdges;
3926 
3927           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3928           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3929           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3930           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3931         }
3932       }
3933       for (f = 0; f < out.numberoftrifaces; f++) {
3934         if (out.trifacemarkerlist[f]) {
3935           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3936           const PetscInt *faces;
3937           PetscInt        numFaces;
3938 
3939           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3940           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3941           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3942           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3943         }
3944       }
3945     }
3946     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3947   }
3948   PetscFunctionReturn(0);
3949 }
3950 
3951 #undef __FUNCT__
3952 #define __FUNCT__ "DMPlexRefine_Tetgen"
3953 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3954 {
3955   MPI_Comm       comm;
3956   const PetscInt dim  = 3;
3957   ::tetgenio     in;
3958   ::tetgenio     out;
3959   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3960   PetscMPIInt    rank;
3961   PetscErrorCode ierr;
3962 
3963   PetscFunctionBegin;
3964   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3965   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3966   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3967   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3968   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3969 
3970   in.numberofpoints = vEnd - vStart;
3971   if (in.numberofpoints > 0) {
3972     PetscSection coordSection;
3973     Vec          coordinates;
3974     PetscScalar *array;
3975 
3976     in.pointlist       = new double[in.numberofpoints*dim];
3977     in.pointmarkerlist = new int[in.numberofpoints];
3978 
3979     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3980     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3981     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3982     for (v = vStart; v < vEnd; ++v) {
3983       const PetscInt idx = v - vStart;
3984       PetscInt       off, d;
3985 
3986       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3987       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3988       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3989     }
3990     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3991   }
3992   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3993 
3994   in.numberofcorners       = 4;
3995   in.numberoftetrahedra    = cEnd - cStart;
3996   in.tetrahedronvolumelist = (double*) maxVolumes;
3997   if (in.numberoftetrahedra > 0) {
3998     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3999     for (c = cStart; c < cEnd; ++c) {
4000       const PetscInt idx      = c - cStart;
4001       PetscInt      *closure = NULL;
4002       PetscInt       closureSize;
4003 
4004       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4005       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4006       for (v = 0; v < 4; ++v) {
4007         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4008       }
4009       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4010     }
4011   }
4012   /* TODO: Put in boundary faces with markers */
4013   if (!rank) {
4014     char args[32];
4015 
4016     /* Take away 'Q' for verbose output */
4017     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
4018     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
4019     ::tetrahedralize(args, &in, &out);
4020   }
4021   in.tetrahedronvolumelist = NULL;
4022 
4023   {
4024     const PetscInt numCorners  = 4;
4025     const PetscInt numCells    = out.numberoftetrahedra;
4026     const PetscInt numVertices = out.numberofpoints;
4027     const int     *cells      = out.tetrahedronlist;
4028     const double  *meshCoords = out.pointlist;
4029     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4030 
4031     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4032     /* Set labels */
4033     for (v = 0; v < numVertices; ++v) {
4034       if (out.pointmarkerlist[v]) {
4035         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4036       }
4037     }
4038     if (interpolate) {
4039       PetscInt e, f;
4040 
4041       for (e = 0; e < out.numberofedges; e++) {
4042         if (out.edgemarkerlist[e]) {
4043           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4044           const PetscInt *edges;
4045           PetscInt        numEdges;
4046 
4047           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4048           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4049           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4050           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4051         }
4052       }
4053       for (f = 0; f < out.numberoftrifaces; f++) {
4054         if (out.trifacemarkerlist[f]) {
4055           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4056           const PetscInt *faces;
4057           PetscInt        numFaces;
4058 
4059           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4060           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4061           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4062           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4063         }
4064       }
4065     }
4066     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4067   }
4068   PetscFunctionReturn(0);
4069 }
4070 #endif
4071 
4072 #if defined(PETSC_HAVE_CTETGEN)
4073 #include "ctetgen.h"
4074 
4075 #undef __FUNCT__
4076 #define __FUNCT__ "DMPlexGenerate_CTetgen"
4077 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4078 {
4079   MPI_Comm       comm;
4080   const PetscInt dim  = 3;
4081   PLC           *in, *out;
4082   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4083   PetscMPIInt    rank;
4084   PetscErrorCode ierr;
4085 
4086   PetscFunctionBegin;
4087   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4088   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
4089   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4090   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4091   ierr = PLCCreate(&in);CHKERRQ(ierr);
4092   ierr = PLCCreate(&out);CHKERRQ(ierr);
4093 
4094   in->numberofpoints = vEnd - vStart;
4095   if (in->numberofpoints > 0) {
4096     PetscSection coordSection;
4097     Vec          coordinates;
4098     PetscScalar *array;
4099 
4100     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4101     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4102     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4103     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4104     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4105     for (v = vStart; v < vEnd; ++v) {
4106       const PetscInt idx = v - vStart;
4107       PetscInt       off, d, m;
4108 
4109       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4110       for (d = 0; d < dim; ++d) {
4111         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4112       }
4113       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
4114 
4115       in->pointmarkerlist[idx] = (int) m;
4116     }
4117     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4118   }
4119   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4120 
4121   in->numberoffacets = fEnd - fStart;
4122   if (in->numberoffacets > 0) {
4123     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
4124     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
4125     for (f = fStart; f < fEnd; ++f) {
4126       const PetscInt idx     = f - fStart;
4127       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
4128       polygon       *poly;
4129 
4130       in->facetlist[idx].numberofpolygons = 1;
4131 
4132       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
4133 
4134       in->facetlist[idx].numberofholes    = 0;
4135       in->facetlist[idx].holelist         = NULL;
4136 
4137       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4138       for (p = 0; p < numPoints*2; p += 2) {
4139         const PetscInt point = points[p];
4140         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4141       }
4142 
4143       poly                   = in->facetlist[idx].polygonlist;
4144       poly->numberofvertices = numVertices;
4145       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
4146       for (v = 0; v < numVertices; ++v) {
4147         const PetscInt vIdx = points[v] - vStart;
4148         poly->vertexlist[v] = vIdx;
4149       }
4150       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
4151       in->facetmarkerlist[idx] = (int) m;
4152       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4153     }
4154   }
4155   if (!rank) {
4156     TetGenOpts t;
4157 
4158     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4159     t.in        = boundary; /* Should go away */
4160     t.plc       = 1;
4161     t.quality   = 1;
4162     t.edgesout  = 1;
4163     t.zeroindex = 1;
4164     t.quiet     = 1;
4165     t.verbose   = verbose;
4166     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
4167     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4168   }
4169   {
4170     const PetscInt numCorners  = 4;
4171     const PetscInt numCells    = out->numberoftetrahedra;
4172     const PetscInt numVertices = out->numberofpoints;
4173     const int     *cells      = out->tetrahedronlist;
4174     const double  *meshCoords = out->pointlist;
4175 
4176     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4177     /* Set labels */
4178     for (v = 0; v < numVertices; ++v) {
4179       if (out->pointmarkerlist[v]) {
4180         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
4181       }
4182     }
4183     if (interpolate) {
4184       PetscInt e;
4185 
4186       for (e = 0; e < out->numberofedges; e++) {
4187         if (out->edgemarkerlist[e]) {
4188           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4189           const PetscInt *edges;
4190           PetscInt        numEdges;
4191 
4192           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4193           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4194           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
4195           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4196         }
4197       }
4198       for (f = 0; f < out->numberoftrifaces; f++) {
4199         if (out->trifacemarkerlist[f]) {
4200           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4201           const PetscInt *faces;
4202           PetscInt        numFaces;
4203 
4204           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4205           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4206           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
4207           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4208         }
4209       }
4210     }
4211     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4212   }
4213 
4214   ierr = PLCDestroy(&in);CHKERRQ(ierr);
4215   ierr = PLCDestroy(&out);CHKERRQ(ierr);
4216   PetscFunctionReturn(0);
4217 }
4218 
4219 #undef __FUNCT__
4220 #define __FUNCT__ "DMPlexRefine_CTetgen"
4221 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
4222 {
4223   MPI_Comm       comm;
4224   const PetscInt dim  = 3;
4225   PLC           *in, *out;
4226   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4227   PetscMPIInt    rank;
4228   PetscErrorCode ierr;
4229 
4230   PetscFunctionBegin;
4231   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4232   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
4233   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4234   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4235   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4236   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4237   ierr = PLCCreate(&in);CHKERRQ(ierr);
4238   ierr = PLCCreate(&out);CHKERRQ(ierr);
4239 
4240   in->numberofpoints = vEnd - vStart;
4241   if (in->numberofpoints > 0) {
4242     PetscSection coordSection;
4243     Vec          coordinates;
4244     PetscScalar *array;
4245 
4246     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4247     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4248     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4249     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4250     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4251     for (v = vStart; v < vEnd; ++v) {
4252       const PetscInt idx = v - vStart;
4253       PetscInt       off, d, m;
4254 
4255       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4256       for (d = 0; d < dim; ++d) {
4257         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4258       }
4259       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
4260 
4261       in->pointmarkerlist[idx] = (int) m;
4262     }
4263     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4264   }
4265   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4266 
4267   in->numberofcorners       = 4;
4268   in->numberoftetrahedra    = cEnd - cStart;
4269   in->tetrahedronvolumelist = maxVolumes;
4270   if (in->numberoftetrahedra > 0) {
4271     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
4272     for (c = cStart; c < cEnd; ++c) {
4273       const PetscInt idx      = c - cStart;
4274       PetscInt      *closure = NULL;
4275       PetscInt       closureSize;
4276 
4277       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4278       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4279       for (v = 0; v < 4; ++v) {
4280         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4281       }
4282       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4283     }
4284   }
4285   if (!rank) {
4286     TetGenOpts t;
4287 
4288     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4289 
4290     t.in        = dm; /* Should go away */
4291     t.refine    = 1;
4292     t.varvolume = 1;
4293     t.quality   = 1;
4294     t.edgesout  = 1;
4295     t.zeroindex = 1;
4296     t.quiet     = 1;
4297     t.verbose   = verbose; /* Change this */
4298 
4299     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4300     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4301   }
4302   {
4303     const PetscInt numCorners  = 4;
4304     const PetscInt numCells    = out->numberoftetrahedra;
4305     const PetscInt numVertices = out->numberofpoints;
4306     const int     *cells       = out->tetrahedronlist;
4307     const double  *meshCoords  = out->pointlist;
4308     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4309 
4310     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4311     /* Set labels */
4312     for (v = 0; v < numVertices; ++v) {
4313       if (out->pointmarkerlist[v]) {
4314         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
4315       }
4316     }
4317     if (interpolate) {
4318       PetscInt e, f;
4319 
4320       for (e = 0; e < out->numberofedges; e++) {
4321         if (out->edgemarkerlist[e]) {
4322           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4323           const PetscInt *edges;
4324           PetscInt        numEdges;
4325 
4326           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4327           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4328           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
4329           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4330         }
4331       }
4332       for (f = 0; f < out->numberoftrifaces; f++) {
4333         if (out->trifacemarkerlist[f]) {
4334           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4335           const PetscInt *faces;
4336           PetscInt        numFaces;
4337 
4338           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4339           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4340           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
4341           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4342         }
4343       }
4344     }
4345     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4346   }
4347   ierr = PLCDestroy(&in);CHKERRQ(ierr);
4348   ierr = PLCDestroy(&out);CHKERRQ(ierr);
4349   PetscFunctionReturn(0);
4350 }
4351 #endif
4352 
4353 #undef __FUNCT__
4354 #define __FUNCT__ "DMPlexGenerate"
4355 /*@C
4356   DMPlexGenerate - Generates a mesh.
4357 
4358   Not Collective
4359 
4360   Input Parameters:
4361 + boundary - The DMPlex boundary object
4362 . name - The mesh generation package name
4363 - interpolate - Flag to create intermediate mesh elements
4364 
4365   Output Parameter:
4366 . mesh - The DMPlex object
4367 
4368   Level: intermediate
4369 
4370 .keywords: mesh, elements
4371 .seealso: DMPlexCreate(), DMRefine()
4372 @*/
4373 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
4374 {
4375   PetscInt       dim;
4376   char           genname[1024];
4377   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4378   PetscErrorCode ierr;
4379 
4380   PetscFunctionBegin;
4381   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
4382   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
4383   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
4384   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4385   if (flg) name = genname;
4386   if (name) {
4387     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4388     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4389     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4390   }
4391   switch (dim) {
4392   case 1:
4393     if (!name || isTriangle) {
4394 #if defined(PETSC_HAVE_TRIANGLE)
4395       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
4396 #else
4397       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4398 #endif
4399     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4400     break;
4401   case 2:
4402     if (!name || isCTetgen) {
4403 #if defined(PETSC_HAVE_CTETGEN)
4404       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4405 #else
4406       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4407 #endif
4408     } else if (isTetgen) {
4409 #if defined(PETSC_HAVE_TETGEN)
4410       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4411 #else
4412       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4413 #endif
4414     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4415     break;
4416   default:
4417     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4418   }
4419   PetscFunctionReturn(0);
4420 }
4421 
4422 typedef PetscInt CellRefiner;
4423 
4424 #undef __FUNCT__
4425 #define __FUNCT__ "GetDepthStart_Private"
4426 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
4427 {
4428   PetscFunctionBegin;
4429   if (cStart) *cStart = 0;
4430   if (vStart) *vStart = depthSize[depth];
4431   if (fStart) *fStart = depthSize[depth] + depthSize[0];
4432   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4433   PetscFunctionReturn(0);
4434 }
4435 
4436 #undef __FUNCT__
4437 #define __FUNCT__ "GetDepthEnd_Private"
4438 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
4439 {
4440   PetscFunctionBegin;
4441   if (cEnd) *cEnd = depthSize[depth];
4442   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
4443   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4444   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
4445   PetscFunctionReturn(0);
4446 }
4447 
4448 #undef __FUNCT__
4449 #define __FUNCT__ "CellRefinerGetSizes"
4450 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
4451 {
4452   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
4453   PetscErrorCode ierr;
4454 
4455   PetscFunctionBegin;
4456   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4457   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4458   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4459   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4460   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4461   switch (refiner) {
4462   case 1:
4463     /* Simplicial 2D */
4464     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
4465     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
4466     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
4467     break;
4468   case 3:
4469     /* Hybrid 2D */
4470     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4471     cMax = PetscMin(cEnd, cMax);
4472     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4473     fMax         = PetscMin(fEnd, fMax);
4474     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
4475     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 */
4476     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
4477     break;
4478   case 2:
4479     /* Hex 2D */
4480     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
4481     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
4482     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
4483     break;
4484   default:
4485     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4486   }
4487   PetscFunctionReturn(0);
4488 }
4489 
4490 #undef __FUNCT__
4491 #define __FUNCT__ "CellRefinerSetConeSizes"
4492 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4493 {
4494   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
4495   PetscErrorCode ierr;
4496 
4497   PetscFunctionBegin;
4498   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4499   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4500   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4501   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4502   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4503   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4504   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4505   switch (refiner) {
4506   case 1:
4507     /* Simplicial 2D */
4508     /* All cells have 3 faces */
4509     for (c = cStart; c < cEnd; ++c) {
4510       for (r = 0; r < 4; ++r) {
4511         const PetscInt newp = (c - cStart)*4 + r;
4512 
4513         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4514       }
4515     }
4516     /* Split faces have 2 vertices and the same cells as the parent */
4517     for (f = fStart; f < fEnd; ++f) {
4518       for (r = 0; r < 2; ++r) {
4519         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4520         PetscInt       size;
4521 
4522         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4523         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4524         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4525       }
4526     }
4527     /* Interior faces have 2 vertices and 2 cells */
4528     for (c = cStart; c < cEnd; ++c) {
4529       for (r = 0; r < 3; ++r) {
4530         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4531 
4532         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4533         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4534       }
4535     }
4536     /* Old vertices have identical supports */
4537     for (v = vStart; v < vEnd; ++v) {
4538       const PetscInt newp = vStartNew + (v - vStart);
4539       PetscInt       size;
4540 
4541       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4542       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4543     }
4544     /* Face vertices have 2 + cells*2 supports */
4545     for (f = fStart; f < fEnd; ++f) {
4546       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4547       PetscInt       size;
4548 
4549       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4550       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
4551     }
4552     break;
4553   case 2:
4554     /* Hex 2D */
4555     /* All cells have 4 faces */
4556     for (c = cStart; c < cEnd; ++c) {
4557       for (r = 0; r < 4; ++r) {
4558         const PetscInt newp = (c - cStart)*4 + r;
4559 
4560         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4561       }
4562     }
4563     /* Split faces have 2 vertices and the same cells as the parent */
4564     for (f = fStart; f < fEnd; ++f) {
4565       for (r = 0; r < 2; ++r) {
4566         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4567         PetscInt       size;
4568 
4569         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4570         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4571         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4572       }
4573     }
4574     /* Interior faces have 2 vertices and 2 cells */
4575     for (c = cStart; c < cEnd; ++c) {
4576       for (r = 0; r < 4; ++r) {
4577         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4578 
4579         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4580         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4581       }
4582     }
4583     /* Old vertices have identical supports */
4584     for (v = vStart; v < vEnd; ++v) {
4585       const PetscInt newp = vStartNew + (v - vStart);
4586       PetscInt       size;
4587 
4588       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4589       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4590     }
4591     /* Face vertices have 2 + cells supports */
4592     for (f = fStart; f < fEnd; ++f) {
4593       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4594       PetscInt       size;
4595 
4596       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4597       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
4598     }
4599     /* Cell vertices have 4 supports */
4600     for (c = cStart; c < cEnd; ++c) {
4601       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4602 
4603       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
4604     }
4605     break;
4606   case 3:
4607     /* Hybrid 2D */
4608     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4609     cMax = PetscMin(cEnd, cMax);
4610     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4611     fMax = PetscMin(fEnd, fMax);
4612     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4613     /* Interior cells have 3 faces */
4614     for (c = cStart; c < cMax; ++c) {
4615       for (r = 0; r < 4; ++r) {
4616         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
4617 
4618         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4619       }
4620     }
4621     /* Hybrid cells have 4 faces */
4622     for (c = cMax; c < cEnd; ++c) {
4623       for (r = 0; r < 2; ++r) {
4624         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
4625 
4626         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4627       }
4628     }
4629     /* Interior split faces have 2 vertices and the same cells as the parent */
4630     for (f = fStart; f < fMax; ++f) {
4631       for (r = 0; r < 2; ++r) {
4632         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4633         PetscInt       size;
4634 
4635         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4636         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4637         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4638       }
4639     }
4640     /* Interior cell faces have 2 vertices and 2 cells */
4641     for (c = cStart; c < cMax; ++c) {
4642       for (r = 0; r < 3; ++r) {
4643         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4644 
4645         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4646         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4647       }
4648     }
4649     /* Hybrid faces have 2 vertices and the same cells */
4650     for (f = fMax; f < fEnd; ++f) {
4651       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4652       PetscInt       size;
4653 
4654       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4655       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4656       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4657     }
4658     /* Hybrid cell faces have 2 vertices and 2 cells */
4659     for (c = cMax; c < cEnd; ++c) {
4660       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4661 
4662       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4663       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4664     }
4665     /* Old vertices have identical supports */
4666     for (v = vStart; v < vEnd; ++v) {
4667       const PetscInt newp = vStartNew + (v - vStart);
4668       PetscInt       size;
4669 
4670       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4671       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4672     }
4673     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4674     for (f = fStart; f < fMax; ++f) {
4675       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4676       const PetscInt *support;
4677       PetscInt       size, newSize = 2, s;
4678 
4679       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4680       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4681       for (s = 0; s < size; ++s) {
4682         if (support[s] >= cMax) newSize += 1;
4683         else newSize += 2;
4684       }
4685       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
4686     }
4687     break;
4688   default:
4689     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4690   }
4691   PetscFunctionReturn(0);
4692 }
4693 
4694 #undef __FUNCT__
4695 #define __FUNCT__ "CellRefinerSetCones"
4696 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4697 {
4698   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;
4699   PetscInt       maxSupportSize, *supportRef;
4700   PetscErrorCode ierr;
4701 
4702   PetscFunctionBegin;
4703   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4704   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4705   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4706   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4707   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4708   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4709   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4710   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
4711   switch (refiner) {
4712   case 1:
4713     /* Simplicial 2D */
4714     /*
4715      2
4716      |\
4717      | \
4718      |  \
4719      |   \
4720      | C  \
4721      |     \
4722      |      \
4723      2---1---1
4724      |\  D  / \
4725      | 2   0   \
4726      |A \ /  B  \
4727      0---0-------1
4728      */
4729     /* All cells have 3 faces */
4730     for (c = cStart; c < cEnd; ++c) {
4731       const PetscInt  newp = cStartNew + (c - cStart)*4;
4732       const PetscInt *cone, *ornt;
4733       PetscInt        coneNew[3], orntNew[3];
4734 
4735       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4736       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4737       /* A triangle */
4738       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4739       orntNew[0] = ornt[0];
4740       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4741       orntNew[1] = -2;
4742       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4743       orntNew[2] = ornt[2];
4744       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4745       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4746 #if 1
4747       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);
4748       for (p = 0; p < 3; ++p) {
4749         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);
4750       }
4751 #endif
4752       /* B triangle */
4753       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4754       orntNew[0] = ornt[0];
4755       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4756       orntNew[1] = ornt[1];
4757       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4758       orntNew[2] = -2;
4759       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4760       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4761 #if 1
4762       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);
4763       for (p = 0; p < 3; ++p) {
4764         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);
4765       }
4766 #endif
4767       /* C triangle */
4768       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4769       orntNew[0] = -2;
4770       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4771       orntNew[1] = ornt[1];
4772       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4773       orntNew[2] = ornt[2];
4774       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4775       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4776 #if 1
4777       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);
4778       for (p = 0; p < 3; ++p) {
4779         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);
4780       }
4781 #endif
4782       /* D triangle */
4783       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4784       orntNew[0] = 0;
4785       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4786       orntNew[1] = 0;
4787       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4788       orntNew[2] = 0;
4789       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4790       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4791 #if 1
4792       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);
4793       for (p = 0; p < 3; ++p) {
4794         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);
4795       }
4796 #endif
4797     }
4798     /* Split faces have 2 vertices and the same cells as the parent */
4799     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4800     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4801     for (f = fStart; f < fEnd; ++f) {
4802       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4803 
4804       for (r = 0; r < 2; ++r) {
4805         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4806         const PetscInt *cone, *support;
4807         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4808 
4809         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4810         coneNew[0]       = vStartNew + (cone[0] - vStart);
4811         coneNew[1]       = vStartNew + (cone[1] - vStart);
4812         coneNew[(r+1)%2] = newv;
4813         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4814 #if 1
4815         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4816         for (p = 0; p < 2; ++p) {
4817           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);
4818         }
4819 #endif
4820         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4821         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4822         for (s = 0; s < supportSize; ++s) {
4823           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4824           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4825           for (c = 0; c < coneSize; ++c) {
4826             if (cone[c] == f) break;
4827           }
4828           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4829         }
4830         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4831 #if 1
4832         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4833         for (p = 0; p < supportSize; ++p) {
4834           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);
4835         }
4836 #endif
4837       }
4838     }
4839     /* Interior faces have 2 vertices and 2 cells */
4840     for (c = cStart; c < cEnd; ++c) {
4841       const PetscInt *cone;
4842 
4843       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4844       for (r = 0; r < 3; ++r) {
4845         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4846         PetscInt       coneNew[2];
4847         PetscInt       supportNew[2];
4848 
4849         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4850         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4851         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4852 #if 1
4853         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4854         for (p = 0; p < 2; ++p) {
4855           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);
4856         }
4857 #endif
4858         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4859         supportNew[1] = (c - cStart)*4 + 3;
4860         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4861 #if 1
4862         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4863         for (p = 0; p < 2; ++p) {
4864           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);
4865         }
4866 #endif
4867       }
4868     }
4869     /* Old vertices have identical supports */
4870     for (v = vStart; v < vEnd; ++v) {
4871       const PetscInt  newp = vStartNew + (v - vStart);
4872       const PetscInt *support, *cone;
4873       PetscInt        size, s;
4874 
4875       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4876       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4877       for (s = 0; s < size; ++s) {
4878         PetscInt r = 0;
4879 
4880         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4881         if (cone[1] == v) r = 1;
4882         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4883       }
4884       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4885 #if 1
4886       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4887       for (p = 0; p < size; ++p) {
4888         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);
4889       }
4890 #endif
4891     }
4892     /* Face vertices have 2 + cells*2 supports */
4893     for (f = fStart; f < fEnd; ++f) {
4894       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4895       const PetscInt *cone, *support;
4896       PetscInt        size, s;
4897 
4898       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4899       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4900       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4901       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4902       for (s = 0; s < size; ++s) {
4903         PetscInt r = 0;
4904 
4905         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4906         if      (cone[1] == f) r = 1;
4907         else if (cone[2] == f) r = 2;
4908         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4909         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4910       }
4911       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4912 #if 1
4913       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4914       for (p = 0; p < 2+size*2; ++p) {
4915         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);
4916       }
4917 #endif
4918     }
4919     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4920     break;
4921   case 2:
4922     /* Hex 2D */
4923     /*
4924      3---------2---------2
4925      |         |         |
4926      |    D    2    C    |
4927      |         |         |
4928      3----3----0----1----1
4929      |         |         |
4930      |    A    0    B    |
4931      |         |         |
4932      0---------0---------1
4933      */
4934     /* All cells have 4 faces */
4935     for (c = cStart; c < cEnd; ++c) {
4936       const PetscInt  newp = (c - cStart)*4;
4937       const PetscInt *cone, *ornt;
4938       PetscInt        coneNew[4], orntNew[4];
4939 
4940       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4941       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4942       /* A quad */
4943       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4944       orntNew[0] = ornt[0];
4945       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4946       orntNew[1] = 0;
4947       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4948       orntNew[2] = -2;
4949       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4950       orntNew[3] = ornt[3];
4951       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4952       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4953 #if 1
4954       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);
4955       for (p = 0; p < 4; ++p) {
4956         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);
4957       }
4958 #endif
4959       /* B quad */
4960       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4961       orntNew[0] = ornt[0];
4962       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4963       orntNew[1] = ornt[1];
4964       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4965       orntNew[2] = 0;
4966       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4967       orntNew[3] = -2;
4968       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4969       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4970 #if 1
4971       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);
4972       for (p = 0; p < 4; ++p) {
4973         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);
4974       }
4975 #endif
4976       /* C quad */
4977       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4978       orntNew[0] = -2;
4979       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4980       orntNew[1] = ornt[1];
4981       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4982       orntNew[2] = ornt[2];
4983       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4984       orntNew[3] = 0;
4985       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4986       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4987 #if 1
4988       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);
4989       for (p = 0; p < 4; ++p) {
4990         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);
4991       }
4992 #endif
4993       /* D quad */
4994       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4995       orntNew[0] = 0;
4996       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4997       orntNew[1] = -2;
4998       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4999       orntNew[2] = ornt[2];
5000       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
5001       orntNew[3] = ornt[3];
5002       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5003       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5004 #if 1
5005       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);
5006       for (p = 0; p < 4; ++p) {
5007         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);
5008       }
5009 #endif
5010     }
5011     /* Split faces have 2 vertices and the same cells as the parent */
5012     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5013     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5014     for (f = fStart; f < fEnd; ++f) {
5015       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5016 
5017       for (r = 0; r < 2; ++r) {
5018         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5019         const PetscInt *cone, *support;
5020         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5021 
5022         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5023         coneNew[0]       = vStartNew + (cone[0] - vStart);
5024         coneNew[1]       = vStartNew + (cone[1] - vStart);
5025         coneNew[(r+1)%2] = newv;
5026         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5027 #if 1
5028         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5029         for (p = 0; p < 2; ++p) {
5030           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);
5031         }
5032 #endif
5033         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5034         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5035         for (s = 0; s < supportSize; ++s) {
5036           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5037           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5038           for (c = 0; c < coneSize; ++c) {
5039             if (cone[c] == f) break;
5040           }
5041           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
5042         }
5043         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5044 #if 1
5045         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5046         for (p = 0; p < supportSize; ++p) {
5047           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);
5048         }
5049 #endif
5050       }
5051     }
5052     /* Interior faces have 2 vertices and 2 cells */
5053     for (c = cStart; c < cEnd; ++c) {
5054       const PetscInt *cone;
5055       PetscInt        coneNew[2], supportNew[2];
5056 
5057       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5058       for (r = 0; r < 4; ++r) {
5059         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5060 
5061         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5062         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5063         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5064 #if 1
5065         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5066         for (p = 0; p < 2; ++p) {
5067           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);
5068         }
5069 #endif
5070         supportNew[0] = (c - cStart)*4 + r;
5071         supportNew[1] = (c - cStart)*4 + (r+1)%4;
5072         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5073 #if 1
5074         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5075         for (p = 0; p < 2; ++p) {
5076           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);
5077         }
5078 #endif
5079       }
5080     }
5081     /* Old vertices have identical supports */
5082     for (v = vStart; v < vEnd; ++v) {
5083       const PetscInt  newp = vStartNew + (v - vStart);
5084       const PetscInt *support, *cone;
5085       PetscInt        size, s;
5086 
5087       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5088       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5089       for (s = 0; s < size; ++s) {
5090         PetscInt r = 0;
5091 
5092         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5093         if (cone[1] == v) r = 1;
5094         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5095       }
5096       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5097 #if 1
5098       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5099       for (p = 0; p < size; ++p) {
5100         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);
5101       }
5102 #endif
5103     }
5104     /* Face vertices have 2 + cells supports */
5105     for (f = fStart; f < fEnd; ++f) {
5106       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5107       const PetscInt *cone, *support;
5108       PetscInt        size, s;
5109 
5110       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5111       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5112       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5113       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5114       for (s = 0; s < size; ++s) {
5115         PetscInt r = 0;
5116 
5117         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5118         if      (cone[1] == f) r = 1;
5119         else if (cone[2] == f) r = 2;
5120         else if (cone[3] == f) r = 3;
5121         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
5122       }
5123       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5124 #if 1
5125       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5126       for (p = 0; p < 2+size; ++p) {
5127         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);
5128       }
5129 #endif
5130     }
5131     /* Cell vertices have 4 supports */
5132     for (c = cStart; c < cEnd; ++c) {
5133       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5134       PetscInt       supportNew[4];
5135 
5136       for (r = 0; r < 4; ++r) {
5137         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5138       }
5139       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5140     }
5141     break;
5142   case 3:
5143     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5144     cMax = PetscMin(cEnd, cMax);
5145     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5146     fMax = PetscMin(fEnd, fMax);
5147     /* Interior cells have 3 faces */
5148     for (c = cStart; c < cMax; ++c) {
5149       const PetscInt  newp = cStartNew + (c - cStart)*4;
5150       const PetscInt *cone, *ornt;
5151       PetscInt        coneNew[3], orntNew[3];
5152 
5153       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5154       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5155       /* A triangle */
5156       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5157       orntNew[0] = ornt[0];
5158       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
5159       orntNew[1] = -2;
5160       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5161       orntNew[2] = ornt[2];
5162       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5163       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5164 #if 1
5165       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);
5166       for (p = 0; p < 3; ++p) {
5167         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);
5168       }
5169 #endif
5170       /* B triangle */
5171       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5172       orntNew[0] = ornt[0];
5173       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5174       orntNew[1] = ornt[1];
5175       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
5176       orntNew[2] = -2;
5177       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5178       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5179 #if 1
5180       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);
5181       for (p = 0; p < 3; ++p) {
5182         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);
5183       }
5184 #endif
5185       /* C triangle */
5186       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
5187       orntNew[0] = -2;
5188       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5189       orntNew[1] = ornt[1];
5190       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5191       orntNew[2] = ornt[2];
5192       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5193       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5194 #if 1
5195       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);
5196       for (p = 0; p < 3; ++p) {
5197         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);
5198       }
5199 #endif
5200       /* D triangle */
5201       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
5202       orntNew[0] = 0;
5203       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
5204       orntNew[1] = 0;
5205       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
5206       orntNew[2] = 0;
5207       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5208       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5209 #if 1
5210       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);
5211       for (p = 0; p < 3; ++p) {
5212         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);
5213       }
5214 #endif
5215     }
5216     /*
5217      2----3----3
5218      |         |
5219      |    B    |
5220      |         |
5221      0----4--- 1
5222      |         |
5223      |    A    |
5224      |         |
5225      0----2----1
5226      */
5227     /* Hybrid cells have 4 faces */
5228     for (c = cMax; c < cEnd; ++c) {
5229       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
5230       const PetscInt *cone, *ornt;
5231       PetscInt        coneNew[4], orntNew[4];
5232 
5233       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5234       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5235       /* A quad */
5236       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5237       orntNew[0] = ornt[0];
5238       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5239       orntNew[1] = ornt[1];
5240       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
5241       orntNew[2] = 0;
5242       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
5243       orntNew[3] = 0;
5244       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5245       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5246 #if 1
5247       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);
5248       for (p = 0; p < 4; ++p) {
5249         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);
5250       }
5251 #endif
5252       /* B quad */
5253       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5254       orntNew[0] = ornt[0];
5255       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5256       orntNew[1] = ornt[1];
5257       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
5258       orntNew[2] = 0;
5259       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
5260       orntNew[3] = 0;
5261       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5262       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5263 #if 1
5264       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);
5265       for (p = 0; p < 4; ++p) {
5266         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);
5267       }
5268 #endif
5269     }
5270     /* Interior split faces have 2 vertices and the same cells as the parent */
5271     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5272     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5273     for (f = fStart; f < fMax; ++f) {
5274       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5275 
5276       for (r = 0; r < 2; ++r) {
5277         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5278         const PetscInt *cone, *support;
5279         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5280 
5281         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5282         coneNew[0]       = vStartNew + (cone[0] - vStart);
5283         coneNew[1]       = vStartNew + (cone[1] - vStart);
5284         coneNew[(r+1)%2] = newv;
5285         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5286 #if 1
5287         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5288         for (p = 0; p < 2; ++p) {
5289           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);
5290         }
5291 #endif
5292         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5293         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5294         for (s = 0; s < supportSize; ++s) {
5295           if (support[s] >= cMax) {
5296             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
5297           } else {
5298             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5299             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5300             for (c = 0; c < coneSize; ++c) {
5301               if (cone[c] == f) break;
5302             }
5303             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5304           }
5305         }
5306         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5307 #if 1
5308         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5309         for (p = 0; p < supportSize; ++p) {
5310           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);
5311         }
5312 #endif
5313       }
5314     }
5315     /* Interior cell faces have 2 vertices and 2 cells */
5316     for (c = cStart; c < cMax; ++c) {
5317       const PetscInt *cone;
5318 
5319       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5320       for (r = 0; r < 3; ++r) {
5321         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5322         PetscInt       coneNew[2];
5323         PetscInt       supportNew[2];
5324 
5325         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5326         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5327         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5328 #if 1
5329         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5330         for (p = 0; p < 2; ++p) {
5331           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);
5332         }
5333 #endif
5334         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5335         supportNew[1] = (c - cStart)*4 + 3;
5336         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5337 #if 1
5338         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5339         for (p = 0; p < 2; ++p) {
5340           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);
5341         }
5342 #endif
5343       }
5344     }
5345     /* Interior hybrid faces have 2 vertices and the same cells */
5346     for (f = fMax; f < fEnd; ++f) {
5347       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5348       const PetscInt *cone;
5349       const PetscInt *support;
5350       PetscInt        coneNew[2];
5351       PetscInt        supportNew[2];
5352       PetscInt        size, s, r;
5353 
5354       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5355       coneNew[0] = vStartNew + (cone[0] - vStart);
5356       coneNew[1] = vStartNew + (cone[1] - vStart);
5357       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5358 #if 1
5359       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5360       for (p = 0; p < 2; ++p) {
5361         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);
5362       }
5363 #endif
5364       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5365       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5366       for (s = 0; s < size; ++s) {
5367         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5368         for (r = 0; r < 2; ++r) {
5369           if (cone[r+2] == f) break;
5370         }
5371         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
5372       }
5373       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5374 #if 1
5375       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5376       for (p = 0; p < size; ++p) {
5377         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);
5378       }
5379 #endif
5380     }
5381     /* Cell hybrid faces have 2 vertices and 2 cells */
5382     for (c = cMax; c < cEnd; ++c) {
5383       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5384       const PetscInt *cone;
5385       PetscInt        coneNew[2];
5386       PetscInt        supportNew[2];
5387 
5388       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5389       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
5390       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
5391       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5392 #if 1
5393       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5394       for (p = 0; p < 2; ++p) {
5395         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);
5396       }
5397 #endif
5398       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
5399       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
5400       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5401 #if 1
5402       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5403       for (p = 0; p < 2; ++p) {
5404         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);
5405       }
5406 #endif
5407     }
5408     /* Old vertices have identical supports */
5409     for (v = vStart; v < vEnd; ++v) {
5410       const PetscInt  newp = vStartNew + (v - vStart);
5411       const PetscInt *support, *cone;
5412       PetscInt        size, s;
5413 
5414       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5415       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5416       for (s = 0; s < size; ++s) {
5417         if (support[s] >= fMax) {
5418           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
5419         } else {
5420           PetscInt r = 0;
5421 
5422           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5423           if (cone[1] == v) r = 1;
5424           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5425         }
5426       }
5427       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5428 #if 1
5429       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5430       for (p = 0; p < size; ++p) {
5431         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);
5432       }
5433 #endif
5434     }
5435     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5436     for (f = fStart; f < fMax; ++f) {
5437       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5438       const PetscInt *cone, *support;
5439       PetscInt        size, newSize = 2, s;
5440 
5441       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5442       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5443       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5444       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5445       for (s = 0; s < size; ++s) {
5446         PetscInt r = 0;
5447 
5448         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5449         if (support[s] >= cMax) {
5450           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
5451 
5452           newSize += 1;
5453         } else {
5454           if      (cone[1] == f) r = 1;
5455           else if (cone[2] == f) r = 2;
5456           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5457           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
5458 
5459           newSize += 2;
5460         }
5461       }
5462       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5463 #if 1
5464       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5465       for (p = 0; p < newSize; ++p) {
5466         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);
5467       }
5468 #endif
5469     }
5470     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5471     break;
5472   default:
5473     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5474   }
5475   PetscFunctionReturn(0);
5476 }
5477 
5478 #undef __FUNCT__
5479 #define __FUNCT__ "CellRefinerSetCoordinates"
5480 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5481 {
5482   PetscSection   coordSection, coordSectionNew;
5483   Vec            coordinates, coordinatesNew;
5484   PetscScalar   *coords, *coordsNew;
5485   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
5486   PetscErrorCode ierr;
5487 
5488   PetscFunctionBegin;
5489   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5490   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5491   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5492   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5493   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5494   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
5495   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5496   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5497   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5498   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5499   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5500   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
5501   if (fMax < 0) fMax = fEnd;
5502   switch (refiner) {
5503   case 1:
5504   case 2:
5505   case 3:
5506     /* Simplicial and Hex 2D */
5507     /* All vertices have the dim coordinates */
5508     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5509       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5510       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5511     }
5512     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5513     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5514     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5515     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5516     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5517     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5518     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5519     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5520     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5521     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5522     /* Old vertices have the same coordinates */
5523     for (v = vStart; v < vEnd; ++v) {
5524       const PetscInt newv = vStartNew + (v - vStart);
5525       PetscInt       off, offnew, d;
5526 
5527       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5528       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5529       for (d = 0; d < dim; ++d) {
5530         coordsNew[offnew+d] = coords[off+d];
5531       }
5532     }
5533     /* Face vertices have the average of endpoint coordinates */
5534     for (f = fStart; f < fMax; ++f) {
5535       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5536       const PetscInt *cone;
5537       PetscInt        coneSize, offA, offB, offnew, d;
5538 
5539       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5540       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5541       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5542       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5543       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5544       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5545       for (d = 0; d < dim; ++d) {
5546         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5547       }
5548     }
5549     /* Just Hex 2D */
5550     if (refiner == 2) {
5551       /* Cell vertices have the average of corner coordinates */
5552       for (c = cStart; c < cEnd; ++c) {
5553         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5554         PetscInt      *cone = NULL;
5555         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5556 
5557         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5558         for (p = 0; p < closureSize*2; p += 2) {
5559           const PetscInt point = cone[p];
5560           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5561         }
5562         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5563         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5564         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5565         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5566         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5567         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5568         for (d = 0; d < dim; ++d) {
5569           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5570         }
5571         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5572       }
5573     }
5574     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5575     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5576     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5577     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5578     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5579     break;
5580   default:
5581     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5582   }
5583   PetscFunctionReturn(0);
5584 }
5585 
5586 #undef __FUNCT__
5587 #define __FUNCT__ "DMPlexCreateProcessSF"
5588 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5589 {
5590   PetscInt           numRoots, numLeaves, l;
5591   const PetscInt    *localPoints;
5592   const PetscSFNode *remotePoints;
5593   PetscInt          *localPointsNew;
5594   PetscSFNode       *remotePointsNew;
5595   PetscInt          *ranks, *ranksNew;
5596   PetscErrorCode     ierr;
5597 
5598   PetscFunctionBegin;
5599   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5600   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5601   for (l = 0; l < numLeaves; ++l) {
5602     ranks[l] = remotePoints[l].rank;
5603   }
5604   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5605   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
5606   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5607   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5608   for (l = 0; l < numLeaves; ++l) {
5609     ranksNew[l]              = ranks[l];
5610     localPointsNew[l]        = l;
5611     remotePointsNew[l].index = 0;
5612     remotePointsNew[l].rank  = ranksNew[l];
5613   }
5614   ierr = PetscFree(ranks);CHKERRQ(ierr);
5615   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5616   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5617   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5618   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5619   PetscFunctionReturn(0);
5620 }
5621 
5622 #undef __FUNCT__
5623 #define __FUNCT__ "CellRefinerCreateSF"
5624 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5625 {
5626   PetscSF            sf, sfNew, sfProcess;
5627   IS                 processRanks;
5628   MPI_Datatype       depthType;
5629   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5630   const PetscInt    *localPoints, *neighbors;
5631   const PetscSFNode *remotePoints;
5632   PetscInt          *localPointsNew;
5633   PetscSFNode       *remotePointsNew;
5634   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5635   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5636   PetscErrorCode     ierr;
5637 
5638   PetscFunctionBegin;
5639   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5640   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5641   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5642   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5643   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5644   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5645   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5646   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5647   switch (refiner) {
5648   case 3:
5649     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5650     cMax = PetscMin(cEnd, cMax);
5651     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5652     fMax = PetscMin(fEnd, fMax);
5653   }
5654   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5655   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5656   /* Caculate size of new SF */
5657   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5658   if (numRoots < 0) PetscFunctionReturn(0);
5659   for (l = 0; l < numLeaves; ++l) {
5660     const PetscInt p = localPoints[l];
5661 
5662     switch (refiner) {
5663     case 1:
5664       /* Simplicial 2D */
5665       if ((p >= vStart) && (p < vEnd)) {
5666         /* Old vertices stay the same */
5667         ++numLeavesNew;
5668       } else if ((p >= fStart) && (p < fEnd)) {
5669         /* Old faces add new faces and vertex */
5670         numLeavesNew += 1 + 2;
5671       } else if ((p >= cStart) && (p < cEnd)) {
5672         /* Old cells add new cells and interior faces */
5673         numLeavesNew += 4 + 3;
5674       }
5675       break;
5676     case 2:
5677       /* Hex 2D */
5678       if ((p >= vStart) && (p < vEnd)) {
5679         /* Old vertices stay the same */
5680         ++numLeavesNew;
5681       } else if ((p >= fStart) && (p < fEnd)) {
5682         /* Old faces add new faces and vertex */
5683         numLeavesNew += 1 + 2;
5684       } else if ((p >= cStart) && (p < cEnd)) {
5685         /* Old cells add new cells and interior faces */
5686         numLeavesNew += 4 + 4;
5687       }
5688       break;
5689     default:
5690       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5691     }
5692   }
5693   /* Communicate depthSizes for each remote rank */
5694   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5695   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5696   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
5697   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);
5698   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5699   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5700   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5701   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5702   for (n = 0; n < numNeighbors; ++n) {
5703     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5704   }
5705   depthSizeOld[depth]   = cMax;
5706   depthSizeOld[0]       = vMax;
5707   depthSizeOld[depth-1] = fMax;
5708   depthSizeOld[1]       = eMax;
5709 
5710   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5711   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5712 
5713   depthSizeOld[depth]   = cEnd - cStart;
5714   depthSizeOld[0]       = vEnd - vStart;
5715   depthSizeOld[depth-1] = fEnd - fStart;
5716   depthSizeOld[1]       = eEnd - eStart;
5717 
5718   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5719   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5720   for (n = 0; n < numNeighbors; ++n) {
5721     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5722   }
5723   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5724   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5725   /* Calculate new point SF */
5726   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5727   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5728   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5729   for (l = 0, m = 0; l < numLeaves; ++l) {
5730     PetscInt    p     = localPoints[l];
5731     PetscInt    rp    = remotePoints[l].index, n;
5732     PetscMPIInt rrank = remotePoints[l].rank;
5733 
5734     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5735     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5736     switch (refiner) {
5737     case 1:
5738       /* Simplicial 2D */
5739       if ((p >= vStart) && (p < vEnd)) {
5740         /* Old vertices stay the same */
5741         localPointsNew[m]        = vStartNew     + (p  - vStart);
5742         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5743         remotePointsNew[m].rank  = rrank;
5744         ++m;
5745       } else if ((p >= fStart) && (p < fEnd)) {
5746         /* Old faces add new faces and vertex */
5747         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5748         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5749         remotePointsNew[m].rank  = rrank;
5750         ++m;
5751         for (r = 0; r < 2; ++r, ++m) {
5752           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5753           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5754           remotePointsNew[m].rank  = rrank;
5755         }
5756       } else if ((p >= cStart) && (p < cEnd)) {
5757         /* Old cells add new cells and interior faces */
5758         for (r = 0; r < 4; ++r, ++m) {
5759           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5760           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5761           remotePointsNew[m].rank  = rrank;
5762         }
5763         for (r = 0; r < 3; ++r, ++m) {
5764           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5765           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5766           remotePointsNew[m].rank  = rrank;
5767         }
5768       }
5769       break;
5770     case 2:
5771       /* Hex 2D */
5772       if ((p >= vStart) && (p < vEnd)) {
5773         /* Old vertices stay the same */
5774         localPointsNew[m]        = vStartNew     + (p  - vStart);
5775         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5776         remotePointsNew[m].rank  = rrank;
5777         ++m;
5778       } else if ((p >= fStart) && (p < fEnd)) {
5779         /* Old faces add new faces and vertex */
5780         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5781         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5782         remotePointsNew[m].rank  = rrank;
5783         ++m;
5784         for (r = 0; r < 2; ++r, ++m) {
5785           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5786           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5787           remotePointsNew[m].rank  = rrank;
5788         }
5789       } else if ((p >= cStart) && (p < cEnd)) {
5790         /* Old cells add new cells and interior faces */
5791         for (r = 0; r < 4; ++r, ++m) {
5792           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5793           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5794           remotePointsNew[m].rank  = rrank;
5795         }
5796         for (r = 0; r < 4; ++r, ++m) {
5797           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5798           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5799           remotePointsNew[m].rank  = rrank;
5800         }
5801       }
5802       break;
5803     case 3:
5804       /* Hybrid simplicial 2D */
5805       if ((p >= vStart) && (p < vEnd)) {
5806         /* Old vertices stay the same */
5807         localPointsNew[m]        = vStartNew     + (p  - vStart);
5808         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5809         remotePointsNew[m].rank  = rrank;
5810         ++m;
5811       } else if ((p >= fStart) && (p < fMax)) {
5812         /* Old interior faces add new faces and vertex */
5813         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5814         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5815         remotePointsNew[m].rank  = rrank;
5816         ++m;
5817         for (r = 0; r < 2; ++r, ++m) {
5818           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5819           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5820           remotePointsNew[m].rank  = rrank;
5821         }
5822       } else if ((p >= fMax) && (p < fEnd)) {
5823         /* Old hybrid faces stay the same */
5824         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5825         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5826         remotePointsNew[m].rank  = rrank;
5827         ++m;
5828       } else if ((p >= cStart) && (p < cMax)) {
5829         /* Old interior cells add new cells and interior faces */
5830         for (r = 0; r < 4; ++r, ++m) {
5831           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5832           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5833           remotePointsNew[m].rank  = rrank;
5834         }
5835         for (r = 0; r < 3; ++r, ++m) {
5836           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5837           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5838           remotePointsNew[m].rank  = rrank;
5839         }
5840       } else if ((p >= cStart) && (p < cMax)) {
5841         /* Old hybrid cells add new cells and hybrid face */
5842         for (r = 0; r < 2; ++r, ++m) {
5843           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5844           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5845           remotePointsNew[m].rank  = rrank;
5846         }
5847         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5848         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]);
5849         remotePointsNew[m].rank  = rrank;
5850         ++m;
5851       }
5852       break;
5853     default:
5854       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5855     }
5856   }
5857   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5858   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5859   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5860   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5861   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5862   PetscFunctionReturn(0);
5863 }
5864 
5865 #undef __FUNCT__
5866 #define __FUNCT__ "CellRefinerCreateLabels"
5867 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5868 {
5869   PetscInt       numLabels, l;
5870   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
5871   PetscErrorCode ierr;
5872 
5873   PetscFunctionBegin;
5874   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5875   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5876   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5877   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5878 
5879   cStartNew = 0;
5880   vStartNew = depthSize[2];
5881   fStartNew = depthSize[2] + depthSize[0];
5882 
5883   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5884   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5885   switch (refiner) {
5886   case 3:
5887     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5888     cMax = PetscMin(cEnd, cMax);
5889     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5890     fMax = PetscMin(fEnd, fMax);
5891   }
5892   for (l = 0; l < numLabels; ++l) {
5893     DMLabel         label, labelNew;
5894     const char     *lname;
5895     PetscBool       isDepth;
5896     IS              valueIS;
5897     const PetscInt *values;
5898     PetscInt        numValues, val;
5899 
5900     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5901     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5902     if (isDepth) continue;
5903     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5904     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5905     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5906     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5907     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5908     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5909     for (val = 0; val < numValues; ++val) {
5910       IS              pointIS;
5911       const PetscInt *points;
5912       PetscInt        numPoints, n;
5913 
5914       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5915       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5916       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5917       for (n = 0; n < numPoints; ++n) {
5918         const PetscInt p = points[n];
5919         switch (refiner) {
5920         case 1:
5921           /* Simplicial 2D */
5922           if ((p >= vStart) && (p < vEnd)) {
5923             /* Old vertices stay the same */
5924             newp = vStartNew + (p - vStart);
5925             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5926           } else if ((p >= fStart) && (p < fEnd)) {
5927             /* Old faces add new faces and vertex */
5928             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5929             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5930             for (r = 0; r < 2; ++r) {
5931               newp = fStartNew + (p - fStart)*2 + r;
5932               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5933             }
5934           } else if ((p >= cStart) && (p < cEnd)) {
5935             /* Old cells add new cells and interior faces */
5936             for (r = 0; r < 4; ++r) {
5937               newp = cStartNew + (p - cStart)*4 + r;
5938               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5939             }
5940             for (r = 0; r < 3; ++r) {
5941               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5942               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5943             }
5944           }
5945           break;
5946         case 2:
5947           /* Hex 2D */
5948           if ((p >= vStart) && (p < vEnd)) {
5949             /* Old vertices stay the same */
5950             newp = vStartNew + (p - vStart);
5951             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5952           } else if ((p >= fStart) && (p < fEnd)) {
5953             /* Old faces add new faces and vertex */
5954             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5955             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5956             for (r = 0; r < 2; ++r) {
5957               newp = fStartNew + (p - fStart)*2 + r;
5958               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5959             }
5960           } else if ((p >= cStart) && (p < cEnd)) {
5961             /* Old cells add new cells and interior faces and vertex */
5962             for (r = 0; r < 4; ++r) {
5963               newp = cStartNew + (p - cStart)*4 + r;
5964               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5965             }
5966             for (r = 0; r < 4; ++r) {
5967               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5968               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5969             }
5970             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5971             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5972           }
5973           break;
5974         case 3:
5975           /* Hybrid simplicial 2D */
5976           if ((p >= vStart) && (p < vEnd)) {
5977             /* Old vertices stay the same */
5978             newp = vStartNew + (p - vStart);
5979             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5980           } else if ((p >= fStart) && (p < fMax)) {
5981             /* Old interior faces add new faces and vertex */
5982             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5983             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5984             for (r = 0; r < 2; ++r) {
5985               newp = fStartNew + (p - fStart)*2 + r;
5986               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5987             }
5988           } else if ((p >= fMax) && (p < fEnd)) {
5989             /* Old hybrid faces stay the same */
5990             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5991             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5992           } else if ((p >= cStart) && (p < cMax)) {
5993             /* Old interior cells add new cells and interior faces */
5994             for (r = 0; r < 4; ++r) {
5995               newp = cStartNew + (p - cStart)*4 + r;
5996               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5997             }
5998             for (r = 0; r < 3; ++r) {
5999               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6000               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6001             }
6002           } else if ((p >= cMax) && (p < cEnd)) {
6003             /* Old hybrid cells add new cells and hybrid face */
6004             for (r = 0; r < 2; ++r) {
6005               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6006               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6007             }
6008             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6009             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6010           }
6011           break;
6012         default:
6013           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6014         }
6015       }
6016       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6017       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6018     }
6019     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6020     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6021     if (0) {
6022       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6023       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6024       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6025     }
6026   }
6027   PetscFunctionReturn(0);
6028 }
6029 
6030 #undef __FUNCT__
6031 #define __FUNCT__ "DMPlexRefine_Uniform"
6032 /* This will only work for interpolated meshes */
6033 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6034 {
6035   DM             rdm;
6036   PetscInt      *depthSize;
6037   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6038   PetscErrorCode ierr;
6039 
6040   PetscFunctionBegin;
6041   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6042   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6043   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6044   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6045   /* Calculate number of new points of each depth */
6046   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6047   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
6048   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6049   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6050   /* Step 1: Set chart */
6051   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6052   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6053   /* Step 2: Set cone/support sizes */
6054   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6055   /* Step 3: Setup refined DM */
6056   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6057   /* Step 4: Set cones and supports */
6058   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6059   /* Step 5: Stratify */
6060   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6061   /* Step 6: Set coordinates for vertices */
6062   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6063   /* Step 7: Create pointSF */
6064   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6065   /* Step 8: Create labels */
6066   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6067   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6068 
6069   *dmRefined = rdm;
6070   PetscFunctionReturn(0);
6071 }
6072 
6073 #undef __FUNCT__
6074 #define __FUNCT__ "DMPlexSetRefinementUniform"
6075 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6076 {
6077   DM_Plex *mesh = (DM_Plex*) dm->data;
6078 
6079   PetscFunctionBegin;
6080   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6081   mesh->refinementUniform = refinementUniform;
6082   PetscFunctionReturn(0);
6083 }
6084 
6085 #undef __FUNCT__
6086 #define __FUNCT__ "DMPlexGetRefinementUniform"
6087 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6088 {
6089   DM_Plex *mesh = (DM_Plex*) dm->data;
6090 
6091   PetscFunctionBegin;
6092   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6093   PetscValidPointer(refinementUniform,  2);
6094   *refinementUniform = mesh->refinementUniform;
6095   PetscFunctionReturn(0);
6096 }
6097 
6098 #undef __FUNCT__
6099 #define __FUNCT__ "DMPlexSetRefinementLimit"
6100 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6101 {
6102   DM_Plex *mesh = (DM_Plex*) dm->data;
6103 
6104   PetscFunctionBegin;
6105   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6106   mesh->refinementLimit = refinementLimit;
6107   PetscFunctionReturn(0);
6108 }
6109 
6110 #undef __FUNCT__
6111 #define __FUNCT__ "DMPlexGetRefinementLimit"
6112 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6113 {
6114   DM_Plex *mesh = (DM_Plex*) dm->data;
6115 
6116   PetscFunctionBegin;
6117   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6118   PetscValidPointer(refinementLimit,  2);
6119   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6120   *refinementLimit = mesh->refinementLimit;
6121   PetscFunctionReturn(0);
6122 }
6123 
6124 #undef __FUNCT__
6125 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
6126 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
6127 {
6128   PetscInt       dim, cStart, coneSize, cMax;
6129   PetscErrorCode ierr;
6130 
6131   PetscFunctionBegin;
6132   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6133   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
6134   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6135   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6136   switch (dim) {
6137   case 2:
6138     switch (coneSize) {
6139     case 3:
6140       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6141       else *cellRefiner = 1; /* Triangular */
6142       break;
6143     case 4:
6144       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6145       else *cellRefiner = 2; /* Quadrilateral */
6146       break;
6147     default:
6148       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6149     }
6150     break;
6151   default:
6152     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6153   }
6154   PetscFunctionReturn(0);
6155 }
6156 
6157 #undef __FUNCT__
6158 #define __FUNCT__ "DMRefine_Plex"
6159 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
6160 {
6161   PetscReal      refinementLimit;
6162   PetscInt       dim, cStart, cEnd;
6163   char           genname[1024], *name = NULL;
6164   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
6165   PetscErrorCode ierr;
6166 
6167   PetscFunctionBegin;
6168   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
6169   if (isUniform) {
6170     CellRefiner cellRefiner;
6171 
6172     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
6173     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
6174     PetscFunctionReturn(0);
6175   }
6176   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
6177   if (refinementLimit == 0.0) PetscFunctionReturn(0);
6178   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6179   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6180   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
6181   if (flg) name = genname;
6182   if (name) {
6183     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
6184     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
6185     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
6186   }
6187   switch (dim) {
6188   case 2:
6189     if (!name || isTriangle) {
6190 #if defined(PETSC_HAVE_TRIANGLE)
6191       double  *maxVolumes;
6192       PetscInt c;
6193 
6194       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6195       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
6196       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6197 #else
6198       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
6199 #endif
6200     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
6201     break;
6202   case 3:
6203     if (!name || isCTetgen) {
6204 #if defined(PETSC_HAVE_CTETGEN)
6205       PetscReal *maxVolumes;
6206       PetscInt   c;
6207 
6208       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
6209       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
6210       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6211 #else
6212       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
6213 #endif
6214     } else if (isTetgen) {
6215 #if defined(PETSC_HAVE_TETGEN)
6216       double  *maxVolumes;
6217       PetscInt c;
6218 
6219       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6220       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
6221       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6222 #else
6223       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
6224 #endif
6225     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
6226     break;
6227   default:
6228     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
6229   }
6230   PetscFunctionReturn(0);
6231 }
6232 
6233 #undef __FUNCT__
6234 #define __FUNCT__ "DMPlexGetDepth"
6235 /*@
6236   DMPlexGetDepth - get the number of strata
6237 
6238   Not Collective
6239 
6240   Input Parameters:
6241 . dm           - The DMPlex object
6242 
6243   Output Parameters:
6244 . depth - number of strata
6245 
6246   Level: developer
6247 
6248   Notes:
6249   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
6250 
6251 .keywords: mesh, points
6252 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
6253 @*/
6254 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
6255 {
6256   PetscInt       d;
6257   PetscErrorCode ierr;
6258 
6259   PetscFunctionBegin;
6260   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6261   PetscValidPointer(depth, 2);
6262   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
6263   *depth = d-1;
6264   PetscFunctionReturn(0);
6265 }
6266 
6267 #undef __FUNCT__
6268 #define __FUNCT__ "DMPlexGetDepthStratum"
6269 /*@
6270   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
6271 
6272   Not Collective
6273 
6274   Input Parameters:
6275 + dm           - The DMPlex object
6276 - stratumValue - The requested depth
6277 
6278   Output Parameters:
6279 + start - The first point at this depth
6280 - end   - One beyond the last point at this depth
6281 
6282   Level: developer
6283 
6284 .keywords: mesh, points
6285 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
6286 @*/
6287 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
6288 {
6289   DM_Plex       *mesh = (DM_Plex*) dm->data;
6290   DMLabel        next  = mesh->labels;
6291   PetscBool      flg   = PETSC_FALSE;
6292   PetscInt       depth;
6293   PetscErrorCode ierr;
6294 
6295   PetscFunctionBegin;
6296   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6297   if (stratumValue < 0) {
6298     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6299     PetscFunctionReturn(0);
6300   } else {
6301     PetscInt pStart, pEnd;
6302 
6303     if (start) *start = 0;
6304     if (end)   *end   = 0;
6305     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6306     if (pStart == pEnd) PetscFunctionReturn(0);
6307   }
6308   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6309   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6310   /* We should have a generic GetLabel() and a Label class */
6311   while (next) {
6312     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6313     if (flg) break;
6314     next = next->next;
6315   }
6316   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6317   depth = stratumValue;
6318   if ((depth < 0) || (depth >= next->numStrata)) {
6319     if (start) *start = 0;
6320     if (end)   *end   = 0;
6321   } else {
6322     if (start) *start = next->points[next->stratumOffsets[depth]];
6323     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
6324   }
6325   PetscFunctionReturn(0);
6326 }
6327 
6328 #undef __FUNCT__
6329 #define __FUNCT__ "DMPlexGetHeightStratum"
6330 /*@
6331   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
6332 
6333   Not Collective
6334 
6335   Input Parameters:
6336 + dm           - The DMPlex object
6337 - stratumValue - The requested height
6338 
6339   Output Parameters:
6340 + start - The first point at this height
6341 - end   - One beyond the last point at this height
6342 
6343   Level: developer
6344 
6345 .keywords: mesh, points
6346 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
6347 @*/
6348 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
6349 {
6350   DM_Plex       *mesh = (DM_Plex*) dm->data;
6351   DMLabel        next  = mesh->labels;
6352   PetscBool      flg   = PETSC_FALSE;
6353   PetscInt       depth;
6354   PetscErrorCode ierr;
6355 
6356   PetscFunctionBegin;
6357   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6358   if (stratumValue < 0) {
6359     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6360   } else {
6361     PetscInt pStart, pEnd;
6362 
6363     if (start) *start = 0;
6364     if (end)   *end   = 0;
6365     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6366     if (pStart == pEnd) PetscFunctionReturn(0);
6367   }
6368   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6369   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6370   /* We should have a generic GetLabel() and a Label class */
6371   while (next) {
6372     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6373     if (flg) break;
6374     next = next->next;
6375   }
6376   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6377   depth = next->stratumValues[next->numStrata-1] - stratumValue;
6378   if ((depth < 0) || (depth >= next->numStrata)) {
6379     if (start) *start = 0;
6380     if (end)   *end   = 0;
6381   } else {
6382     if (start) *start = next->points[next->stratumOffsets[depth]];
6383     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
6384   }
6385   PetscFunctionReturn(0);
6386 }
6387 
6388 #undef __FUNCT__
6389 #define __FUNCT__ "DMPlexCreateSectionInitial"
6390 /* Set the number of dof on each point and separate by fields */
6391 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
6392 {
6393   PetscInt      *numDofTot;
6394   PetscInt       pStart = 0, pEnd = 0;
6395   PetscInt       p, d, f;
6396   PetscErrorCode ierr;
6397 
6398   PetscFunctionBegin;
6399   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
6400   for (d = 0; d <= dim; ++d) {
6401     numDofTot[d] = 0;
6402     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
6403   }
6404   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
6405   if (numFields > 0) {
6406     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
6407     if (numComp) {
6408       for (f = 0; f < numFields; ++f) {
6409         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
6410       }
6411     }
6412   }
6413   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6414   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
6415   for (d = 0; d <= dim; ++d) {
6416     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
6417     for (p = pStart; p < pEnd; ++p) {
6418       for (f = 0; f < numFields; ++f) {
6419         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
6420       }
6421       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
6422     }
6423   }
6424   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
6425   PetscFunctionReturn(0);
6426 }
6427 
6428 #undef __FUNCT__
6429 #define __FUNCT__ "DMPlexCreateSectionBCDof"
6430 /* Set the number of dof on each point and separate by fields
6431    If constDof is PETSC_DETERMINE, constrain every dof on the point
6432 */
6433 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
6434 {
6435   PetscInt       numFields;
6436   PetscInt       bc;
6437   PetscErrorCode ierr;
6438 
6439   PetscFunctionBegin;
6440   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6441   for (bc = 0; bc < numBC; ++bc) {
6442     PetscInt        field = 0;
6443     const PetscInt *idx;
6444     PetscInt        n, i;
6445 
6446     if (numFields) field = bcField[bc];
6447     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
6448     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6449     for (i = 0; i < n; ++i) {
6450       const PetscInt p        = idx[i];
6451       PetscInt       numConst = constDof;
6452 
6453       /* Constrain every dof on the point */
6454       if (numConst < 0) {
6455         if (numFields) {
6456           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
6457         } else {
6458           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
6459         }
6460       }
6461       if (numFields) {
6462         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
6463       }
6464       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
6465     }
6466     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6467   }
6468   PetscFunctionReturn(0);
6469 }
6470 
6471 #undef __FUNCT__
6472 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
6473 /* Set the constrained indices on each point and separate by fields */
6474 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
6475 {
6476   PetscInt      *maxConstraints;
6477   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
6478   PetscErrorCode ierr;
6479 
6480   PetscFunctionBegin;
6481   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6482   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6483   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
6484   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
6485   for (p = pStart; p < pEnd; ++p) {
6486     PetscInt cdof;
6487 
6488     if (numFields) {
6489       for (f = 0; f < numFields; ++f) {
6490         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
6491         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6492       }
6493     } else {
6494       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6495       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6496     }
6497   }
6498   for (f = 0; f < numFields; ++f) {
6499     maxConstraints[numFields] += maxConstraints[f];
6500   }
6501   if (maxConstraints[numFields]) {
6502     PetscInt *indices;
6503 
6504     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6505     for (p = pStart; p < pEnd; ++p) {
6506       PetscInt cdof, d;
6507 
6508       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6509       if (cdof) {
6510         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
6511         if (numFields) {
6512           PetscInt numConst = 0, foff = 0;
6513 
6514           for (f = 0; f < numFields; ++f) {
6515             PetscInt cfdof, fdof;
6516 
6517             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6518             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
6519             /* Change constraint numbering from absolute local dof number to field relative local dof number */
6520             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
6521             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
6522             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
6523             numConst += cfdof;
6524             foff     += fdof;
6525           }
6526           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6527         } else {
6528           for (d = 0; d < cdof; ++d) indices[d] = d;
6529         }
6530         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6531       }
6532     }
6533     ierr = PetscFree(indices);CHKERRQ(ierr);
6534   }
6535   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
6536   PetscFunctionReturn(0);
6537 }
6538 
6539 #undef __FUNCT__
6540 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
6541 /* Set the constrained field indices on each point */
6542 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6543 {
6544   const PetscInt *points, *indices;
6545   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6546   PetscErrorCode  ierr;
6547 
6548   PetscFunctionBegin;
6549   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6550   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
6551 
6552   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
6553   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
6554   if (!constraintIndices) {
6555     PetscInt *idx, i;
6556 
6557     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6558     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
6559     for (i = 0; i < maxDof; ++i) idx[i] = i;
6560     for (p = 0; p < numPoints; ++p) {
6561       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
6562     }
6563     ierr = PetscFree(idx);CHKERRQ(ierr);
6564   } else {
6565     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
6566     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
6567     for (p = 0; p < numPoints; ++p) {
6568       PetscInt fcdof;
6569 
6570       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
6571       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);
6572       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
6573     }
6574     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
6575   }
6576   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
6577   PetscFunctionReturn(0);
6578 }
6579 
6580 #undef __FUNCT__
6581 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
6582 /* Set the constrained indices on each point and separate by fields */
6583 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6584 {
6585   PetscInt      *indices;
6586   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
6587   PetscErrorCode ierr;
6588 
6589   PetscFunctionBegin;
6590   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6591   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6592   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6593   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6594   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6595   for (p = pStart; p < pEnd; ++p) {
6596     PetscInt cdof, d;
6597 
6598     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6599     if (cdof) {
6600       PetscInt numConst = 0, foff = 0;
6601 
6602       for (f = 0; f < numFields; ++f) {
6603         const PetscInt *fcind;
6604         PetscInt        fdof, fcdof;
6605 
6606         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6607         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
6608         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
6609         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6610         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6611         foff     += fdof;
6612         numConst += fcdof;
6613       }
6614       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6615       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6616     }
6617   }
6618   ierr = PetscFree(indices);CHKERRQ(ierr);
6619   PetscFunctionReturn(0);
6620 }
6621 
6622 #undef __FUNCT__
6623 #define __FUNCT__ "DMPlexCreateSection"
6624 /*@C
6625   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
6626 
6627   Not Collective
6628 
6629   Input Parameters:
6630 + dm        - The DMPlex object
6631 . dim       - The spatial dimension of the problem
6632 . numFields - The number of fields in the problem
6633 . numComp   - An array of size numFields that holds the number of components for each field
6634 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6635 . numBC     - The number of boundary conditions
6636 . bcField   - An array of size numBC giving the field number for each boundry condition
6637 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
6638 
6639   Output Parameter:
6640 . section - The PetscSection object
6641 
6642   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
6643   nubmer of dof for field 0 on each edge.
6644 
6645   Level: developer
6646 
6647   Fortran Notes:
6648   A Fortran 90 version is available as DMPlexCreateSectionF90()
6649 
6650 .keywords: mesh, elements
6651 .seealso: DMPlexCreate(), PetscSectionCreate()
6652 @*/
6653 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6654 {
6655   PetscErrorCode ierr;
6656 
6657   PetscFunctionBegin;
6658   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
6659   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
6660   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
6661   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
6662   {
6663     PetscBool view = PETSC_FALSE;
6664 
6665     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
6666     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
6667   }
6668   PetscFunctionReturn(0);
6669 }
6670 
6671 #undef __FUNCT__
6672 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
6673 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6674 {
6675   PetscSection   section;
6676   PetscErrorCode ierr;
6677 
6678   PetscFunctionBegin;
6679   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
6680   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6681   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
6682   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6683   PetscFunctionReturn(0);
6684 }
6685 
6686 #undef __FUNCT__
6687 #define __FUNCT__ "DMPlexGetCoordinateSection"
6688 /*@
6689   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6690 
6691   Not Collective
6692 
6693   Input Parameter:
6694 . dm - The DMPlex object
6695 
6696   Output Parameter:
6697 . section - The PetscSection object
6698 
6699   Level: intermediate
6700 
6701 .keywords: mesh, coordinates
6702 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6703 @*/
6704 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6705 {
6706   DM             cdm;
6707   PetscErrorCode ierr;
6708 
6709   PetscFunctionBegin;
6710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6711   PetscValidPointer(section, 2);
6712   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6713   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
6714   PetscFunctionReturn(0);
6715 }
6716 
6717 #undef __FUNCT__
6718 #define __FUNCT__ "DMPlexSetCoordinateSection"
6719 /*@
6720   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
6721 
6722   Not Collective
6723 
6724   Input Parameters:
6725 + dm      - The DMPlex object
6726 - section - The PetscSection object
6727 
6728   Level: intermediate
6729 
6730 .keywords: mesh, coordinates
6731 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6732 @*/
6733 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6734 {
6735   DM             cdm;
6736   PetscErrorCode ierr;
6737 
6738   PetscFunctionBegin;
6739   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6740   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
6741   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6742   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
6743   PetscFunctionReturn(0);
6744 }
6745 
6746 #undef __FUNCT__
6747 #define __FUNCT__ "DMPlexGetConeSection"
6748 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6749 {
6750   DM_Plex *mesh = (DM_Plex*) dm->data;
6751 
6752   PetscFunctionBegin;
6753   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6754   if (section) *section = mesh->coneSection;
6755   PetscFunctionReturn(0);
6756 }
6757 
6758 #undef __FUNCT__
6759 #define __FUNCT__ "DMPlexGetCones"
6760 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6761 {
6762   DM_Plex *mesh = (DM_Plex*) dm->data;
6763 
6764   PetscFunctionBegin;
6765   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6766   if (cones) *cones = mesh->cones;
6767   PetscFunctionReturn(0);
6768 }
6769 
6770 #undef __FUNCT__
6771 #define __FUNCT__ "DMPlexGetConeOrientations"
6772 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6773 {
6774   DM_Plex *mesh = (DM_Plex*) dm->data;
6775 
6776   PetscFunctionBegin;
6777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6778   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6779   PetscFunctionReturn(0);
6780 }
6781 
6782 #undef __FUNCT__
6783 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
6784 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
6785 {
6786   const PetscInt embedDim = 2;
6787   PetscReal      x        = PetscRealPart(point[0]);
6788   PetscReal      y        = PetscRealPart(point[1]);
6789   PetscReal      v0[2], J[4], invJ[4], detJ;
6790   PetscReal      xi, eta;
6791   PetscErrorCode ierr;
6792 
6793   PetscFunctionBegin;
6794   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
6795   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
6796   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
6797 
6798   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
6799   else *cell = -1;
6800   PetscFunctionReturn(0);
6801 }
6802 
6803 #undef __FUNCT__
6804 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
6805 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
6806 {
6807   PetscSection       coordSection;
6808   Vec                coordsLocal;
6809   const PetscScalar *coords;
6810   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
6811   PetscReal          x         = PetscRealPart(point[0]);
6812   PetscReal          y         = PetscRealPart(point[1]);
6813   PetscInt           crossings = 0, f;
6814   PetscErrorCode     ierr;
6815 
6816   PetscFunctionBegin;
6817   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
6818   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6819   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
6820   for (f = 0; f < 4; ++f) {
6821     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
6822     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
6823     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
6824     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
6825     PetscReal slope = (y_j - y_i) / (x_j - x_i);
6826     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
6827     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
6828     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
6829     if ((cond1 || cond2)  && above) ++crossings;
6830   }
6831   if (crossings % 2) *cell = c;
6832   else *cell = -1;
6833   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
6834   PetscFunctionReturn(0);
6835 }
6836 
6837 #undef __FUNCT__
6838 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
6839 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
6840 {
6841   const PetscInt embedDim = 3;
6842   PetscReal      v0[3], J[9], invJ[9], detJ;
6843   PetscReal      x = PetscRealPart(point[0]);
6844   PetscReal      y = PetscRealPart(point[1]);
6845   PetscReal      z = PetscRealPart(point[2]);
6846   PetscReal      xi, eta, zeta;
6847   PetscErrorCode ierr;
6848 
6849   PetscFunctionBegin;
6850   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
6851   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
6852   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
6853   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
6854 
6855   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
6856   else *cell = -1;
6857   PetscFunctionReturn(0);
6858 }
6859 
6860 #undef __FUNCT__
6861 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
6862 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
6863 {
6864   PetscSection       coordSection;
6865   Vec                coordsLocal;
6866   const PetscScalar *coords;
6867   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
6868                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
6869   PetscBool          found = PETSC_TRUE;
6870   PetscInt           f;
6871   PetscErrorCode     ierr;
6872 
6873   PetscFunctionBegin;
6874   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
6875   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6876   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
6877   for (f = 0; f < 6; ++f) {
6878     /* Check the point is under plane */
6879     /*   Get face normal */
6880     PetscReal v_i[3];
6881     PetscReal v_j[3];
6882     PetscReal normal[3];
6883     PetscReal pp[3];
6884     PetscReal dot;
6885 
6886     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
6887     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
6888     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
6889     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
6890     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
6891     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
6892     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
6893     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
6894     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
6895     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
6896     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
6897     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
6898     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
6899 
6900     /* Check that projected point is in face (2D location problem) */
6901     if (dot < 0.0) {
6902       found = PETSC_FALSE;
6903       break;
6904     }
6905   }
6906   if (found) *cell = c;
6907   else *cell = -1;
6908   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
6909   PetscFunctionReturn(0);
6910 }
6911 
6912 #undef __FUNCT__
6913 #define __FUNCT__ "DMLocatePoints_Plex"
6914 /*
6915  Need to implement using the guess
6916 */
6917 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
6918 {
6919   PetscInt       cell = -1 /*, guess = -1*/;
6920   PetscInt       bs, numPoints, p;
6921   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
6922   PetscInt      *cells;
6923   PetscScalar   *a;
6924   PetscErrorCode ierr;
6925 
6926   PetscFunctionBegin;
6927   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6928   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6929   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6930   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
6931   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
6932   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
6933   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
6934   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);
6935   numPoints /= bs;
6936   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
6937   for (p = 0; p < numPoints; ++p) {
6938     const PetscScalar *point = &a[p*bs];
6939 
6940     switch (dim) {
6941     case 2:
6942       for (c = cStart; c < cEnd; ++c) {
6943         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6944         switch (coneSize) {
6945         case 3:
6946           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
6947           break;
6948         case 4:
6949           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
6950           break;
6951         default:
6952           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
6953         }
6954         if (cell >= 0) break;
6955       }
6956       break;
6957     case 3:
6958       for (c = cStart; c < cEnd; ++c) {
6959         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6960         switch (coneSize) {
6961         case 4:
6962           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
6963           break;
6964         case 8:
6965           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
6966           break;
6967         default:
6968           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
6969         }
6970         if (cell >= 0) break;
6971       }
6972       break;
6973     default:
6974       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
6975     }
6976     cells[p] = cell;
6977   }
6978   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
6979   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
6980   PetscFunctionReturn(0);
6981 }
6982 
6983 /******************************** FEM Support **********************************/
6984 
6985 #undef __FUNCT__
6986 #define __FUNCT__ "DMPlexVecGetClosure"
6987 /*@C
6988   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6989 
6990   Not collective
6991 
6992   Input Parameters:
6993 + dm - The DM
6994 . section - The section describing the layout in v, or NULL to use the default section
6995 . v - The local vector
6996 - point - The sieve point in the DM
6997 
6998   Output Parameters:
6999 + csize - The number of values in the closure, or NULL
7000 - values - The array of values, which is a borrowed array and should not be freed
7001 
7002   Fortran Notes:
7003   Since it returns an array, this routine is only available in Fortran 90, and you must
7004   include petsc.h90 in your code.
7005 
7006   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
7007 
7008   Level: intermediate
7009 
7010 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7011 @*/
7012 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
7013 {
7014   PetscScalar   *array, *vArray;
7015   PetscInt      *points = NULL;
7016   PetscInt       offsets[32];
7017   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
7018   PetscErrorCode ierr;
7019 
7020   PetscFunctionBegin;
7021   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7022   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7023   if (!section) {
7024     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7025   }
7026   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7027   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7028   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7029   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7030   /* Compress out points not in the section */
7031   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7032   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7033     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7034       points[q*2]   = points[p];
7035       points[q*2+1] = points[p+1];
7036       ++q;
7037     }
7038   }
7039   numPoints = q;
7040   for (p = 0, size = 0; p < numPoints*2; p += 2) {
7041     PetscInt dof, fdof;
7042 
7043     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7044     for (f = 0; f < numFields; ++f) {
7045       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7046       offsets[f+1] += fdof;
7047     }
7048     size += dof;
7049   }
7050   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7051   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
7052   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
7053   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
7054   for (p = 0; p < numPoints*2; p += 2) {
7055     PetscInt     o = points[p+1];
7056     PetscInt     dof, off, d;
7057     PetscScalar *varr;
7058 
7059     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7060     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
7061     varr = &vArray[off];
7062     if (numFields) {
7063       PetscInt fdof, foff, fcomp, f, c;
7064 
7065       for (f = 0, foff = 0; f < numFields; ++f) {
7066         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7067         if (o >= 0) {
7068           for (d = 0; d < fdof; ++d, ++offsets[f]) {
7069             array[offsets[f]] = varr[foff+d];
7070           }
7071         } else {
7072           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7073           for (d = fdof/fcomp-1; d >= 0; --d) {
7074             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
7075               array[offsets[f]] = varr[foff+d*fcomp+c];
7076             }
7077           }
7078         }
7079         foff += fdof;
7080       }
7081     } else {
7082       if (o >= 0) {
7083         for (d = 0; d < dof; ++d, ++offsets[0]) {
7084           array[offsets[0]] = varr[d];
7085         }
7086       } else {
7087         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
7088           array[offsets[0]] = varr[d];
7089         }
7090       }
7091     }
7092   }
7093   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7094   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
7095   if (csize) *csize = size;
7096   *values = array;
7097   PetscFunctionReturn(0);
7098 }
7099 
7100 #undef __FUNCT__
7101 #define __FUNCT__ "DMPlexVecRestoreClosure"
7102 /*@C
7103   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
7104 
7105   Not collective
7106 
7107   Input Parameters:
7108 + dm - The DM
7109 . section - The section describing the layout in v, or NULL to use the default section
7110 . v - The local vector
7111 . point - The sieve point in the DM
7112 . csize - The number of values in the closure, or NULL
7113 - values - The array of values, which is a borrowed array and should not be freed
7114 
7115   Fortran Notes:
7116   Since it returns an array, this routine is only available in Fortran 90, and you must
7117   include petsc.h90 in your code.
7118 
7119   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
7120 
7121   Level: intermediate
7122 
7123 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7124 @*/
7125 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
7126 {
7127   PetscInt       size = 0;
7128   PetscErrorCode ierr;
7129 
7130   PetscFunctionBegin;
7131   /* Should work without recalculating size */
7132   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
7133   PetscFunctionReturn(0);
7134 }
7135 
7136 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
7137 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
7138 
7139 #undef __FUNCT__
7140 #define __FUNCT__ "updatePoint_private"
7141 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
7142 {
7143   PetscInt        cdof;   /* The number of constraints on this point */
7144   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7145   PetscScalar    *a;
7146   PetscInt        off, cind = 0, k;
7147   PetscErrorCode  ierr;
7148 
7149   PetscFunctionBegin;
7150   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7151   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7152   a    = &array[off];
7153   if (!cdof || setBC) {
7154     if (orientation >= 0) {
7155       for (k = 0; k < dof; ++k) {
7156         fuse(&a[k], values[k]);
7157       }
7158     } else {
7159       for (k = 0; k < dof; ++k) {
7160         fuse(&a[k], values[dof-k-1]);
7161       }
7162     }
7163   } else {
7164     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7165     if (orientation >= 0) {
7166       for (k = 0; k < dof; ++k) {
7167         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7168         fuse(&a[k], values[k]);
7169       }
7170     } else {
7171       for (k = 0; k < dof; ++k) {
7172         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7173         fuse(&a[k], values[dof-k-1]);
7174       }
7175     }
7176   }
7177   PetscFunctionReturn(0);
7178 }
7179 
7180 #undef __FUNCT__
7181 #define __FUNCT__ "updatePointFields_private"
7182 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
7183 {
7184   PetscScalar   *a;
7185   PetscInt       numFields, off, foff, f;
7186   PetscErrorCode ierr;
7187 
7188   PetscFunctionBegin;
7189   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7190   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7191   a    = &array[off];
7192   for (f = 0, foff = 0; f < numFields; ++f) {
7193     PetscInt        fdof, fcomp, fcdof;
7194     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7195     PetscInt        cind = 0, k, c;
7196 
7197     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7198     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7199     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
7200     if (!fcdof || setBC) {
7201       if (orientation >= 0) {
7202         for (k = 0; k < fdof; ++k) {
7203           fuse(&a[foff+k], values[foffs[f]+k]);
7204         }
7205       } else {
7206         for (k = fdof/fcomp-1; k >= 0; --k) {
7207           for (c = 0; c < fcomp; ++c) {
7208             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7209           }
7210         }
7211       }
7212     } else {
7213       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7214       if (orientation >= 0) {
7215         for (k = 0; k < fdof; ++k) {
7216           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
7217           fuse(&a[foff+k], values[foffs[f]+k]);
7218         }
7219       } else {
7220         for (k = fdof/fcomp-1; k >= 0; --k) {
7221           for (c = 0; c < fcomp; ++c) {
7222             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
7223             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7224           }
7225         }
7226       }
7227     }
7228     foff     += fdof;
7229     foffs[f] += fdof;
7230   }
7231   PetscFunctionReturn(0);
7232 }
7233 
7234 #undef __FUNCT__
7235 #define __FUNCT__ "DMPlexVecSetClosure"
7236 /*@C
7237   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
7238 
7239   Not collective
7240 
7241   Input Parameters:
7242 + dm - The DM
7243 . section - The section describing the layout in v, or NULL to use the default sectionw
7244 . v - The local vector
7245 . point - The sieve point in the DM
7246 . values - The array of values, which is a borrowed array and should not be freed
7247 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7248 
7249   Fortran Notes:
7250   Since it returns an array, this routine is only available in Fortran 90, and you must
7251   include petsc.h90 in your code.
7252 
7253   Level: intermediate
7254 
7255 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
7256 @*/
7257 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7258 {
7259   PetscScalar   *array;
7260   PetscInt      *points = NULL;
7261   PetscInt       offsets[32];
7262   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
7263   PetscErrorCode ierr;
7264 
7265   PetscFunctionBegin;
7266   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7267   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7268   if (!section) {
7269     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7270   }
7271   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7272   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7273   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7274   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7275   /* Compress out points not in the section */
7276   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7277   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7278     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7279       points[q*2]   = points[p];
7280       points[q*2+1] = points[p+1];
7281       ++q;
7282     }
7283   }
7284   numPoints = q;
7285   for (p = 0; p < numPoints*2; p += 2) {
7286     PetscInt fdof;
7287 
7288     for (f = 0; f < numFields; ++f) {
7289       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7290       offsets[f+1] += fdof;
7291     }
7292   }
7293   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7294   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
7295   if (numFields) {
7296     switch (mode) {
7297     case INSERT_VALUES:
7298       for (p = 0; p < numPoints*2; p += 2) {
7299         PetscInt o = points[p+1];
7300         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
7301       } break;
7302     case INSERT_ALL_VALUES:
7303       for (p = 0; p < numPoints*2; p += 2) {
7304         PetscInt o = points[p+1];
7305         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
7306       } break;
7307     case ADD_VALUES:
7308       for (p = 0; p < numPoints*2; p += 2) {
7309         PetscInt o = points[p+1];
7310         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
7311       } break;
7312     case ADD_ALL_VALUES:
7313       for (p = 0; p < numPoints*2; p += 2) {
7314         PetscInt o = points[p+1];
7315         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
7316       } break;
7317     default:
7318       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7319     }
7320   } else {
7321     switch (mode) {
7322     case INSERT_VALUES:
7323       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7324         PetscInt o = points[p+1];
7325         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7326         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
7327       } break;
7328     case INSERT_ALL_VALUES:
7329       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7330         PetscInt o = points[p+1];
7331         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7332         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
7333       } break;
7334     case ADD_VALUES:
7335       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7336         PetscInt o = points[p+1];
7337         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7338         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
7339       } break;
7340     case ADD_ALL_VALUES:
7341       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7342         PetscInt o = points[p+1];
7343         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7344         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
7345       } break;
7346     default:
7347       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7348     }
7349   }
7350   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7351   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
7352   PetscFunctionReturn(0);
7353 }
7354 
7355 #undef __FUNCT__
7356 #define __FUNCT__ "DMPlexPrintMatSetValues"
7357 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
7358 {
7359   PetscMPIInt    rank;
7360   PetscInt       i, j;
7361   PetscErrorCode ierr;
7362 
7363   PetscFunctionBegin;
7364   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
7365   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
7366   for (i = 0; i < numIndices; i++) {
7367     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
7368   }
7369   for (i = 0; i < numIndices; i++) {
7370     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
7371     for (j = 0; j < numIndices; j++) {
7372 #if defined(PETSC_USE_COMPLEX)
7373       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
7374 #else
7375       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
7376 #endif
7377     }
7378     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
7379   }
7380   PetscFunctionReturn(0);
7381 }
7382 
7383 #undef __FUNCT__
7384 #define __FUNCT__ "indicesPoint_private"
7385 /* . off - The global offset of this point */
7386 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
7387 {
7388   PetscInt        dof;    /* The number of unknowns on this point */
7389   PetscInt        cdof;   /* The number of constraints on this point */
7390   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7391   PetscInt        cind = 0, k;
7392   PetscErrorCode  ierr;
7393 
7394   PetscFunctionBegin;
7395   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
7396   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7397   if (!cdof || setBC) {
7398     if (orientation >= 0) {
7399       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
7400     } else {
7401       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
7402     }
7403   } else {
7404     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7405     if (orientation >= 0) {
7406       for (k = 0; k < dof; ++k) {
7407         if ((cind < cdof) && (k == cdofs[cind])) {
7408           /* Insert check for returning constrained indices */
7409           indices[*loff+k] = -(off+k+1);
7410           ++cind;
7411         } else {
7412           indices[*loff+k] = off+k-cind;
7413         }
7414       }
7415     } else {
7416       for (k = 0; k < dof; ++k) {
7417         if ((cind < cdof) && (k == cdofs[cind])) {
7418           /* Insert check for returning constrained indices */
7419           indices[*loff+dof-k-1] = -(off+k+1);
7420           ++cind;
7421         } else {
7422           indices[*loff+dof-k-1] = off+k-cind;
7423         }
7424       }
7425     }
7426   }
7427   *loff += dof;
7428   PetscFunctionReturn(0);
7429 }
7430 
7431 #undef __FUNCT__
7432 #define __FUNCT__ "indicesPointFields_private"
7433 /* . off - The global offset of this point */
7434 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
7435 {
7436   PetscInt       numFields, foff, f;
7437   PetscErrorCode ierr;
7438 
7439   PetscFunctionBegin;
7440   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7441   for (f = 0, foff = 0; f < numFields; ++f) {
7442     PetscInt        fdof, fcomp, cfdof;
7443     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7444     PetscInt        cind = 0, k, c;
7445 
7446     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7447     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7448     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
7449     if (!cfdof || setBC) {
7450       if (orientation >= 0) {
7451         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
7452       } else {
7453         for (k = fdof/fcomp-1; k >= 0; --k) {
7454           for (c = 0; c < fcomp; ++c) {
7455             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
7456           }
7457         }
7458       }
7459     } else {
7460       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7461       if (orientation >= 0) {
7462         for (k = 0; k < fdof; ++k) {
7463           if ((cind < cfdof) && (k == fcdofs[cind])) {
7464             indices[foffs[f]+k] = -(off+foff+k+1);
7465             ++cind;
7466           } else {
7467             indices[foffs[f]+k] = off+foff+k-cind;
7468           }
7469         }
7470       } else {
7471         for (k = fdof/fcomp-1; k >= 0; --k) {
7472           for (c = 0; c < fcomp; ++c) {
7473             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
7474               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
7475               ++cind;
7476             } else {
7477               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
7478             }
7479           }
7480         }
7481       }
7482     }
7483     foff     += fdof - cfdof;
7484     foffs[f] += fdof;
7485   }
7486   PetscFunctionReturn(0);
7487 }
7488 
7489 #undef __FUNCT__
7490 #define __FUNCT__ "DMPlexMatSetClosure"
7491 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
7492 {
7493   DM_Plex       *mesh   = (DM_Plex*) dm->data;
7494   PetscInt      *points = NULL;
7495   PetscInt      *indices;
7496   PetscInt       offsets[32];
7497   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
7498   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
7499   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
7500   PetscErrorCode ierr;
7501 
7502   PetscFunctionBegin;
7503   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7504   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
7505   if (useDefault) {
7506     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7507   }
7508   if (useGlobalDefault) {
7509     if (useDefault) {
7510       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
7511     } else {
7512       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7513     }
7514   }
7515   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7516   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7517   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7518   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7519   /* Compress out points not in the section */
7520   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7521   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7522     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7523       points[q*2]   = points[p];
7524       points[q*2+1] = points[p+1];
7525       ++q;
7526     }
7527   }
7528   numPoints = q;
7529   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
7530     PetscInt fdof;
7531 
7532     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7533     for (f = 0; f < numFields; ++f) {
7534       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7535       offsets[f+1] += fdof;
7536     }
7537     numIndices += dof;
7538   }
7539   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7540 
7541   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
7542   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7543   if (numFields) {
7544     for (p = 0; p < numPoints*2; p += 2) {
7545       PetscInt o = points[p+1];
7546       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7547       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
7548     }
7549   } else {
7550     for (p = 0, off = 0; p < numPoints*2; p += 2) {
7551       PetscInt o = points[p+1];
7552       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7553       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
7554     }
7555   }
7556   if (useGlobalDefault && !useDefault) {
7557     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7558   }
7559   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
7560   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7561   if (ierr) {
7562     PetscMPIInt    rank;
7563     PetscErrorCode ierr2;
7564 
7565     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
7566     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7567     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
7568     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
7569     CHKERRQ(ierr);
7570   }
7571   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7572   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7573   PetscFunctionReturn(0);
7574 }
7575 
7576 #undef __FUNCT__
7577 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
7578 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
7579 {
7580   PetscSection       coordSection;
7581   Vec                coordinates;
7582   const PetscScalar *coords;
7583   const PetscInt     dim = 2;
7584   PetscInt           d, f;
7585   PetscErrorCode     ierr;
7586 
7587   PetscFunctionBegin;
7588   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7589   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7590   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7591   if (v0) {
7592     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
7593   }
7594   if (J) {
7595     for (d = 0; d < dim; d++) {
7596       for (f = 0; f < dim; f++) {
7597         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7598       }
7599     }
7600     *detJ = J[0]*J[3] - J[1]*J[2];
7601 #if 0
7602     if (detJ < 0.0) {
7603       const PetscReal xLength = mesh->periodicity[0];
7604 
7605       if (xLength != 0.0) {
7606         PetscReal v0x = coords[0*dim+0];
7607 
7608         if (v0x == 0.0) v0x = v0[0] = xLength;
7609         for (f = 0; f < dim; f++) {
7610           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
7611 
7612           J[0*dim+f] = 0.5*(px - v0x);
7613         }
7614       }
7615       detJ = J[0]*J[3] - J[1]*J[2];
7616     }
7617 #endif
7618     PetscLogFlops(8.0 + 3.0);
7619   }
7620   if (invJ) {
7621     const PetscReal invDet = 1.0/(*detJ);
7622 
7623     invJ[0] =  invDet*J[3];
7624     invJ[1] = -invDet*J[1];
7625     invJ[2] = -invDet*J[2];
7626     invJ[3] =  invDet*J[0];
7627     PetscLogFlops(5.0);
7628   }
7629   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7630   PetscFunctionReturn(0);
7631 }
7632 
7633 #undef __FUNCT__
7634 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
7635 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
7636 {
7637   PetscSection       coordSection;
7638   Vec                coordinates;
7639   const PetscScalar *coords;
7640   const PetscInt     dim = 2;
7641   PetscInt           d, f;
7642   PetscErrorCode     ierr;
7643 
7644   PetscFunctionBegin;
7645   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7646   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7647   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7648   if (v0) {
7649     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
7650   }
7651   if (J) {
7652     for (d = 0; d < dim; d++) {
7653       for (f = 0; f < dim; f++) {
7654         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7655       }
7656     }
7657     *detJ = J[0]*J[3] - J[1]*J[2];
7658     PetscLogFlops(8.0 + 3.0);
7659   }
7660   if (invJ) {
7661     const PetscReal invDet = 1.0/(*detJ);
7662 
7663     invJ[0] =  invDet*J[3];
7664     invJ[1] = -invDet*J[1];
7665     invJ[2] = -invDet*J[2];
7666     invJ[3] =  invDet*J[0];
7667     PetscLogFlops(5.0);
7668   }
7669   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7670   PetscFunctionReturn(0);
7671 }
7672 
7673 #undef __FUNCT__
7674 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
7675 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
7676 {
7677   PetscSection       coordSection;
7678   Vec                coordinates;
7679   const PetscScalar *coords;
7680   const PetscInt     dim = 3;
7681   PetscInt           d, f;
7682   PetscErrorCode     ierr;
7683 
7684   PetscFunctionBegin;
7685   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7686   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7687   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7688   if (v0) {
7689     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
7690   }
7691   if (J) {
7692     for (d = 0; d < dim; d++) {
7693       for (f = 0; f < dim; f++) {
7694         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7695       }
7696     }
7697     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
7698     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
7699              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
7700              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
7701     PetscLogFlops(18.0 + 12.0);
7702   }
7703   if (invJ) {
7704     const PetscReal invDet = 1.0/(*detJ);
7705 
7706     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
7707     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
7708     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
7709     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
7710     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
7711     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
7712     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
7713     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
7714     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
7715     PetscLogFlops(37.0);
7716   }
7717   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7718   PetscFunctionReturn(0);
7719 }
7720 
7721 #undef __FUNCT__
7722 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
7723 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
7724 {
7725   PetscSection       coordSection;
7726   Vec                coordinates;
7727   const PetscScalar *coords;
7728   const PetscInt     dim = 3;
7729   PetscInt           d;
7730   PetscErrorCode     ierr;
7731 
7732   PetscFunctionBegin;
7733   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7734   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7735   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7736   if (v0) {
7737     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
7738   }
7739   if (J) {
7740     for (d = 0; d < dim; d++) {
7741       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7742       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7743       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7744     }
7745     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
7746              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
7747              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
7748     PetscLogFlops(18.0 + 12.0);
7749   }
7750   if (invJ) {
7751     const PetscReal invDet = -1.0/(*detJ);
7752 
7753     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
7754     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
7755     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
7756     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
7757     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
7758     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
7759     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
7760     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
7761     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
7762     PetscLogFlops(37.0);
7763   }
7764   *detJ *= 8.0;
7765   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7766   PetscFunctionReturn(0);
7767 }
7768 
7769 #undef __FUNCT__
7770 #define __FUNCT__ "DMPlexComputeCellGeometry"
7771 /*@C
7772   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
7773 
7774   Collective on DM
7775 
7776   Input Arguments:
7777 + dm   - the DM
7778 - cell - the cell
7779 
7780   Output Arguments:
7781 + v0   - the translation part of this affine transform
7782 . J    - the Jacobian of the transform to the reference element
7783 . invJ - the inverse of the Jacobian
7784 - detJ - the Jacobian determinant
7785 
7786   Level: advanced
7787 
7788   Fortran Notes:
7789   Since it returns arrays, this routine is only available in Fortran 90, and you must
7790   include petsc.h90 in your code.
7791 
7792 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
7793 @*/
7794 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
7795 {
7796   PetscInt       dim, coneSize;
7797   PetscErrorCode ierr;
7798 
7799   PetscFunctionBegin;
7800   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7801   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
7802   switch (dim) {
7803   case 2:
7804     switch (coneSize) {
7805     case 3:
7806       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
7807       break;
7808     case 4:
7809       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
7810       break;
7811     default:
7812       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
7813     }
7814     break;
7815   case 3:
7816     switch (coneSize) {
7817     case 4:
7818       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
7819       break;
7820     case 8:
7821       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
7822       break;
7823     default:
7824       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
7825     }
7826     break;
7827   default:
7828     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
7829   }
7830   PetscFunctionReturn(0);
7831 }
7832 
7833 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
7834 {
7835   switch (i) {
7836   case 0:
7837     switch (j) {
7838     case 0: return 0;
7839     case 1:
7840       switch (k) {
7841       case 0: return 0;
7842       case 1: return 0;
7843       case 2: return 1;
7844       }
7845     case 2:
7846       switch (k) {
7847       case 0: return 0;
7848       case 1: return -1;
7849       case 2: return 0;
7850       }
7851     }
7852   case 1:
7853     switch (j) {
7854     case 0:
7855       switch (k) {
7856       case 0: return 0;
7857       case 1: return 0;
7858       case 2: return -1;
7859       }
7860     case 1: return 0;
7861     case 2:
7862       switch (k) {
7863       case 0: return 1;
7864       case 1: return 0;
7865       case 2: return 0;
7866       }
7867     }
7868   case 2:
7869     switch (j) {
7870     case 0:
7871       switch (k) {
7872       case 0: return 0;
7873       case 1: return 1;
7874       case 2: return 0;
7875       }
7876     case 1:
7877       switch (k) {
7878       case 0: return -1;
7879       case 1: return 0;
7880       case 2: return 0;
7881       }
7882     case 2: return 0;
7883     }
7884   }
7885   return 0;
7886 }
7887 
7888 #undef __FUNCT__
7889 #define __FUNCT__ "DMPlexCreateRigidBody"
7890 /*@C
7891   DMPlexCreateRigidBody - create rigid body modes from coordinates
7892 
7893   Collective on DM
7894 
7895   Input Arguments:
7896 + dm - the DM
7897 . section - the local section associated with the rigid field, or NULL for the default section
7898 - globalSection - the global section associated with the rigid field, or NULL for the default section
7899 
7900   Output Argument:
7901 . sp - the null space
7902 
7903   Note: This is necessary to take account of Dirichlet conditions on the displacements
7904 
7905   Level: advanced
7906 
7907 .seealso: MatNullSpaceCreate()
7908 @*/
7909 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
7910 {
7911   MPI_Comm       comm;
7912   Vec            coordinates, localMode, mode[6];
7913   PetscSection   coordSection;
7914   PetscScalar   *coords;
7915   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
7916   PetscErrorCode ierr;
7917 
7918   PetscFunctionBegin;
7919   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
7920   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7921   if (dim == 1) {
7922     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
7923     PetscFunctionReturn(0);
7924   }
7925   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
7926   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
7927   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
7928   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7929   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7930   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7931   m    = (dim*(dim+1))/2;
7932   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
7933   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
7934   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
7935   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
7936   /* Assume P1 */
7937   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
7938   for (d = 0; d < dim; ++d) {
7939     PetscScalar values[3] = {0.0, 0.0, 0.0};
7940 
7941     values[d] = 1.0;
7942     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
7943     for (v = vStart; v < vEnd; ++v) {
7944       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
7945     }
7946     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
7947     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
7948   }
7949   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
7950   for (d = dim; d < dim*(dim+1)/2; ++d) {
7951     PetscInt i, j, k = dim > 2 ? d - dim : d;
7952 
7953     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
7954     for (v = vStart; v < vEnd; ++v) {
7955       PetscScalar values[3] = {0.0, 0.0, 0.0};
7956       PetscInt    off;
7957 
7958       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
7959       for (i = 0; i < dim; ++i) {
7960         for (j = 0; j < dim; ++j) {
7961           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
7962         }
7963       }
7964       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
7965     }
7966     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
7967     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
7968   }
7969   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
7970   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
7971   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
7972   /* Orthonormalize system */
7973   for (i = dim; i < m; ++i) {
7974     PetscScalar dots[6];
7975 
7976     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
7977     for (j = 0; j < i; ++j) dots[j] *= -1.0;
7978     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
7979     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
7980   }
7981   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
7982   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
7983   PetscFunctionReturn(0);
7984 }
7985 
7986 #undef __FUNCT__
7987 #define __FUNCT__ "DMPlexGetHybridBounds"
7988 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
7989 {
7990   DM_Plex       *mesh = (DM_Plex*) dm->data;
7991   PetscInt       dim;
7992   PetscErrorCode ierr;
7993 
7994   PetscFunctionBegin;
7995   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7996   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7997   if (cMax) *cMax = mesh->hybridPointMax[dim];
7998   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
7999   if (eMax) *eMax = mesh->hybridPointMax[1];
8000   if (vMax) *vMax = mesh->hybridPointMax[0];
8001   PetscFunctionReturn(0);
8002 }
8003 
8004 #undef __FUNCT__
8005 #define __FUNCT__ "DMPlexSetHybridBounds"
8006 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
8007 {
8008   DM_Plex       *mesh = (DM_Plex*) dm->data;
8009   PetscInt       dim;
8010   PetscErrorCode ierr;
8011 
8012   PetscFunctionBegin;
8013   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8014   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8015   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
8016   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
8017   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
8018   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
8019   PetscFunctionReturn(0);
8020 }
8021 
8022 #undef __FUNCT__
8023 #define __FUNCT__ "DMPlexGetVTKCellHeight"
8024 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8025 {
8026   DM_Plex *mesh = (DM_Plex*) dm->data;
8027 
8028   PetscFunctionBegin;
8029   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8030   PetscValidPointer(cellHeight, 2);
8031   *cellHeight = mesh->vtkCellHeight;
8032   PetscFunctionReturn(0);
8033 }
8034 
8035 #undef __FUNCT__
8036 #define __FUNCT__ "DMPlexSetVTKCellHeight"
8037 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8038 {
8039   DM_Plex *mesh = (DM_Plex*) dm->data;
8040 
8041   PetscFunctionBegin;
8042   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8043   mesh->vtkCellHeight = cellHeight;
8044   PetscFunctionReturn(0);
8045 }
8046 
8047 #undef __FUNCT__
8048 #define __FUNCT__ "DMPlexCreateNumbering_Private"
8049 /* We can easily have a form that takes an IS instead */
8050 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
8051 {
8052   PetscSection   section, globalSection;
8053   PetscInt      *numbers, p;
8054   PetscErrorCode ierr;
8055 
8056   PetscFunctionBegin;
8057   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
8058   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
8059   for (p = pStart; p < pEnd; ++p) {
8060     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
8061   }
8062   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
8063   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8064   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
8065   for (p = pStart; p < pEnd; ++p) {
8066     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
8067   }
8068   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
8069   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
8070   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8071   PetscFunctionReturn(0);
8072 }
8073 
8074 #undef __FUNCT__
8075 #define __FUNCT__ "DMPlexGetCellNumbering"
8076 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8077 {
8078   DM_Plex       *mesh = (DM_Plex*) dm->data;
8079   PetscInt       cellHeight, cStart, cEnd, cMax;
8080   PetscErrorCode ierr;
8081 
8082   PetscFunctionBegin;
8083   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8084   if (!mesh->globalCellNumbers) {
8085     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8086     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8087     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8088     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8089     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
8090   }
8091   *globalCellNumbers = mesh->globalCellNumbers;
8092   PetscFunctionReturn(0);
8093 }
8094 
8095 #undef __FUNCT__
8096 #define __FUNCT__ "DMPlexGetVertexNumbering"
8097 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8098 {
8099   DM_Plex       *mesh = (DM_Plex*) dm->data;
8100   PetscInt       vStart, vEnd, vMax;
8101   PetscErrorCode ierr;
8102 
8103   PetscFunctionBegin;
8104   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8105   if (!mesh->globalVertexNumbers) {
8106     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8107     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
8108     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
8109     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
8110   }
8111   *globalVertexNumbers = mesh->globalVertexNumbers;
8112   PetscFunctionReturn(0);
8113 }
8114 
8115 #undef __FUNCT__
8116 #define __FUNCT__ "DMPlexGetScale"
8117 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
8118 {
8119   DM_Plex *mesh = (DM_Plex*) dm->data;
8120 
8121   PetscFunctionBegin;
8122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8123   PetscValidPointer(scale, 3);
8124   *scale = mesh->scale[unit];
8125   PetscFunctionReturn(0);
8126 }
8127 
8128 #undef __FUNCT__
8129 #define __FUNCT__ "DMPlexSetScale"
8130 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
8131 {
8132   DM_Plex *mesh = (DM_Plex*) dm->data;
8133 
8134   PetscFunctionBegin;
8135   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8136   mesh->scale[unit] = scale;
8137   PetscFunctionReturn(0);
8138 }
8139 
8140 
8141 /*******************************************************************************
8142 This should be in a separate Discretization object, but I am not sure how to lay
8143 it out yet, so I am stuffing things here while I experiment.
8144 *******************************************************************************/
8145 #undef __FUNCT__
8146 #define __FUNCT__ "DMPlexSetFEMIntegration"
8147 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
8148                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
8149                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
8150                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8151                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
8152                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
8153                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
8154                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8155                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8156                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8157                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
8158                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
8159                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
8160                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8161                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8162                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8163                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
8164 {
8165   DM_Plex *mesh = (DM_Plex*) dm->data;
8166 
8167   PetscFunctionBegin;
8168   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8169   mesh->integrateResidualFEM       = integrateResidualFEM;
8170   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
8171   mesh->integrateJacobianFEM       = integrateJacobianFEM;
8172   PetscFunctionReturn(0);
8173 }
8174 
8175 #undef __FUNCT__
8176 #define __FUNCT__ "DMPlexProjectFunctionLocal"
8177 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
8178 {
8179   Vec            coordinates;
8180   PetscSection   section, cSection;
8181   PetscInt       dim, vStart, vEnd, v, c, d;
8182   PetscScalar   *values, *cArray;
8183   PetscReal     *coords;
8184   PetscErrorCode ierr;
8185 
8186   PetscFunctionBegin;
8187   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8188   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8189   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
8190   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8191   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
8192   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
8193   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
8194   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
8195   for (v = vStart; v < vEnd; ++v) {
8196     PetscInt dof, off;
8197 
8198     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
8199     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
8200     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
8201     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
8202     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
8203     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
8204   }
8205   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
8206   /* Temporary, must be replaced by a projection on the finite element basis */
8207   {
8208     PetscInt eStart = 0, eEnd = 0, e, depth;
8209 
8210     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
8211     --depth;
8212     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
8213     for (e = eStart; e < eEnd; ++e) {
8214       const PetscInt *cone = NULL;
8215       PetscInt        coneSize, d;
8216       PetscScalar    *coordsA, *coordsB;
8217 
8218       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
8219       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8220       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
8221       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
8222       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
8223       for (d = 0; d < dim; ++d) {
8224         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
8225       }
8226       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
8227       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
8228     }
8229   }
8230 
8231   ierr = PetscFree(coords);CHKERRQ(ierr);
8232   ierr = PetscFree(values);CHKERRQ(ierr);
8233 #if 0
8234   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
8235   PetscReal      detJ;
8236 
8237   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
8238   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
8239   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
8240 
8241   for (PetscInt c = cStart; c < cEnd; ++c) {
8242     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
8243     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
8244     const int                          oSize   = pV.getSize();
8245     int                                v       = 0;
8246 
8247     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
8248     for (PetscInt cl = 0; cl < oSize; ++cl) {
8249       const PetscInt fDim;
8250 
8251       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
8252       if (pointDim) {
8253         for (PetscInt d = 0; d < fDim; ++d, ++v) {
8254           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
8255         }
8256       }
8257     }
8258     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
8259     pV.clear();
8260   }
8261   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
8262   ierr = PetscFree(values);CHKERRQ(ierr);
8263 #endif
8264   PetscFunctionReturn(0);
8265 }
8266 
8267 #undef __FUNCT__
8268 #define __FUNCT__ "DMPlexProjectFunction"
8269 /*@C
8270   DMPlexProjectFunction - This projects the given function into the function space provided.
8271 
8272   Input Parameters:
8273 + dm      - The DM
8274 . numComp - The number of components (functions)
8275 . funcs   - The coordinate functions to evaluate
8276 - mode    - The insertion mode for values
8277 
8278   Output Parameter:
8279 . X - vector
8280 
8281   Level: developer
8282 
8283   Note:
8284   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
8285   We will eventually fix it.
8286 
8287 ,seealso: DMPlexComputeL2Diff()
8288 */
8289 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
8290 {
8291   Vec            localX;
8292   PetscErrorCode ierr;
8293 
8294   PetscFunctionBegin;
8295   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
8296   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
8297   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
8298   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
8299   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
8300   PetscFunctionReturn(0);
8301 }
8302 
8303 #undef __FUNCT__
8304 #define __FUNCT__ "DMPlexComputeL2Diff"
8305 /*@C
8306   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8307 
8308   Input Parameters:
8309 + dm    - The DM
8310 . quad  - The PetscQuadrature object for each field
8311 . funcs - The functions to evaluate for each field component
8312 - X     - The coefficient vector u_h
8313 
8314   Output Parameter:
8315 . diff - The diff ||u - u_h||_2
8316 
8317   Level: developer
8318 
8319 .seealso: DMPlexProjectFunction()
8320 */
8321 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
8322 {
8323   const PetscInt debug = 0;
8324   PetscSection   section;
8325   Vec            localX;
8326   PetscReal     *coords, *v0, *J, *invJ, detJ;
8327   PetscReal      localDiff = 0.0;
8328   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
8329   PetscErrorCode ierr;
8330 
8331   PetscFunctionBegin;
8332   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8333   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8334   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8335   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
8336   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
8337   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
8338   for (field = 0; field < numFields; ++field) {
8339     numComponents += quad[field].numComponents;
8340   }
8341   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
8342   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
8343   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8344   for (c = cStart; c < cEnd; ++c) {
8345     const PetscScalar *x;
8346     PetscReal          elemDiff = 0.0;
8347 
8348     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8349     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
8350     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
8351 
8352     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
8353       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
8354       const PetscReal *quadPoints    = quad[field].quadPoints;
8355       const PetscReal *quadWeights   = quad[field].quadWeights;
8356       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
8357       const PetscInt   numBasisComps = quad[field].numComponents;
8358       const PetscReal *basis         = quad[field].basis;
8359       PetscInt         q, d, e, fc, f;
8360 
8361       if (debug) {
8362         char title[1024];
8363         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
8364         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
8365       }
8366       for (q = 0; q < numQuadPoints; ++q) {
8367         for (d = 0; d < dim; d++) {
8368           coords[d] = v0[d];
8369           for (e = 0; e < dim; e++) {
8370             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
8371           }
8372         }
8373         for (fc = 0; fc < numBasisComps; ++fc) {
8374           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
8375           PetscReal       interpolant = 0.0;
8376           for (f = 0; f < numBasisFuncs; ++f) {
8377             const PetscInt fidx = f*numBasisComps+fc;
8378             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
8379           }
8380           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
8381           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
8382         }
8383       }
8384       comp        += numBasisComps;
8385       fieldOffset += numBasisFuncs*numBasisComps;
8386     }
8387     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
8388     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
8389     localDiff += elemDiff;
8390   }
8391   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
8392   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
8393   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
8394   *diff = PetscSqrtReal(*diff);
8395   PetscFunctionReturn(0);
8396 }
8397 
8398 #undef __FUNCT__
8399 #define __FUNCT__ "DMPlexComputeResidualFEM"
8400 /*@
8401   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
8402 
8403   Input Parameters:
8404 + dm - The mesh
8405 . X  - Local input vector
8406 - user - The user context
8407 
8408   Output Parameter:
8409 . F  - Local output vector
8410 
8411   Note:
8412   The second member of the user context must be an FEMContext.
8413 
8414   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
8415   like a GPU, or vectorize on a multicore machine.
8416 
8417 .seealso: DMPlexComputeJacobianActionFEM()
8418 */
8419 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
8420 {
8421   DM_Plex         *mesh = (DM_Plex*) dm->data;
8422   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
8423   PetscQuadrature *quad = fem->quad;
8424   PetscSection     section;
8425   PetscReal       *v0, *J, *invJ, *detJ;
8426   PetscScalar     *elemVec, *u;
8427   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
8428   PetscInt         cellDof = 0, numComponents = 0;
8429   PetscErrorCode   ierr;
8430 
8431   PetscFunctionBegin;
8432   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8433   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8434   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8435   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8436   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8437   numCells = cEnd - cStart;
8438   for (field = 0; field < numFields; ++field) {
8439     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
8440     numComponents += quad[field].numComponents;
8441   }
8442   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
8443   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
8444   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);
8445   for (c = cStart; c < cEnd; ++c) {
8446     const PetscScalar *x;
8447     PetscInt           i;
8448 
8449     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
8450     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
8451     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8452 
8453     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
8454     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8455   }
8456   for (field = 0; field < numFields; ++field) {
8457     const PetscInt numQuadPoints = quad[field].numQuadPoints;
8458     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
8459     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
8460     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
8461     /* Conforming batches */
8462     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
8463     PetscInt numBlocks  = 1;
8464     PetscInt batchSize  = numBlocks * blockSize;
8465     PetscInt numBatches = numBatchesTmp;
8466     PetscInt numChunks  = numCells / (numBatches*batchSize);
8467     /* Remainder */
8468     PetscInt numRemainder = numCells % (numBatches * batchSize);
8469     PetscInt offset       = numCells - numRemainder;
8470 
8471     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
8472     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
8473                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
8474   }
8475   for (c = cStart; c < cEnd; ++c) {
8476     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
8477     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
8478   }
8479   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
8480   if (mesh->printFEM) {
8481     PetscMPIInt rank, numProcs;
8482     PetscInt    p;
8483 
8484     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
8485     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
8486     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
8487     for (p = 0; p < numProcs; ++p) {
8488       if (p == rank) {
8489         Vec f;
8490 
8491         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
8492         ierr = VecCopy(F, f);CHKERRQ(ierr);
8493         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
8494         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
8495         ierr = VecDestroy(&f);CHKERRQ(ierr);
8496         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
8497       }
8498       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
8499     }
8500   }
8501   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8502   PetscFunctionReturn(0);
8503 }
8504 
8505 #undef __FUNCT__
8506 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
8507 /*@C
8508   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
8509 
8510   Input Parameters:
8511 + dm - The mesh
8512 . J  - The Jacobian shell matrix
8513 . X  - Local input vector
8514 - user - The user context
8515 
8516   Output Parameter:
8517 . F  - Local output vector
8518 
8519   Note:
8520   The second member of the user context must be an FEMContext.
8521 
8522   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
8523   like a GPU, or vectorize on a multicore machine.
8524 
8525 .seealso: DMPlexComputeResidualFEM()
8526 */
8527 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
8528 {
8529   DM_Plex         *mesh = (DM_Plex*) dm->data;
8530   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
8531   PetscQuadrature *quad = fem->quad;
8532   PetscSection     section;
8533   JacActionCtx    *jctx;
8534   PetscReal       *v0, *J, *invJ, *detJ;
8535   PetscScalar     *elemVec, *u, *a;
8536   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
8537   PetscInt         cellDof = 0;
8538   PetscErrorCode   ierr;
8539 
8540   PetscFunctionBegin;
8541   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8542   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
8543   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8544   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8545   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8546   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8547   numCells = cEnd - cStart;
8548   for (field = 0; field < numFields; ++field) {
8549     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
8550   }
8551   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
8552   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);
8553   for (c = cStart; c < cEnd; ++c) {
8554     const PetscScalar *x;
8555     PetscInt           i;
8556 
8557     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
8558     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
8559     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
8560     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
8561     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
8562     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8563     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
8564     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8565   }
8566   for (field = 0; field < numFields; ++field) {
8567     const PetscInt numQuadPoints = quad[field].numQuadPoints;
8568     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
8569     /* Conforming batches */
8570     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
8571     PetscInt numBlocks  = 1;
8572     PetscInt batchSize  = numBlocks * blockSize;
8573     PetscInt numBatches = numBatchesTmp;
8574     PetscInt numChunks  = numCells / (numBatches*batchSize);
8575     /* Remainder */
8576     PetscInt numRemainder = numCells % (numBatches * batchSize);
8577     PetscInt offset       = numCells - numRemainder;
8578 
8579     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);
8580     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],
8581                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
8582   }
8583   for (c = cStart; c < cEnd; ++c) {
8584     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
8585     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
8586   }
8587   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
8588   if (mesh->printFEM) {
8589     PetscMPIInt rank, numProcs;
8590     PetscInt    p;
8591 
8592     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
8593     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
8594     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
8595     for (p = 0; p < numProcs; ++p) {
8596       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
8597       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
8598     }
8599   }
8600   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8601   PetscFunctionReturn(0);
8602 }
8603 
8604 #undef __FUNCT__
8605 #define __FUNCT__ "DMPlexComputeJacobianFEM"
8606 /*@
8607   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
8608 
8609   Input Parameters:
8610 + dm - The mesh
8611 . X  - Local input vector
8612 - user - The user context
8613 
8614   Output Parameter:
8615 . Jac  - Jacobian matrix
8616 
8617   Note:
8618   The second member of the user context must be an FEMContext.
8619 
8620   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
8621   like a GPU, or vectorize on a multicore machine.
8622 
8623 .seealso: FormFunctionLocal()
8624 */
8625 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
8626 {
8627   DM_Plex         *mesh = (DM_Plex*) dm->data;
8628   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
8629   PetscQuadrature *quad = fem->quad;
8630   PetscSection     section;
8631   PetscReal       *v0, *J, *invJ, *detJ;
8632   PetscScalar     *elemMat, *u;
8633   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
8634   PetscInt         cellDof = 0, numComponents = 0;
8635   PetscBool        isShell;
8636   PetscErrorCode   ierr;
8637 
8638   PetscFunctionBegin;
8639   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8640   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8641   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8642   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8643   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8644   numCells = cEnd - cStart;
8645   for (field = 0; field < numFields; ++field) {
8646     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
8647     numComponents += quad[field].numComponents;
8648   }
8649   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
8650   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
8651   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);
8652   for (c = cStart; c < cEnd; ++c) {
8653     const PetscScalar *x;
8654     PetscInt           i;
8655 
8656     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
8657     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
8658     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8659 
8660     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
8661     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8662   }
8663   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
8664   for (fieldI = 0; fieldI < numFields; ++fieldI) {
8665     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
8666     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
8667     PetscInt       fieldJ;
8668 
8669     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
8670       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
8671       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
8672       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
8673       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
8674       /* Conforming batches */
8675       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
8676       PetscInt numBlocks  = 1;
8677       PetscInt batchSize  = numBlocks * blockSize;
8678       PetscInt numBatches = numBatchesTmp;
8679       PetscInt numChunks  = numCells / (numBatches*batchSize);
8680       /* Remainder */
8681       PetscInt numRemainder = numCells % (numBatches * batchSize);
8682       PetscInt offset       = numCells - numRemainder;
8683 
8684       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
8685       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
8686                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
8687     }
8688   }
8689   for (c = cStart; c < cEnd; ++c) {
8690     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
8691     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
8692   }
8693   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
8694 
8695   /* Assemble matrix, using the 2-step process:
8696        MatAssemblyBegin(), MatAssemblyEnd(). */
8697   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
8698   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
8699 
8700   if (mesh->printFEM) {
8701     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
8702     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
8703     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
8704   }
8705   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8706   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
8707   if (isShell) {
8708     JacActionCtx *jctx;
8709 
8710     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
8711     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
8712   }
8713   *str = SAME_NONZERO_PATTERN;
8714   PetscFunctionReturn(0);
8715 }
8716 
8717 
8718 #undef __FUNCT__
8719 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
8720 /*@C
8721   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
8722   the local section and an SF describing the section point overlap.
8723 
8724   Input Parameters:
8725   + s - The PetscSection for the local field layout
8726   . sf - The SF describing parallel layout of the section points
8727   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
8728   . label - The label specifying the points
8729   - labelValue - The label stratum specifying the points
8730 
8731   Output Parameter:
8732   . gsection - The PetscSection for the global field layout
8733 
8734   Note: This gives negative sizes and offsets to points not owned by this process
8735 
8736   Level: developer
8737 
8738 .seealso: PetscSectionCreate()
8739 @*/
8740 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
8741 {
8742   PetscInt      *neg;
8743   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
8744   PetscErrorCode ierr;
8745 
8746   PetscFunctionBegin;
8747   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
8748   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
8749   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
8750   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
8751   /* Mark ghost points with negative dof */
8752   for (p = pStart; p < pEnd; ++p) {
8753     PetscInt value;
8754 
8755     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
8756     if (value != labelValue) continue;
8757     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
8758     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
8759     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
8760     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
8761     neg[p-pStart] = -(dof+1);
8762   }
8763   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
8764   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
8765   if (nroots >= 0) {
8766     if (nroots > pEnd - pStart) {
8767       PetscInt *tmpDof;
8768       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
8769       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
8770       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
8771       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
8772       for (p = pStart; p < pEnd; ++p) {
8773         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
8774       }
8775       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
8776     } else {
8777       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
8778       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
8779     }
8780   }
8781   /* Calculate new sizes, get proccess offset, and calculate point offsets */
8782   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
8783     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
8784 
8785     (*gsection)->atlasOff[p] = off;
8786 
8787     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
8788   }
8789   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
8790   globalOff -= off;
8791   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
8792     (*gsection)->atlasOff[p] += globalOff;
8793 
8794     neg[p] = -((*gsection)->atlasOff[p]+1);
8795   }
8796   /* Put in negative offsets for ghost points */
8797   if (nroots >= 0) {
8798     if (nroots > pEnd - pStart) {
8799       PetscInt *tmpOff;
8800       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
8801       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
8802       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
8803       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
8804       for (p = pStart; p < pEnd; ++p) {
8805         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
8806       }
8807       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
8808     } else {
8809       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
8810       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
8811     }
8812   }
8813   ierr = PetscFree(neg);CHKERRQ(ierr);
8814   PetscFunctionReturn(0);
8815 }
8816