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