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