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