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