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