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