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