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