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