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