xref: /petsc/src/dm/impls/plex/plex.c (revision d49bb8f946631d5470c2a737c5ecfe1ed81df0b7)
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 = PetscSectionSetUp(*section);CHKERRQ(ierr);
3592   ierr = DMPlexGetAnchors(dm,&aSec,NULL);CHKERRQ(ierr);
3593   if (numBC || aSec) {
3594     ierr = DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
3595     ierr = DMPlexCreateSectionBCIndices(dm, *section);CHKERRQ(ierr);
3596   }
3597   ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr);
3598   PetscFunctionReturn(0);
3599 }
3600 
3601 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3602 {
3603   PetscSection   section, s;
3604   Mat            m;
3605   PetscInt       maxHeight;
3606   PetscErrorCode ierr;
3607 
3608   PetscFunctionBegin;
3609   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
3610   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
3611   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
3612   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
3613   ierr = DMSetSection(*cdm, section);CHKERRQ(ierr);
3614   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
3615   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
3616   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
3617   ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr);
3618   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
3619   ierr = MatDestroy(&m);CHKERRQ(ierr);
3620   PetscFunctionReturn(0);
3621 }
3622 
3623 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3624 {
3625   Vec            coordsLocal;
3626   DM             coordsDM;
3627   PetscErrorCode ierr;
3628 
3629   PetscFunctionBegin;
3630   *field = NULL;
3631   ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr);
3632   ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr);
3633   if (coordsLocal && coordsDM) {
3634     ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr);
3635   }
3636   PetscFunctionReturn(0);
3637 }
3638 
3639 /*@C
3640   DMPlexGetConeSection - Return a section which describes the layout of cone data
3641 
3642   Not Collective
3643 
3644   Input Parameters:
3645 . dm        - The DMPlex object
3646 
3647   Output Parameter:
3648 . section - The PetscSection object
3649 
3650   Level: developer
3651 
3652 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3653 @*/
3654 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3655 {
3656   DM_Plex *mesh = (DM_Plex*) dm->data;
3657 
3658   PetscFunctionBegin;
3659   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3660   if (section) *section = mesh->coneSection;
3661   PetscFunctionReturn(0);
3662 }
3663 
3664 /*@C
3665   DMPlexGetSupportSection - Return a section which describes the layout of support data
3666 
3667   Not Collective
3668 
3669   Input Parameters:
3670 . dm        - The DMPlex object
3671 
3672   Output Parameter:
3673 . section - The PetscSection object
3674 
3675   Level: developer
3676 
3677 .seealso: DMPlexGetConeSection()
3678 @*/
3679 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3680 {
3681   DM_Plex *mesh = (DM_Plex*) dm->data;
3682 
3683   PetscFunctionBegin;
3684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3685   if (section) *section = mesh->supportSection;
3686   PetscFunctionReturn(0);
3687 }
3688 
3689 /*@C
3690   DMPlexGetCones - Return cone data
3691 
3692   Not Collective
3693 
3694   Input Parameters:
3695 . dm        - The DMPlex object
3696 
3697   Output Parameter:
3698 . cones - The cone for each point
3699 
3700   Level: developer
3701 
3702 .seealso: DMPlexGetConeSection()
3703 @*/
3704 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3705 {
3706   DM_Plex *mesh = (DM_Plex*) dm->data;
3707 
3708   PetscFunctionBegin;
3709   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3710   if (cones) *cones = mesh->cones;
3711   PetscFunctionReturn(0);
3712 }
3713 
3714 /*@C
3715   DMPlexGetConeOrientations - Return cone orientation data
3716 
3717   Not Collective
3718 
3719   Input Parameters:
3720 . dm        - The DMPlex object
3721 
3722   Output Parameter:
3723 . coneOrientations - The cone orientation for each point
3724 
3725   Level: developer
3726 
3727 .seealso: DMPlexGetConeSection()
3728 @*/
3729 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3730 {
3731   DM_Plex *mesh = (DM_Plex*) dm->data;
3732 
3733   PetscFunctionBegin;
3734   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3735   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3736   PetscFunctionReturn(0);
3737 }
3738 
3739 /******************************** FEM Support **********************************/
3740 
3741 PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3742 {
3743   DMLabel        label;
3744   PetscInt      *perm;
3745   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3746   PetscErrorCode ierr;
3747 
3748   PetscFunctionBegin;
3749   if (point < 0) {ierr = DMPlexGetDepthStratum(dm, 1, &point, NULL);CHKERRQ(ierr);}
3750   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3751   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3752   ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr);
3753   if (depth == 1) {eStart = point;}
3754   else if  (depth == dim) {
3755     const PetscInt *cone;
3756 
3757     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3758     eStart = cone[0];
3759   } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering", point, depth);
3760   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
3761   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
3762   if (dim <= 1) PetscFunctionReturn(0);
3763   for (f = 0; f < Nf; ++f) {
3764     /* An order k SEM disc has k-1 dofs on an edge */
3765     ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3766     ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3767     k = k/Nc + 1;
3768     size += PetscPowInt(k+1, dim)*Nc;
3769   }
3770   ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
3771   for (f = 0; f < Nf; ++f) {
3772     switch (dim) {
3773     case 2:
3774       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3775       ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3776       ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3777       k = k/Nc + 1;
3778       /* The SEM order is
3779 
3780          v_lb, {e_b}, v_rb,
3781          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3782          v_lt, reverse {e_t}, v_rt
3783       */
3784       {
3785         const PetscInt of   = 0;
3786         const PetscInt oeb  = of   + PetscSqr(k-1);
3787         const PetscInt oer  = oeb  + (k-1);
3788         const PetscInt oet  = oer  + (k-1);
3789         const PetscInt oel  = oet  + (k-1);
3790         const PetscInt ovlb = oel  + (k-1);
3791         const PetscInt ovrb = ovlb + 1;
3792         const PetscInt ovrt = ovrb + 1;
3793         const PetscInt ovlt = ovrt + 1;
3794         PetscInt       o;
3795 
3796         /* bottom */
3797         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3798         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3799         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3800         /* middle */
3801         for (i = 0; i < k-1; ++i) {
3802           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3803           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;
3804           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3805         }
3806         /* top */
3807         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3808         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3809         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3810         foffset = offset;
3811       }
3812       break;
3813     case 3:
3814       /* The original hex closure is
3815 
3816          {c,
3817           f_b, f_t, f_f, f_b, f_r, f_l,
3818           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3819           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3820       */
3821       ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3822       ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3823       k = k/Nc + 1;
3824       /* The SEM order is
3825          Bottom Slice
3826          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3827          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3828          v_blb, {e_bb}, v_brb,
3829 
3830          Middle Slice (j)
3831          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3832          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3833          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3834 
3835          Top Slice
3836          v_tlf, {e_tf}, v_trf,
3837          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3838          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3839       */
3840       {
3841         const PetscInt oc    = 0;
3842         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3843         const PetscInt oft   = ofb   + PetscSqr(k-1);
3844         const PetscInt off   = oft   + PetscSqr(k-1);
3845         const PetscInt ofk   = off   + PetscSqr(k-1);
3846         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3847         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3848         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3849         const PetscInt oebb  = oebl  + (k-1);
3850         const PetscInt oebr  = oebb  + (k-1);
3851         const PetscInt oebf  = oebr  + (k-1);
3852         const PetscInt oetf  = oebf  + (k-1);
3853         const PetscInt oetr  = oetf  + (k-1);
3854         const PetscInt oetb  = oetr  + (k-1);
3855         const PetscInt oetl  = oetb  + (k-1);
3856         const PetscInt oerf  = oetl  + (k-1);
3857         const PetscInt oelf  = oerf  + (k-1);
3858         const PetscInt oelb  = oelf  + (k-1);
3859         const PetscInt oerb  = oelb  + (k-1);
3860         const PetscInt ovblf = oerb  + (k-1);
3861         const PetscInt ovblb = ovblf + 1;
3862         const PetscInt ovbrb = ovblb + 1;
3863         const PetscInt ovbrf = ovbrb + 1;
3864         const PetscInt ovtlf = ovbrf + 1;
3865         const PetscInt ovtrf = ovtlf + 1;
3866         const PetscInt ovtrb = ovtrf + 1;
3867         const PetscInt ovtlb = ovtrb + 1;
3868         PetscInt       o, n;
3869 
3870         /* Bottom Slice */
3871         /*   bottom */
3872         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3873         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3874         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3875         /*   middle */
3876         for (i = 0; i < k-1; ++i) {
3877           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3878           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;}
3879           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3880         }
3881         /*   top */
3882         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3883         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3884         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
3885 
3886         /* Middle Slice */
3887         for (j = 0; j < k-1; ++j) {
3888           /*   bottom */
3889           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3890           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;
3891           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3892           /*   middle */
3893           for (i = 0; i < k-1; ++i) {
3894             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3895             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;
3896             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3897           }
3898           /*   top */
3899           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3900           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;
3901           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3902         }
3903 
3904         /* Top Slice */
3905         /*   bottom */
3906         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3907         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3908         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3909         /*   middle */
3910         for (i = 0; i < k-1; ++i) {
3911           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3912           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3913           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3914         }
3915         /*   top */
3916         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3917         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3918         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
3919 
3920         foffset = offset;
3921       }
3922       break;
3923     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3924     }
3925   }
3926   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3927   /* Check permutation */
3928   {
3929     PetscInt *check;
3930 
3931     ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
3932     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]);}
3933     for (i = 0; i < size; ++i) check[perm[i]] = i;
3934     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3935     ierr = PetscFree(check);CHKERRQ(ierr);
3936   }
3937   ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
3938   PetscFunctionReturn(0);
3939 }
3940 
3941 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3942 {
3943   PetscDS        prob;
3944   PetscInt       depth, Nf, h;
3945   DMLabel        label;
3946   PetscErrorCode ierr;
3947 
3948   PetscFunctionBeginHot;
3949   prob    = dm->prob;
3950   Nf      = prob->Nf;
3951   label   = dm->depthLabel;
3952   *dspace = NULL;
3953   if (field < Nf) {
3954     PetscObject disc = prob->disc[field];
3955 
3956     if (disc->classid == PETSCFE_CLASSID) {
3957       PetscDualSpace dsp;
3958 
3959       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3960       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
3961       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
3962       h    = depth - 1 - h;
3963       if (h) {
3964         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
3965       } else {
3966         *dspace = dsp;
3967       }
3968     }
3969   }
3970   PetscFunctionReturn(0);
3971 }
3972 
3973 
3974 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3975 {
3976   PetscScalar    *array, *vArray;
3977   const PetscInt *cone, *coneO;
3978   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3979   PetscErrorCode  ierr;
3980 
3981   PetscFunctionBeginHot;
3982   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3983   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3984   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3985   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3986   if (!values || !*values) {
3987     if ((point >= pStart) && (point < pEnd)) {
3988       PetscInt dof;
3989 
3990       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3991       size += dof;
3992     }
3993     for (p = 0; p < numPoints; ++p) {
3994       const PetscInt cp = cone[p];
3995       PetscInt       dof;
3996 
3997       if ((cp < pStart) || (cp >= pEnd)) continue;
3998       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3999       size += dof;
4000     }
4001     if (!values) {
4002       if (csize) *csize = size;
4003       PetscFunctionReturn(0);
4004     }
4005     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
4006   } else {
4007     array = *values;
4008   }
4009   size = 0;
4010   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4011   if ((point >= pStart) && (point < pEnd)) {
4012     PetscInt     dof, off, d;
4013     PetscScalar *varr;
4014 
4015     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4016     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4017     varr = &vArray[off];
4018     for (d = 0; d < dof; ++d, ++offset) {
4019       array[offset] = varr[d];
4020     }
4021     size += dof;
4022   }
4023   for (p = 0; p < numPoints; ++p) {
4024     const PetscInt cp = cone[p];
4025     PetscInt       o  = coneO[p];
4026     PetscInt       dof, off, d;
4027     PetscScalar   *varr;
4028 
4029     if ((cp < pStart) || (cp >= pEnd)) continue;
4030     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4031     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
4032     varr = &vArray[off];
4033     if (o >= 0) {
4034       for (d = 0; d < dof; ++d, ++offset) {
4035         array[offset] = varr[d];
4036       }
4037     } else {
4038       for (d = dof-1; d >= 0; --d, ++offset) {
4039         array[offset] = varr[d];
4040       }
4041     }
4042     size += dof;
4043   }
4044   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4045   if (!*values) {
4046     if (csize) *csize = size;
4047     *values = array;
4048   } else {
4049     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4050     *csize = size;
4051   }
4052   PetscFunctionReturn(0);
4053 }
4054 
4055 static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4056 {
4057   const PetscInt *cla;
4058   PetscInt       np, *pts = NULL;
4059   PetscErrorCode ierr;
4060 
4061   PetscFunctionBeginHot;
4062   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
4063   if (!*clPoints) {
4064     PetscInt pStart, pEnd, p, q;
4065 
4066     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4067     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
4068     /* Compress out points not in the section */
4069     for (p = 0, q = 0; p < np; p++) {
4070       PetscInt r = pts[2*p];
4071       if ((r >= pStart) && (r < pEnd)) {
4072         pts[q*2]   = r;
4073         pts[q*2+1] = pts[2*p+1];
4074         ++q;
4075       }
4076     }
4077     np = q;
4078     cla = NULL;
4079   } else {
4080     PetscInt dof, off;
4081 
4082     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
4083     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
4084     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
4085     np   = dof/2;
4086     pts  = (PetscInt *) &cla[off];
4087   }
4088   *numPoints = np;
4089   *points    = pts;
4090   *clp       = cla;
4091 
4092   PetscFunctionReturn(0);
4093 }
4094 
4095 static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4096 {
4097   PetscErrorCode ierr;
4098 
4099   PetscFunctionBeginHot;
4100   if (!*clPoints) {
4101     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
4102   } else {
4103     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
4104   }
4105   *numPoints = 0;
4106   *points    = NULL;
4107   *clSec     = NULL;
4108   *clPoints  = NULL;
4109   *clp       = NULL;
4110   PetscFunctionReturn(0);
4111 }
4112 
4113 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[])
4114 {
4115   PetscInt          offset = 0, p;
4116   const PetscInt    **perms = NULL;
4117   const PetscScalar **flips = NULL;
4118   PetscErrorCode    ierr;
4119 
4120   PetscFunctionBeginHot;
4121   *size = 0;
4122   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4123   for (p = 0; p < numPoints; p++) {
4124     const PetscInt    point = points[2*p];
4125     const PetscInt    *perm = perms ? perms[p] : NULL;
4126     const PetscScalar *flip = flips ? flips[p] : NULL;
4127     PetscInt          dof, off, d;
4128     const PetscScalar *varr;
4129 
4130     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4131     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4132     varr = &vArray[off];
4133     if (clperm) {
4134       if (perm) {
4135         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4136       } else {
4137         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4138       }
4139       if (flip) {
4140         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4141       }
4142     } else {
4143       if (perm) {
4144         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4145       } else {
4146         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4147       }
4148       if (flip) {
4149         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4150       }
4151     }
4152     offset += dof;
4153   }
4154   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4155   *size = offset;
4156   PetscFunctionReturn(0);
4157 }
4158 
4159 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[])
4160 {
4161   PetscInt          offset = 0, f;
4162   PetscErrorCode    ierr;
4163 
4164   PetscFunctionBeginHot;
4165   *size = 0;
4166   for (f = 0; f < numFields; ++f) {
4167     PetscInt          p;
4168     const PetscInt    **perms = NULL;
4169     const PetscScalar **flips = NULL;
4170 
4171     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4172     for (p = 0; p < numPoints; p++) {
4173       const PetscInt    point = points[2*p];
4174       PetscInt          fdof, foff, b;
4175       const PetscScalar *varr;
4176       const PetscInt    *perm = perms ? perms[p] : NULL;
4177       const PetscScalar *flip = flips ? flips[p] : NULL;
4178 
4179       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4180       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4181       varr = &vArray[foff];
4182       if (clperm) {
4183         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4184         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4185         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4186       } else {
4187         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4188         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4189         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4190       }
4191       offset += fdof;
4192     }
4193     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4194   }
4195   *size = offset;
4196   PetscFunctionReturn(0);
4197 }
4198 
4199 /*@C
4200   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4201 
4202   Not collective
4203 
4204   Input Parameters:
4205 + dm - The DM
4206 . section - The section describing the layout in v, or NULL to use the default section
4207 . v - The local vector
4208 . point - The point in the DM
4209 . csize - The size of the input values array, or NULL
4210 - values - An array to use for the values, or NULL to have it allocated automatically
4211 
4212   Output Parameters:
4213 + csize - The number of values in the closure
4214 - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4215 
4216 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4217 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4218 $ assembly function, and a user may already have allocated storage for this operation.
4219 $
4220 $ A typical use could be
4221 $
4222 $  values = NULL;
4223 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4224 $  for (cl = 0; cl < clSize; ++cl) {
4225 $    <Compute on closure>
4226 $  }
4227 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4228 $
4229 $ or
4230 $
4231 $  PetscMalloc1(clMaxSize, &values);
4232 $  for (p = pStart; p < pEnd; ++p) {
4233 $    clSize = clMaxSize;
4234 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4235 $    for (cl = 0; cl < clSize; ++cl) {
4236 $      <Compute on closure>
4237 $    }
4238 $  }
4239 $  PetscFree(values);
4240 
4241   Fortran Notes:
4242   Since it returns an array, this routine is only available in Fortran 90, and you must
4243   include petsc.h90 in your code.
4244 
4245   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4246 
4247   Level: intermediate
4248 
4249 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4250 @*/
4251 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4252 {
4253   PetscSection       clSection;
4254   IS                 clPoints;
4255   PetscScalar       *array;
4256   const PetscScalar *vArray;
4257   PetscInt          *points = NULL;
4258   const PetscInt    *clp, *perm;
4259   PetscInt           depth, numFields, numPoints, size;
4260   PetscErrorCode     ierr;
4261 
4262   PetscFunctionBeginHot;
4263   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4264   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
4265   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4266   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4267   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4268   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4269   if (depth == 1 && numFields < 2) {
4270     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
4271     PetscFunctionReturn(0);
4272   }
4273   /* Get points */
4274   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4275   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr);
4276   /* Get array */
4277   if (!values || !*values) {
4278     PetscInt asize = 0, dof, p;
4279 
4280     for (p = 0; p < numPoints*2; p += 2) {
4281       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4282       asize += dof;
4283     }
4284     if (!values) {
4285       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4286       if (csize) *csize = asize;
4287       PetscFunctionReturn(0);
4288     }
4289     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
4290   } else {
4291     array = *values;
4292   }
4293   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
4294   /* Get values */
4295   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
4296   else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);CHKERRQ(ierr);}
4297   /* Cleanup points */
4298   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4299   /* Cleanup array */
4300   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
4301   if (!*values) {
4302     if (csize) *csize = size;
4303     *values = array;
4304   } else {
4305     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4306     *csize = size;
4307   }
4308   PetscFunctionReturn(0);
4309 }
4310 
4311 /*@C
4312   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4313 
4314   Not collective
4315 
4316   Input Parameters:
4317 + dm - The DM
4318 . section - The section describing the layout in v, or NULL to use the default section
4319 . v - The local vector
4320 . point - The point in the DM
4321 . csize - The number of values in the closure, or NULL
4322 - values - The array of values, which is a borrowed array and should not be freed
4323 
4324   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4325 
4326   Fortran Notes:
4327   Since it returns an array, this routine is only available in Fortran 90, and you must
4328   include petsc.h90 in your code.
4329 
4330   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4331 
4332   Level: intermediate
4333 
4334 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4335 @*/
4336 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4337 {
4338   PetscInt       size = 0;
4339   PetscErrorCode ierr;
4340 
4341   PetscFunctionBegin;
4342   /* Should work without recalculating size */
4343   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
4344   *values = NULL;
4345   PetscFunctionReturn(0);
4346 }
4347 
4348 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
4349 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
4350 
4351 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[])
4352 {
4353   PetscInt        cdof;   /* The number of constraints on this point */
4354   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4355   PetscScalar    *a;
4356   PetscInt        off, cind = 0, k;
4357   PetscErrorCode  ierr;
4358 
4359   PetscFunctionBegin;
4360   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4361   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4362   a    = &array[off];
4363   if (!cdof || setBC) {
4364     if (clperm) {
4365       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4366       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4367     } else {
4368       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4369       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4370     }
4371   } else {
4372     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4373     if (clperm) {
4374       if (perm) {for (k = 0; k < dof; ++k) {
4375           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4376           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4377         }
4378       } else {
4379         for (k = 0; k < dof; ++k) {
4380           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4381           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4382         }
4383       }
4384     } else {
4385       if (perm) {
4386         for (k = 0; k < dof; ++k) {
4387           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4388           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4389         }
4390       } else {
4391         for (k = 0; k < dof; ++k) {
4392           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4393           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4394         }
4395       }
4396     }
4397   }
4398   PetscFunctionReturn(0);
4399 }
4400 
4401 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[])
4402 {
4403   PetscInt        cdof;   /* The number of constraints on this point */
4404   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4405   PetscScalar    *a;
4406   PetscInt        off, cind = 0, k;
4407   PetscErrorCode  ierr;
4408 
4409   PetscFunctionBegin;
4410   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4411   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4412   a    = &array[off];
4413   if (cdof) {
4414     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4415     if (clperm) {
4416       if (perm) {
4417         for (k = 0; k < dof; ++k) {
4418           if ((cind < cdof) && (k == cdofs[cind])) {
4419             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4420             cind++;
4421           }
4422         }
4423       } else {
4424         for (k = 0; k < dof; ++k) {
4425           if ((cind < cdof) && (k == cdofs[cind])) {
4426             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4427             cind++;
4428           }
4429         }
4430       }
4431     } else {
4432       if (perm) {
4433         for (k = 0; k < dof; ++k) {
4434           if ((cind < cdof) && (k == cdofs[cind])) {
4435             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4436             cind++;
4437           }
4438         }
4439       } else {
4440         for (k = 0; k < dof; ++k) {
4441           if ((cind < cdof) && (k == cdofs[cind])) {
4442             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4443             cind++;
4444           }
4445         }
4446       }
4447     }
4448   }
4449   PetscFunctionReturn(0);
4450 }
4451 
4452 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[])
4453 {
4454   PetscScalar    *a;
4455   PetscInt        fdof, foff, fcdof, foffset = *offset;
4456   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4457   PetscInt        cind = 0, b;
4458   PetscErrorCode  ierr;
4459 
4460   PetscFunctionBegin;
4461   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4462   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4463   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4464   a    = &array[foff];
4465   if (!fcdof || setBC) {
4466     if (clperm) {
4467       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4468       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4469     } else {
4470       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4471       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4472     }
4473   } else {
4474     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4475     if (clperm) {
4476       if (perm) {
4477         for (b = 0; b < fdof; b++) {
4478           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4479           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4480         }
4481       } else {
4482         for (b = 0; b < fdof; b++) {
4483           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4484           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4485         }
4486       }
4487     } else {
4488       if (perm) {
4489         for (b = 0; b < fdof; b++) {
4490           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4491           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4492         }
4493       } else {
4494         for (b = 0; b < fdof; b++) {
4495           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4496           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4497         }
4498       }
4499     }
4500   }
4501   *offset += fdof;
4502   PetscFunctionReturn(0);
4503 }
4504 
4505 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[])
4506 {
4507   PetscScalar    *a;
4508   PetscInt        fdof, foff, fcdof, foffset = *offset;
4509   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4510   PetscInt        cind = 0, ncind = 0, b;
4511   PetscBool       ncSet, fcSet;
4512   PetscErrorCode  ierr;
4513 
4514   PetscFunctionBegin;
4515   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4516   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4517   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4518   a    = &array[foff];
4519   if (fcdof) {
4520     /* We just override fcdof and fcdofs with Ncc and comps */
4521     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4522     if (clperm) {
4523       if (perm) {
4524         if (comps) {
4525           for (b = 0; b < fdof; b++) {
4526             ncSet = fcSet = PETSC_FALSE;
4527             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4528             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4529             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4530           }
4531         } else {
4532           for (b = 0; b < fdof; b++) {
4533             if ((cind < fcdof) && (b == fcdofs[cind])) {
4534               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4535               ++cind;
4536             }
4537           }
4538         }
4539       } else {
4540         if (comps) {
4541           for (b = 0; b < fdof; b++) {
4542             ncSet = fcSet = PETSC_FALSE;
4543             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4544             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4545             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4546           }
4547         } else {
4548           for (b = 0; b < fdof; b++) {
4549             if ((cind < fcdof) && (b == fcdofs[cind])) {
4550               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4551               ++cind;
4552             }
4553           }
4554         }
4555       }
4556     } else {
4557       if (perm) {
4558         if (comps) {
4559           for (b = 0; b < fdof; b++) {
4560             ncSet = fcSet = PETSC_FALSE;
4561             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4562             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4563             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4564           }
4565         } else {
4566           for (b = 0; b < fdof; b++) {
4567             if ((cind < fcdof) && (b == fcdofs[cind])) {
4568               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4569               ++cind;
4570             }
4571           }
4572         }
4573       } else {
4574         if (comps) {
4575           for (b = 0; b < fdof; b++) {
4576             ncSet = fcSet = PETSC_FALSE;
4577             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4578             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4579             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4580           }
4581         } else {
4582           for (b = 0; b < fdof; b++) {
4583             if ((cind < fcdof) && (b == fcdofs[cind])) {
4584               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4585               ++cind;
4586             }
4587           }
4588         }
4589       }
4590     }
4591   }
4592   *offset += fdof;
4593   PetscFunctionReturn(0);
4594 }
4595 
4596 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4597 {
4598   PetscScalar    *array;
4599   const PetscInt *cone, *coneO;
4600   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4601   PetscErrorCode  ierr;
4602 
4603   PetscFunctionBeginHot;
4604   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4605   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4606   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4607   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4608   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4609   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4610     const PetscInt cp = !p ? point : cone[p-1];
4611     const PetscInt o  = !p ? 0     : coneO[p-1];
4612 
4613     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4614     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4615     /* ADD_VALUES */
4616     {
4617       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4618       PetscScalar    *a;
4619       PetscInt        cdof, coff, cind = 0, k;
4620 
4621       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
4622       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
4623       a    = &array[coff];
4624       if (!cdof) {
4625         if (o >= 0) {
4626           for (k = 0; k < dof; ++k) {
4627             a[k] += values[off+k];
4628           }
4629         } else {
4630           for (k = 0; k < dof; ++k) {
4631             a[k] += values[off+dof-k-1];
4632           }
4633         }
4634       } else {
4635         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
4636         if (o >= 0) {
4637           for (k = 0; k < dof; ++k) {
4638             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4639             a[k] += values[off+k];
4640           }
4641         } else {
4642           for (k = 0; k < dof; ++k) {
4643             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4644             a[k] += values[off+dof-k-1];
4645           }
4646         }
4647       }
4648     }
4649   }
4650   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4651   PetscFunctionReturn(0);
4652 }
4653 
4654 /*@C
4655   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4656 
4657   Not collective
4658 
4659   Input Parameters:
4660 + dm - The DM
4661 . section - The section describing the layout in v, or NULL to use the default section
4662 . v - The local vector
4663 . point - The point in the DM
4664 . values - The array of values
4665 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4666          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
4667 
4668   Fortran Notes:
4669   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4670 
4671   Level: intermediate
4672 
4673 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4674 @*/
4675 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4676 {
4677   PetscSection    clSection;
4678   IS              clPoints;
4679   PetscScalar    *array;
4680   PetscInt       *points = NULL;
4681   const PetscInt *clp, *clperm;
4682   PetscInt        depth, numFields, numPoints, p;
4683   PetscErrorCode  ierr;
4684 
4685   PetscFunctionBeginHot;
4686   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4687   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
4688   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4689   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4690   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4691   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4692   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4693     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
4694     PetscFunctionReturn(0);
4695   }
4696   /* Get points */
4697   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
4698   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4699   /* Get array */
4700   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4701   /* Get values */
4702   if (numFields > 0) {
4703     PetscInt offset = 0, f;
4704     for (f = 0; f < numFields; ++f) {
4705       const PetscInt    **perms = NULL;
4706       const PetscScalar **flips = NULL;
4707 
4708       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4709       switch (mode) {
4710       case INSERT_VALUES:
4711         for (p = 0; p < numPoints; p++) {
4712           const PetscInt    point = points[2*p];
4713           const PetscInt    *perm = perms ? perms[p] : NULL;
4714           const PetscScalar *flip = flips ? flips[p] : NULL;
4715           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4716         } break;
4717       case INSERT_ALL_VALUES:
4718         for (p = 0; p < numPoints; p++) {
4719           const PetscInt    point = points[2*p];
4720           const PetscInt    *perm = perms ? perms[p] : NULL;
4721           const PetscScalar *flip = flips ? flips[p] : NULL;
4722           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4723         } break;
4724       case INSERT_BC_VALUES:
4725         for (p = 0; p < numPoints; p++) {
4726           const PetscInt    point = points[2*p];
4727           const PetscInt    *perm = perms ? perms[p] : NULL;
4728           const PetscScalar *flip = flips ? flips[p] : NULL;
4729           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4730         } break;
4731       case ADD_VALUES:
4732         for (p = 0; p < numPoints; p++) {
4733           const PetscInt    point = points[2*p];
4734           const PetscInt    *perm = perms ? perms[p] : NULL;
4735           const PetscScalar *flip = flips ? flips[p] : NULL;
4736           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4737         } break;
4738       case ADD_ALL_VALUES:
4739         for (p = 0; p < numPoints; p++) {
4740           const PetscInt    point = points[2*p];
4741           const PetscInt    *perm = perms ? perms[p] : NULL;
4742           const PetscScalar *flip = flips ? flips[p] : NULL;
4743           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4744         } break;
4745       case ADD_BC_VALUES:
4746         for (p = 0; p < numPoints; p++) {
4747           const PetscInt    point = points[2*p];
4748           const PetscInt    *perm = perms ? perms[p] : NULL;
4749           const PetscScalar *flip = flips ? flips[p] : NULL;
4750           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4751         } break;
4752       default:
4753         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4754       }
4755       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4756     }
4757   } else {
4758     PetscInt dof, off;
4759     const PetscInt    **perms = NULL;
4760     const PetscScalar **flips = NULL;
4761 
4762     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4763     switch (mode) {
4764     case INSERT_VALUES:
4765       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4766         const PetscInt    point = points[2*p];
4767         const PetscInt    *perm = perms ? perms[p] : NULL;
4768         const PetscScalar *flip = flips ? flips[p] : NULL;
4769         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4770         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4771       } break;
4772     case INSERT_ALL_VALUES:
4773       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4774         const PetscInt    point = points[2*p];
4775         const PetscInt    *perm = perms ? perms[p] : NULL;
4776         const PetscScalar *flip = flips ? flips[p] : NULL;
4777         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4778         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4779       } break;
4780     case INSERT_BC_VALUES:
4781       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4782         const PetscInt    point = points[2*p];
4783         const PetscInt    *perm = perms ? perms[p] : NULL;
4784         const PetscScalar *flip = flips ? flips[p] : NULL;
4785         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4786         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4787       } break;
4788     case ADD_VALUES:
4789       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4790         const PetscInt    point = points[2*p];
4791         const PetscInt    *perm = perms ? perms[p] : NULL;
4792         const PetscScalar *flip = flips ? flips[p] : NULL;
4793         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4794         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4795       } break;
4796     case ADD_ALL_VALUES:
4797       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4798         const PetscInt    point = points[2*p];
4799         const PetscInt    *perm = perms ? perms[p] : NULL;
4800         const PetscScalar *flip = flips ? flips[p] : NULL;
4801         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4802         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4803       } break;
4804     case ADD_BC_VALUES:
4805       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4806         const PetscInt    point = points[2*p];
4807         const PetscInt    *perm = perms ? perms[p] : NULL;
4808         const PetscScalar *flip = flips ? flips[p] : NULL;
4809         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4810         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4811       } break;
4812     default:
4813       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4814     }
4815     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4816   }
4817   /* Cleanup points */
4818   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4819   /* Cleanup array */
4820   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4821   PetscFunctionReturn(0);
4822 }
4823 
4824 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4825 {
4826   PetscSection      clSection;
4827   IS                clPoints;
4828   PetscScalar       *array;
4829   PetscInt          *points = NULL;
4830   const PetscInt    *clp, *clperm;
4831   PetscInt          numFields, numPoints, p;
4832   PetscInt          offset = 0, f;
4833   PetscErrorCode    ierr;
4834 
4835   PetscFunctionBeginHot;
4836   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4837   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
4838   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4839   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4840   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4841   /* Get points */
4842   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
4843   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4844   /* Get array */
4845   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4846   /* Get values */
4847   for (f = 0; f < numFields; ++f) {
4848     const PetscInt    **perms = NULL;
4849     const PetscScalar **flips = NULL;
4850 
4851     if (!fieldActive[f]) {
4852       for (p = 0; p < numPoints*2; p += 2) {
4853         PetscInt fdof;
4854         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4855         offset += fdof;
4856       }
4857       continue;
4858     }
4859     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4860     switch (mode) {
4861     case INSERT_VALUES:
4862       for (p = 0; p < numPoints; p++) {
4863         const PetscInt    point = points[2*p];
4864         const PetscInt    *perm = perms ? perms[p] : NULL;
4865         const PetscScalar *flip = flips ? flips[p] : NULL;
4866         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4867       } break;
4868     case INSERT_ALL_VALUES:
4869       for (p = 0; p < numPoints; p++) {
4870         const PetscInt    point = points[2*p];
4871         const PetscInt    *perm = perms ? perms[p] : NULL;
4872         const PetscScalar *flip = flips ? flips[p] : NULL;
4873         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4874         } break;
4875     case INSERT_BC_VALUES:
4876       for (p = 0; p < numPoints; p++) {
4877         const PetscInt    point = points[2*p];
4878         const PetscInt    *perm = perms ? perms[p] : NULL;
4879         const PetscScalar *flip = flips ? flips[p] : NULL;
4880         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4881       } break;
4882     case ADD_VALUES:
4883       for (p = 0; p < numPoints; p++) {
4884         const PetscInt    point = points[2*p];
4885         const PetscInt    *perm = perms ? perms[p] : NULL;
4886         const PetscScalar *flip = flips ? flips[p] : NULL;
4887         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4888       } break;
4889     case ADD_ALL_VALUES:
4890       for (p = 0; p < numPoints; p++) {
4891         const PetscInt    point = points[2*p];
4892         const PetscInt    *perm = perms ? perms[p] : NULL;
4893         const PetscScalar *flip = flips ? flips[p] : NULL;
4894         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4895       } break;
4896     default:
4897       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4898     }
4899     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4900   }
4901   /* Cleanup points */
4902   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4903   /* Cleanup array */
4904   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4905   PetscFunctionReturn(0);
4906 }
4907 
4908 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4909 {
4910   PetscMPIInt    rank;
4911   PetscInt       i, j;
4912   PetscErrorCode ierr;
4913 
4914   PetscFunctionBegin;
4915   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
4916   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
4917   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
4918   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
4919   numCIndices = numCIndices ? numCIndices : numRIndices;
4920   for (i = 0; i < numRIndices; i++) {
4921     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
4922     for (j = 0; j < numCIndices; j++) {
4923 #if defined(PETSC_USE_COMPLEX)
4924       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
4925 #else
4926       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
4927 #endif
4928     }
4929     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
4930   }
4931   PetscFunctionReturn(0);
4932 }
4933 
4934 /* . off - The global offset of this point */
4935 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4936 {
4937   PetscInt        dof;    /* The number of unknowns on this point */
4938   PetscInt        cdof;   /* The number of constraints on this point */
4939   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4940   PetscInt        cind = 0, k;
4941   PetscErrorCode  ierr;
4942 
4943   PetscFunctionBegin;
4944   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4945   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4946   if (!cdof || setBC) {
4947     if (perm) {
4948       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4949     } else {
4950       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4951     }
4952   } else {
4953     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4954     if (perm) {
4955       for (k = 0; k < dof; ++k) {
4956         if ((cind < cdof) && (k == cdofs[cind])) {
4957           /* Insert check for returning constrained indices */
4958           indices[*loff+perm[k]] = -(off+k+1);
4959           ++cind;
4960         } else {
4961           indices[*loff+perm[k]] = off+k-cind;
4962         }
4963       }
4964     } else {
4965       for (k = 0; k < dof; ++k) {
4966         if ((cind < cdof) && (k == cdofs[cind])) {
4967           /* Insert check for returning constrained indices */
4968           indices[*loff+k] = -(off+k+1);
4969           ++cind;
4970         } else {
4971           indices[*loff+k] = off+k-cind;
4972         }
4973       }
4974     }
4975   }
4976   *loff += dof;
4977   PetscFunctionReturn(0);
4978 }
4979 
4980 /*
4981   This version only believes the point offset from the globalSection
4982 
4983  . off - The global offset of this point
4984 */
4985 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4986 {
4987   PetscInt       numFields, foff, f;
4988   PetscErrorCode ierr;
4989 
4990   PetscFunctionBegin;
4991   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4992   for (f = 0, foff = 0; f < numFields; ++f) {
4993     PetscInt        fdof, cfdof;
4994     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4995     PetscInt        cind = 0, b;
4996     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4997 
4998     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4999     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5000     if (!cfdof || setBC) {
5001       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
5002       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
5003     } else {
5004       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5005       if (perm) {
5006         for (b = 0; b < fdof; b++) {
5007           if ((cind < cfdof) && (b == fcdofs[cind])) {
5008             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
5009             ++cind;
5010           } else {
5011             indices[foffs[f]+perm[b]] = off+foff+b-cind;
5012           }
5013         }
5014       } else {
5015         for (b = 0; b < fdof; b++) {
5016           if ((cind < cfdof) && (b == fcdofs[cind])) {
5017             indices[foffs[f]+b] = -(off+foff+b+1);
5018             ++cind;
5019           } else {
5020             indices[foffs[f]+b] = off+foff+b-cind;
5021           }
5022         }
5023       }
5024     }
5025     foff     += (setBC ? fdof : (fdof - cfdof));
5026     foffs[f] += fdof;
5027   }
5028   PetscFunctionReturn(0);
5029 }
5030 
5031 /*
5032   This version believes the globalSection offsets for each field, rather than just the point offset
5033 
5034  . foffs - The offset into 'indices' for each field, since it is segregated by field
5035 */
5036 PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
5037 {
5038   PetscInt       numFields, foff, f;
5039   PetscErrorCode ierr;
5040 
5041   PetscFunctionBegin;
5042   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5043   for (f = 0; f < numFields; ++f) {
5044     PetscInt        fdof, cfdof;
5045     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5046     PetscInt        cind = 0, b;
5047     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5048 
5049     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5050     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5051     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
5052     if (!cfdof || setBC) {
5053       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = foff+b;}}
5054       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = foff+b;}}
5055     } else {
5056       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5057       if (perm) {
5058         for (b = 0; b < fdof; b++) {
5059           if ((cind < cfdof) && (b == fcdofs[cind])) {
5060             indices[foffs[f]+perm[b]] = -(foff+b+1);
5061             ++cind;
5062           } else {
5063             indices[foffs[f]+perm[b]] = foff+b-cind;
5064           }
5065         }
5066       } else {
5067         for (b = 0; b < fdof; b++) {
5068           if ((cind < cfdof) && (b == fcdofs[cind])) {
5069             indices[foffs[f]+b] = -(foff+b+1);
5070             ++cind;
5071           } else {
5072             indices[foffs[f]+b] = foff+b-cind;
5073           }
5074         }
5075       }
5076     }
5077     foffs[f] += fdof;
5078   }
5079   PetscFunctionReturn(0);
5080 }
5081 
5082 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)
5083 {
5084   Mat             cMat;
5085   PetscSection    aSec, cSec;
5086   IS              aIS;
5087   PetscInt        aStart = -1, aEnd = -1;
5088   const PetscInt  *anchors;
5089   PetscInt        numFields, f, p, q, newP = 0;
5090   PetscInt        newNumPoints = 0, newNumIndices = 0;
5091   PetscInt        *newPoints, *indices, *newIndices;
5092   PetscInt        maxAnchor, maxDof;
5093   PetscInt        newOffsets[32];
5094   PetscInt        *pointMatOffsets[32];
5095   PetscInt        *newPointOffsets[32];
5096   PetscScalar     *pointMat[32];
5097   PetscScalar     *newValues=NULL,*tmpValues;
5098   PetscBool       anyConstrained = PETSC_FALSE;
5099   PetscErrorCode  ierr;
5100 
5101   PetscFunctionBegin;
5102   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5103   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5104   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5105 
5106   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
5107   /* if there are point-to-point constraints */
5108   if (aSec) {
5109     ierr = PetscMemzero(newOffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5110     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
5111     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
5112     /* figure out how many points are going to be in the new element matrix
5113      * (we allow double counting, because it's all just going to be summed
5114      * into the global matrix anyway) */
5115     for (p = 0; p < 2*numPoints; p+=2) {
5116       PetscInt b    = points[p];
5117       PetscInt bDof = 0, bSecDof;
5118 
5119       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5120       if (!bSecDof) {
5121         continue;
5122       }
5123       if (b >= aStart && b < aEnd) {
5124         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
5125       }
5126       if (bDof) {
5127         /* this point is constrained */
5128         /* it is going to be replaced by its anchors */
5129         PetscInt bOff, q;
5130 
5131         anyConstrained = PETSC_TRUE;
5132         newNumPoints  += bDof;
5133         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
5134         for (q = 0; q < bDof; q++) {
5135           PetscInt a = anchors[bOff + q];
5136           PetscInt aDof;
5137 
5138           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5139           newNumIndices += aDof;
5140           for (f = 0; f < numFields; ++f) {
5141             PetscInt fDof;
5142 
5143             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
5144             newOffsets[f+1] += fDof;
5145           }
5146         }
5147       }
5148       else {
5149         /* this point is not constrained */
5150         newNumPoints++;
5151         newNumIndices += bSecDof;
5152         for (f = 0; f < numFields; ++f) {
5153           PetscInt fDof;
5154 
5155           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5156           newOffsets[f+1] += fDof;
5157         }
5158       }
5159     }
5160   }
5161   if (!anyConstrained) {
5162     if (outNumPoints)  *outNumPoints  = 0;
5163     if (outNumIndices) *outNumIndices = 0;
5164     if (outPoints)     *outPoints     = NULL;
5165     if (outValues)     *outValues     = NULL;
5166     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
5167     PetscFunctionReturn(0);
5168   }
5169 
5170   if (outNumPoints)  *outNumPoints  = newNumPoints;
5171   if (outNumIndices) *outNumIndices = newNumIndices;
5172 
5173   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
5174 
5175   if (!outPoints && !outValues) {
5176     if (offsets) {
5177       for (f = 0; f <= numFields; f++) {
5178         offsets[f] = newOffsets[f];
5179       }
5180     }
5181     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
5182     PetscFunctionReturn(0);
5183   }
5184 
5185   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
5186 
5187   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
5188 
5189   /* workspaces */
5190   if (numFields) {
5191     for (f = 0; f < numFields; f++) {
5192       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
5193       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
5194     }
5195   }
5196   else {
5197     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
5198     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
5199   }
5200 
5201   /* get workspaces for the point-to-point matrices */
5202   if (numFields) {
5203     PetscInt totalOffset, totalMatOffset;
5204 
5205     for (p = 0; p < numPoints; p++) {
5206       PetscInt b    = points[2*p];
5207       PetscInt bDof = 0, bSecDof;
5208 
5209       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5210       if (!bSecDof) {
5211         for (f = 0; f < numFields; f++) {
5212           newPointOffsets[f][p + 1] = 0;
5213           pointMatOffsets[f][p + 1] = 0;
5214         }
5215         continue;
5216       }
5217       if (b >= aStart && b < aEnd) {
5218         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5219       }
5220       if (bDof) {
5221         for (f = 0; f < numFields; f++) {
5222           PetscInt fDof, q, bOff, allFDof = 0;
5223 
5224           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5225           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5226           for (q = 0; q < bDof; q++) {
5227             PetscInt a = anchors[bOff + q];
5228             PetscInt aFDof;
5229 
5230             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
5231             allFDof += aFDof;
5232           }
5233           newPointOffsets[f][p+1] = allFDof;
5234           pointMatOffsets[f][p+1] = fDof * allFDof;
5235         }
5236       }
5237       else {
5238         for (f = 0; f < numFields; f++) {
5239           PetscInt fDof;
5240 
5241           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5242           newPointOffsets[f][p+1] = fDof;
5243           pointMatOffsets[f][p+1] = 0;
5244         }
5245       }
5246     }
5247     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5248       newPointOffsets[f][0] = totalOffset;
5249       pointMatOffsets[f][0] = totalMatOffset;
5250       for (p = 0; p < numPoints; p++) {
5251         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5252         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5253       }
5254       totalOffset    = newPointOffsets[f][numPoints];
5255       totalMatOffset = pointMatOffsets[f][numPoints];
5256       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
5257     }
5258   }
5259   else {
5260     for (p = 0; p < numPoints; p++) {
5261       PetscInt b    = points[2*p];
5262       PetscInt bDof = 0, bSecDof;
5263 
5264       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5265       if (!bSecDof) {
5266         newPointOffsets[0][p + 1] = 0;
5267         pointMatOffsets[0][p + 1] = 0;
5268         continue;
5269       }
5270       if (b >= aStart && b < aEnd) {
5271         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5272       }
5273       if (bDof) {
5274         PetscInt bOff, q, allDof = 0;
5275 
5276         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5277         for (q = 0; q < bDof; q++) {
5278           PetscInt a = anchors[bOff + q], aDof;
5279 
5280           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
5281           allDof += aDof;
5282         }
5283         newPointOffsets[0][p+1] = allDof;
5284         pointMatOffsets[0][p+1] = bSecDof * allDof;
5285       }
5286       else {
5287         newPointOffsets[0][p+1] = bSecDof;
5288         pointMatOffsets[0][p+1] = 0;
5289       }
5290     }
5291     newPointOffsets[0][0] = 0;
5292     pointMatOffsets[0][0] = 0;
5293     for (p = 0; p < numPoints; p++) {
5294       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5295       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5296     }
5297     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
5298   }
5299 
5300   /* output arrays */
5301   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5302 
5303   /* get the point-to-point matrices; construct newPoints */
5304   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
5305   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
5306   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
5307   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
5308   if (numFields) {
5309     for (p = 0, newP = 0; p < numPoints; p++) {
5310       PetscInt b    = points[2*p];
5311       PetscInt o    = points[2*p+1];
5312       PetscInt bDof = 0, bSecDof;
5313 
5314       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
5315       if (!bSecDof) {
5316         continue;
5317       }
5318       if (b >= aStart && b < aEnd) {
5319         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5320       }
5321       if (bDof) {
5322         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5323 
5324         fStart[0] = 0;
5325         fEnd[0]   = 0;
5326         for (f = 0; f < numFields; f++) {
5327           PetscInt fDof;
5328 
5329           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
5330           fStart[f+1] = fStart[f] + fDof;
5331           fEnd[f+1]   = fStart[f+1];
5332         }
5333         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
5334         ierr = DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);CHKERRQ(ierr);
5335 
5336         fAnchorStart[0] = 0;
5337         fAnchorEnd[0]   = 0;
5338         for (f = 0; f < numFields; f++) {
5339           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5340 
5341           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5342           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5343         }
5344         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5345         for (q = 0; q < bDof; q++) {
5346           PetscInt a = anchors[bOff + q], aOff;
5347 
5348           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5349           newPoints[2*(newP + q)]     = a;
5350           newPoints[2*(newP + q) + 1] = 0;
5351           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
5352           ierr = DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);CHKERRQ(ierr);
5353         }
5354         newP += bDof;
5355 
5356         if (outValues) {
5357           /* get the point-to-point submatrix */
5358           for (f = 0; f < numFields; f++) {
5359             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
5360           }
5361         }
5362       }
5363       else {
5364         newPoints[2 * newP]     = b;
5365         newPoints[2 * newP + 1] = o;
5366         newP++;
5367       }
5368     }
5369   } else {
5370     for (p = 0; p < numPoints; p++) {
5371       PetscInt b    = points[2*p];
5372       PetscInt o    = points[2*p+1];
5373       PetscInt bDof = 0, bSecDof;
5374 
5375       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
5376       if (!bSecDof) {
5377         continue;
5378       }
5379       if (b >= aStart && b < aEnd) {
5380         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5381       }
5382       if (bDof) {
5383         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5384 
5385         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
5386         ierr = DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);CHKERRQ(ierr);
5387 
5388         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
5389         for (q = 0; q < bDof; q++) {
5390           PetscInt a = anchors[bOff + q], aOff;
5391 
5392           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5393 
5394           newPoints[2*(newP + q)]     = a;
5395           newPoints[2*(newP + q) + 1] = 0;
5396           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
5397           ierr = DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);CHKERRQ(ierr);
5398         }
5399         newP += bDof;
5400 
5401         /* get the point-to-point submatrix */
5402         if (outValues) {
5403           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
5404         }
5405       }
5406       else {
5407         newPoints[2 * newP]     = b;
5408         newPoints[2 * newP + 1] = o;
5409         newP++;
5410       }
5411     }
5412   }
5413 
5414   if (outValues) {
5415     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
5416     ierr = PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));CHKERRQ(ierr);
5417     /* multiply constraints on the right */
5418     if (numFields) {
5419       for (f = 0; f < numFields; f++) {
5420         PetscInt oldOff = offsets[f];
5421 
5422         for (p = 0; p < numPoints; p++) {
5423           PetscInt cStart = newPointOffsets[f][p];
5424           PetscInt b      = points[2 * p];
5425           PetscInt c, r, k;
5426           PetscInt dof;
5427 
5428           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5429           if (!dof) {
5430             continue;
5431           }
5432           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5433             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5434             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5435 
5436             for (r = 0; r < numIndices; r++) {
5437               for (c = 0; c < nCols; c++) {
5438                 for (k = 0; k < dof; k++) {
5439                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5440                 }
5441               }
5442             }
5443           }
5444           else {
5445             /* copy this column as is */
5446             for (r = 0; r < numIndices; r++) {
5447               for (c = 0; c < dof; c++) {
5448                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5449               }
5450             }
5451           }
5452           oldOff += dof;
5453         }
5454       }
5455     }
5456     else {
5457       PetscInt oldOff = 0;
5458       for (p = 0; p < numPoints; p++) {
5459         PetscInt cStart = newPointOffsets[0][p];
5460         PetscInt b      = points[2 * p];
5461         PetscInt c, r, k;
5462         PetscInt dof;
5463 
5464         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5465         if (!dof) {
5466           continue;
5467         }
5468         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5469           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5470           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5471 
5472           for (r = 0; r < numIndices; r++) {
5473             for (c = 0; c < nCols; c++) {
5474               for (k = 0; k < dof; k++) {
5475                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5476               }
5477             }
5478           }
5479         }
5480         else {
5481           /* copy this column as is */
5482           for (r = 0; r < numIndices; r++) {
5483             for (c = 0; c < dof; c++) {
5484               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5485             }
5486           }
5487         }
5488         oldOff += dof;
5489       }
5490     }
5491 
5492     if (multiplyLeft) {
5493       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
5494       ierr = PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));CHKERRQ(ierr);
5495       /* multiply constraints transpose on the left */
5496       if (numFields) {
5497         for (f = 0; f < numFields; f++) {
5498           PetscInt oldOff = offsets[f];
5499 
5500           for (p = 0; p < numPoints; p++) {
5501             PetscInt rStart = newPointOffsets[f][p];
5502             PetscInt b      = points[2 * p];
5503             PetscInt c, r, k;
5504             PetscInt dof;
5505 
5506             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5507             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5508               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
5509               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5510 
5511               for (r = 0; r < nRows; r++) {
5512                 for (c = 0; c < newNumIndices; c++) {
5513                   for (k = 0; k < dof; k++) {
5514                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5515                   }
5516                 }
5517               }
5518             }
5519             else {
5520               /* copy this row as is */
5521               for (r = 0; r < dof; r++) {
5522                 for (c = 0; c < newNumIndices; c++) {
5523                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5524                 }
5525               }
5526             }
5527             oldOff += dof;
5528           }
5529         }
5530       }
5531       else {
5532         PetscInt oldOff = 0;
5533 
5534         for (p = 0; p < numPoints; p++) {
5535           PetscInt rStart = newPointOffsets[0][p];
5536           PetscInt b      = points[2 * p];
5537           PetscInt c, r, k;
5538           PetscInt dof;
5539 
5540           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5541           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5542             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
5543             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5544 
5545             for (r = 0; r < nRows; r++) {
5546               for (c = 0; c < newNumIndices; c++) {
5547                 for (k = 0; k < dof; k++) {
5548                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5549                 }
5550               }
5551             }
5552           }
5553           else {
5554             /* copy this row as is */
5555             for (r = 0; r < dof; r++) {
5556               for (c = 0; c < newNumIndices; c++) {
5557                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5558               }
5559             }
5560           }
5561           oldOff += dof;
5562         }
5563       }
5564 
5565       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
5566     }
5567     else {
5568       newValues = tmpValues;
5569     }
5570   }
5571 
5572   /* clean up */
5573   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
5574   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
5575 
5576   if (numFields) {
5577     for (f = 0; f < numFields; f++) {
5578       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
5579       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
5580       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
5581     }
5582   }
5583   else {
5584     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
5585     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
5586     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
5587   }
5588   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
5589 
5590   /* output */
5591   if (outPoints) {
5592     *outPoints = newPoints;
5593   }
5594   else {
5595     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5596   }
5597   if (outValues) {
5598     *outValues = newValues;
5599   }
5600   for (f = 0; f <= numFields; f++) {
5601     offsets[f] = newOffsets[f];
5602   }
5603   PetscFunctionReturn(0);
5604 }
5605 
5606 /*@C
5607   DMPlexGetClosureIndices - Get the global indices in a vector v for all points in the closure of the given point
5608 
5609   Not collective
5610 
5611   Input Parameters:
5612 + dm - The DM
5613 . section - The section describing the layout in v, or NULL to use the default section
5614 . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5615 - point - The mesh point
5616 
5617   Output parameters:
5618 + numIndices - The number of indices
5619 . indices - The indices
5620 - outOffsets - Field offset if not NULL
5621 
5622   Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5623 
5624   Level: advanced
5625 
5626 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5627 @*/
5628 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5629 {
5630   PetscSection    clSection;
5631   IS              clPoints;
5632   const PetscInt *clp;
5633   const PetscInt  **perms[32] = {NULL};
5634   PetscInt       *points = NULL, *pointsNew;
5635   PetscInt        numPoints, numPointsNew;
5636   PetscInt        offsets[32];
5637   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5638   PetscErrorCode  ierr;
5639 
5640   PetscFunctionBegin;
5641   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5642   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5643   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5644   if (numIndices) PetscValidPointer(numIndices, 4);
5645   PetscValidPointer(indices, 5);
5646   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
5647   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5648   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5649   /* Get points in closure */
5650   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5651   /* Get number of indices and indices per field */
5652   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5653     PetscInt dof, fdof;
5654 
5655     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5656     for (f = 0; f < Nf; ++f) {
5657       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5658       offsets[f+1] += fdof;
5659     }
5660     Nind += dof;
5661   }
5662   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5663   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5664   if (!Nf) offsets[1] = Nind;
5665   /* Get dual space symmetries */
5666   for (f = 0; f < PetscMax(1,Nf); f++) {
5667     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5668     else    {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5669   }
5670   /* Correct for hanging node constraints */
5671   {
5672     ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
5673     if (numPointsNew) {
5674       for (f = 0; f < PetscMax(1,Nf); f++) {
5675         if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5676         else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5677       }
5678       for (f = 0; f < PetscMax(1,Nf); f++) {
5679         if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
5680         else    {ierr = PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
5681       }
5682       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5683       numPoints = numPointsNew;
5684       Nind      = NindNew;
5685       points    = pointsNew;
5686     }
5687   }
5688   /* Calculate indices */
5689   ierr = DMGetWorkArray(dm, Nind, MPIU_INT, indices);CHKERRQ(ierr);
5690   if (Nf) {
5691     if (outOffsets) {
5692       PetscInt f;
5693 
5694       for (f = 0; f <= Nf; f++) {
5695         outOffsets[f] = offsets[f];
5696       }
5697     }
5698     for (p = 0; p < numPoints; p++) {
5699       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5700       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5701     }
5702   } else {
5703     for (p = 0, off = 0; p < numPoints; p++) {
5704       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5705 
5706       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5707       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5708     }
5709   }
5710   /* Cleanup points */
5711   for (f = 0; f < PetscMax(1,Nf); f++) {
5712     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5713     else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5714   }
5715   if (numPointsNew) {
5716     ierr = DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);CHKERRQ(ierr);
5717   } else {
5718     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5719   }
5720   if (numIndices) *numIndices = Nind;
5721   PetscFunctionReturn(0);
5722 }
5723 
5724 /*@C
5725   DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5726 
5727   Not collective
5728 
5729   Input Parameters:
5730 + dm - The DM
5731 . section - The section describing the layout in v, or NULL to use the default section
5732 . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5733 . point - The mesh point
5734 . numIndices - The number of indices
5735 . indices - The indices
5736 - outOffsets - Field offset if not NULL
5737 
5738   Level: advanced
5739 
5740 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5741 @*/
5742 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5743 {
5744   PetscErrorCode ierr;
5745 
5746   PetscFunctionBegin;
5747   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5748   PetscValidPointer(indices, 5);
5749   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
5750   PetscFunctionReturn(0);
5751 }
5752 
5753 /*@C
5754   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5755 
5756   Not collective
5757 
5758   Input Parameters:
5759 + dm - The DM
5760 . section - The section describing the layout in v, or NULL to use the default section
5761 . globalSection - The section describing the layout in v, or NULL to use the default global section
5762 . A - The matrix
5763 . point - The point in the DM
5764 . values - The array of values
5765 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5766 
5767   Fortran Notes:
5768   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5769 
5770   Level: intermediate
5771 
5772 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5773 @*/
5774 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5775 {
5776   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5777   PetscSection        clSection;
5778   IS                  clPoints;
5779   PetscInt           *points = NULL, *newPoints;
5780   const PetscInt     *clp;
5781   PetscInt           *indices;
5782   PetscInt            offsets[32];
5783   const PetscInt    **perms[32] = {NULL};
5784   const PetscScalar **flips[32] = {NULL};
5785   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5786   PetscScalar        *valCopy = NULL;
5787   PetscScalar        *newValues;
5788   PetscErrorCode      ierr;
5789 
5790   PetscFunctionBegin;
5791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5792   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
5793   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5794   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
5795   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5796   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
5797   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5798   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5799   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5800   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5801   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5802     PetscInt fdof;
5803 
5804     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5805     for (f = 0; f < numFields; ++f) {
5806       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5807       offsets[f+1] += fdof;
5808     }
5809     numIndices += dof;
5810   }
5811   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5812 
5813   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5814   /* Get symmetries */
5815   for (f = 0; f < PetscMax(1,numFields); f++) {
5816     if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5817     else           {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5818     if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5819       PetscInt foffset = offsets[f];
5820 
5821       for (p = 0; p < numPoints; p++) {
5822         PetscInt point          = points[2*p], fdof;
5823         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5824 
5825         if (!numFields) {
5826           ierr = PetscSectionGetDof(section,point,&fdof);CHKERRQ(ierr);
5827         } else {
5828           ierr = PetscSectionGetFieldDof(section,point,f,&fdof);CHKERRQ(ierr);
5829         }
5830         if (flip) {
5831           PetscInt i, j, k;
5832 
5833           if (!valCopy) {
5834             ierr = DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
5835             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5836             values = valCopy;
5837           }
5838           for (i = 0; i < fdof; i++) {
5839             PetscScalar fval = flip[i];
5840 
5841             for (k = 0; k < numIndices; k++) {
5842               valCopy[numIndices * (foffset + i) + k] *= fval;
5843               valCopy[numIndices * k + (foffset + i)] *= fval;
5844             }
5845           }
5846         }
5847         foffset += fdof;
5848       }
5849     }
5850   }
5851   ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr);
5852   if (newNumPoints) {
5853     if (valCopy) {
5854       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
5855     }
5856     for (f = 0; f < PetscMax(1,numFields); f++) {
5857       if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5858       else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5859     }
5860     for (f = 0; f < PetscMax(1,numFields); f++) {
5861       if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
5862       else           {ierr = PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
5863     }
5864     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5865     numPoints  = newNumPoints;
5866     numIndices = newNumIndices;
5867     points     = newPoints;
5868     values     = newValues;
5869   }
5870   ierr = DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr);
5871   if (numFields) {
5872     PetscBool useFieldOffsets;
5873 
5874     ierr = PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);CHKERRQ(ierr);
5875     if (useFieldOffsets) {
5876       for (p = 0; p < numPoints; p++) {
5877         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, indices);
5878       }
5879     } else {
5880       for (p = 0; p < numPoints; p++) {
5881         ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5882         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5883       }
5884     }
5885   } else {
5886     for (p = 0, off = 0; p < numPoints; p++) {
5887       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5888       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5889       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5890     }
5891   }
5892   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
5893   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5894   if (mesh->printFEM > 1) {
5895     PetscInt i;
5896     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
5897     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
5898     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5899   }
5900   if (ierr) {
5901     PetscMPIInt    rank;
5902     PetscErrorCode ierr2;
5903 
5904     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5905     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5906     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5907     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5908     CHKERRQ(ierr);
5909   }
5910   for (f = 0; f < PetscMax(1,numFields); f++) {
5911     if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5912     else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5913   }
5914   if (newNumPoints) {
5915     ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
5916     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5917   }
5918   else {
5919     if (valCopy) {
5920       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
5921     }
5922     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5923   }
5924   ierr = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr);
5925   PetscFunctionReturn(0);
5926 }
5927 
5928 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5929 {
5930   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5931   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5932   PetscInt       *cpoints = NULL;
5933   PetscInt       *findices, *cindices;
5934   PetscInt        foffsets[32], coffsets[32];
5935   CellRefiner     cellRefiner;
5936   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5937   PetscErrorCode  ierr;
5938 
5939   PetscFunctionBegin;
5940   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
5941   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
5942   if (!fsection) {ierr = DMGetSection(dmf, &fsection);CHKERRQ(ierr);}
5943   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
5944   if (!csection) {ierr = DMGetSection(dmc, &csection);CHKERRQ(ierr);}
5945   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
5946   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
5947   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
5948   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
5949   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
5950   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
5951   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
5952   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5953   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5954   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5955   /* Column indices */
5956   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5957   maxFPoints = numCPoints;
5958   /* Compress out points not in the section */
5959   /*   TODO: Squeeze out points with 0 dof as well */
5960   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
5961   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5962     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5963       cpoints[q*2]   = cpoints[p];
5964       cpoints[q*2+1] = cpoints[p+1];
5965       ++q;
5966     }
5967   }
5968   numCPoints = q;
5969   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5970     PetscInt fdof;
5971 
5972     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
5973     if (!dof) continue;
5974     for (f = 0; f < numFields; ++f) {
5975       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
5976       coffsets[f+1] += fdof;
5977     }
5978     numCIndices += dof;
5979   }
5980   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5981   /* Row indices */
5982   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
5983   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
5984   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
5985   for (r = 0, q = 0; r < numSubcells; ++r) {
5986     /* TODO Map from coarse to fine cells */
5987     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5988     /* Compress out points not in the section */
5989     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
5990     for (p = 0; p < numFPoints*2; p += 2) {
5991       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5992         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
5993         if (!dof) continue;
5994         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5995         if (s < q) continue;
5996         ftotpoints[q*2]   = fpoints[p];
5997         ftotpoints[q*2+1] = fpoints[p+1];
5998         ++q;
5999       }
6000     }
6001     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6002   }
6003   numFPoints = q;
6004   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6005     PetscInt fdof;
6006 
6007     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
6008     if (!dof) continue;
6009     for (f = 0; f < numFields; ++f) {
6010       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
6011       foffsets[f+1] += fdof;
6012     }
6013     numFIndices += dof;
6014   }
6015   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6016 
6017   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6018   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6019   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
6020   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
6021   if (numFields) {
6022     const PetscInt **permsF[32] = {NULL};
6023     const PetscInt **permsC[32] = {NULL};
6024 
6025     for (f = 0; f < numFields; f++) {
6026       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6027       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6028     }
6029     for (p = 0; p < numFPoints; p++) {
6030       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6031       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
6032     }
6033     for (p = 0; p < numCPoints; p++) {
6034       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6035       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6036     }
6037     for (f = 0; f < numFields; f++) {
6038       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6039       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6040     }
6041   } else {
6042     const PetscInt **permsF = NULL;
6043     const PetscInt **permsC = NULL;
6044 
6045     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6046     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6047     for (p = 0, off = 0; p < numFPoints; p++) {
6048       const PetscInt *perm = permsF ? permsF[p] : NULL;
6049 
6050       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6051       ierr = DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);CHKERRQ(ierr);
6052     }
6053     for (p = 0, off = 0; p < numCPoints; p++) {
6054       const PetscInt *perm = permsC ? permsC[p] : NULL;
6055 
6056       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6057       ierr = DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);CHKERRQ(ierr);
6058     }
6059     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6060     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6061   }
6062   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
6063   /* TODO: flips */
6064   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6065   if (ierr) {
6066     PetscMPIInt    rank;
6067     PetscErrorCode ierr2;
6068 
6069     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6070     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6071     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6072     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6073     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6074     CHKERRQ(ierr);
6075   }
6076   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6077   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6078   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
6079   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
6080   PetscFunctionReturn(0);
6081 }
6082 
6083 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6084 {
6085   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6086   PetscInt      *cpoints = NULL;
6087   PetscInt       foffsets[32], coffsets[32];
6088   CellRefiner    cellRefiner;
6089   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6090   PetscErrorCode ierr;
6091 
6092   PetscFunctionBegin;
6093   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
6094   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
6095   if (!fsection) {ierr = DMGetSection(dmf, &fsection);CHKERRQ(ierr);}
6096   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
6097   if (!csection) {ierr = DMGetSection(dmc, &csection);CHKERRQ(ierr);}
6098   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
6099   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
6100   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
6101   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
6102   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
6103   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
6104   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6105   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6106   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6107   /* Column indices */
6108   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6109   maxFPoints = numCPoints;
6110   /* Compress out points not in the section */
6111   /*   TODO: Squeeze out points with 0 dof as well */
6112   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
6113   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6114     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6115       cpoints[q*2]   = cpoints[p];
6116       cpoints[q*2+1] = cpoints[p+1];
6117       ++q;
6118     }
6119   }
6120   numCPoints = q;
6121   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6122     PetscInt fdof;
6123 
6124     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
6125     if (!dof) continue;
6126     for (f = 0; f < numFields; ++f) {
6127       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
6128       coffsets[f+1] += fdof;
6129     }
6130     numCIndices += dof;
6131   }
6132   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6133   /* Row indices */
6134   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
6135   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
6136   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6137   for (r = 0, q = 0; r < numSubcells; ++r) {
6138     /* TODO Map from coarse to fine cells */
6139     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6140     /* Compress out points not in the section */
6141     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
6142     for (p = 0; p < numFPoints*2; p += 2) {
6143       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6144         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
6145         if (!dof) continue;
6146         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6147         if (s < q) continue;
6148         ftotpoints[q*2]   = fpoints[p];
6149         ftotpoints[q*2+1] = fpoints[p+1];
6150         ++q;
6151       }
6152     }
6153     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6154   }
6155   numFPoints = q;
6156   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6157     PetscInt fdof;
6158 
6159     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
6160     if (!dof) continue;
6161     for (f = 0; f < numFields; ++f) {
6162       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
6163       foffsets[f+1] += fdof;
6164     }
6165     numFIndices += dof;
6166   }
6167   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6168 
6169   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6170   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6171   if (numFields) {
6172     const PetscInt **permsF[32] = {NULL};
6173     const PetscInt **permsC[32] = {NULL};
6174 
6175     for (f = 0; f < numFields; f++) {
6176       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6177       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6178     }
6179     for (p = 0; p < numFPoints; p++) {
6180       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6181       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
6182     }
6183     for (p = 0; p < numCPoints; p++) {
6184       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6185       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6186     }
6187     for (f = 0; f < numFields; f++) {
6188       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6189       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6190     }
6191   } else {
6192     const PetscInt **permsF = NULL;
6193     const PetscInt **permsC = NULL;
6194 
6195     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6196     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6197     for (p = 0, off = 0; p < numFPoints; p++) {
6198       const PetscInt *perm = permsF ? permsF[p] : NULL;
6199 
6200       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6201       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6202     }
6203     for (p = 0, off = 0; p < numCPoints; p++) {
6204       const PetscInt *perm = permsC ? permsC[p] : NULL;
6205 
6206       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6207       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6208     }
6209     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6210     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6211   }
6212   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6213   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6214   PetscFunctionReturn(0);
6215 }
6216 
6217 /*@
6218   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6219 
6220   Input Parameter:
6221 . dm - The DMPlex object
6222 
6223   Output Parameters:
6224 + cMax - The first hybrid cell
6225 . fMax - The first hybrid face
6226 . eMax - The first hybrid edge
6227 - vMax - The first hybrid vertex
6228 
6229   Level: developer
6230 
6231 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6232 @*/
6233 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6234 {
6235   DM_Plex       *mesh = (DM_Plex*) dm->data;
6236   PetscInt       dim;
6237   PetscErrorCode ierr;
6238 
6239   PetscFunctionBegin;
6240   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6241   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6242   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6243   if (cMax) *cMax = mesh->hybridPointMax[dim];
6244   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6245   if (eMax) *eMax = mesh->hybridPointMax[1];
6246   if (vMax) *vMax = mesh->hybridPointMax[0];
6247   PetscFunctionReturn(0);
6248 }
6249 
6250 static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6251 {
6252   IS             is, his;
6253   PetscInt       first = 0, stride;
6254   PetscBool      isStride;
6255   PetscErrorCode ierr;
6256 
6257   PetscFunctionBegin;
6258   ierr = DMLabelGetStratumIS(depthLabel, d, &is);CHKERRQ(ierr);
6259   ierr = PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);CHKERRQ(ierr);
6260   if (isStride) {
6261     ierr = ISStrideGetInfo(is, &first, &stride);CHKERRQ(ierr);
6262   }
6263   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6264   ierr = ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);CHKERRQ(ierr);
6265   ierr = DMLabelSetStratumIS(dimLabel, d, his);CHKERRQ(ierr);
6266   ierr = ISDestroy(&his);CHKERRQ(ierr);
6267   ierr = ISDestroy(&is);CHKERRQ(ierr);
6268   PetscFunctionReturn(0);
6269 }
6270 
6271 /*@
6272   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6273 
6274   Input Parameters:
6275 . dm   - The DMPlex object
6276 . cMax - The first hybrid cell
6277 . fMax - The first hybrid face
6278 . eMax - The first hybrid edge
6279 - vMax - The first hybrid vertex
6280 
6281   Level: developer
6282 
6283 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6284 @*/
6285 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6286 {
6287   DM_Plex       *mesh = (DM_Plex*) dm->data;
6288   PetscInt       dim;
6289   PetscErrorCode ierr;
6290 
6291   PetscFunctionBegin;
6292   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6293   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6294   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6295   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6296   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6297   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6298   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6299   PetscFunctionReturn(0);
6300 }
6301 
6302 /*@C
6303   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6304 
6305   Input Parameter:
6306 . dm   - The DMPlex object
6307 
6308   Output Parameter:
6309 . cellHeight - The height of a cell
6310 
6311   Level: developer
6312 
6313 .seealso DMPlexSetVTKCellHeight()
6314 @*/
6315 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6316 {
6317   DM_Plex *mesh = (DM_Plex*) dm->data;
6318 
6319   PetscFunctionBegin;
6320   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6321   PetscValidPointer(cellHeight, 2);
6322   *cellHeight = mesh->vtkCellHeight;
6323   PetscFunctionReturn(0);
6324 }
6325 
6326 /*@C
6327   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6328 
6329   Input Parameters:
6330 + dm   - The DMPlex object
6331 - cellHeight - The height of a cell
6332 
6333   Level: developer
6334 
6335 .seealso DMPlexGetVTKCellHeight()
6336 @*/
6337 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6338 {
6339   DM_Plex *mesh = (DM_Plex*) dm->data;
6340 
6341   PetscFunctionBegin;
6342   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6343   mesh->vtkCellHeight = cellHeight;
6344   PetscFunctionReturn(0);
6345 }
6346 
6347 /* We can easily have a form that takes an IS instead */
6348 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6349 {
6350   PetscSection   section, globalSection;
6351   PetscInt      *numbers, p;
6352   PetscErrorCode ierr;
6353 
6354   PetscFunctionBegin;
6355   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6356   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
6357   for (p = pStart; p < pEnd; ++p) {
6358     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
6359   }
6360   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
6361   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6362   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
6363   for (p = pStart; p < pEnd; ++p) {
6364     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
6365     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6366     else                       numbers[p-pStart] += shift;
6367   }
6368   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
6369   if (globalSize) {
6370     PetscLayout layout;
6371     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
6372     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
6373     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
6374   }
6375   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6376   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6377   PetscFunctionReturn(0);
6378 }
6379 
6380 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6381 {
6382   PetscInt       cellHeight, cStart, cEnd, cMax;
6383   PetscErrorCode ierr;
6384 
6385   PetscFunctionBegin;
6386   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
6387   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6388   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6389   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6390   ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
6391   PetscFunctionReturn(0);
6392 }
6393 
6394 /*@C
6395   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6396 
6397   Input Parameter:
6398 . dm   - The DMPlex object
6399 
6400   Output Parameter:
6401 . globalCellNumbers - Global cell numbers for all cells on this process
6402 
6403   Level: developer
6404 
6405 .seealso DMPlexGetVertexNumbering()
6406 @*/
6407 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6408 {
6409   DM_Plex       *mesh = (DM_Plex*) dm->data;
6410   PetscErrorCode ierr;
6411 
6412   PetscFunctionBegin;
6413   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6414   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
6415   *globalCellNumbers = mesh->globalCellNumbers;
6416   PetscFunctionReturn(0);
6417 }
6418 
6419 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6420 {
6421   PetscInt       vStart, vEnd, vMax;
6422   PetscErrorCode ierr;
6423 
6424   PetscFunctionBegin;
6425   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6426   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6427   ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
6428   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6429   ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
6430   PetscFunctionReturn(0);
6431 }
6432 
6433 /*@C
6434   DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process
6435 
6436   Input Parameter:
6437 . dm   - The DMPlex object
6438 
6439   Output Parameter:
6440 . globalVertexNumbers - Global vertex numbers for all vertices on this process
6441 
6442   Level: developer
6443 
6444 .seealso DMPlexGetCellNumbering()
6445 @*/
6446 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6447 {
6448   DM_Plex       *mesh = (DM_Plex*) dm->data;
6449   PetscErrorCode ierr;
6450 
6451   PetscFunctionBegin;
6452   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6453   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
6454   *globalVertexNumbers = mesh->globalVertexNumbers;
6455   PetscFunctionReturn(0);
6456 }
6457 
6458 /*@C
6459   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6460 
6461   Input Parameter:
6462 . dm   - The DMPlex object
6463 
6464   Output Parameter:
6465 . globalPointNumbers - Global numbers for all points on this process
6466 
6467   Level: developer
6468 
6469 .seealso DMPlexGetCellNumbering()
6470 @*/
6471 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6472 {
6473   IS             nums[4];
6474   PetscInt       depths[4];
6475   PetscInt       depth, d, shift = 0;
6476   PetscErrorCode ierr;
6477 
6478   PetscFunctionBegin;
6479   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6480   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6481   /* For unstratified meshes use dim instead of depth */
6482   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
6483   depths[0] = depth; depths[1] = 0;
6484   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6485   for (d = 0; d <= depth; ++d) {
6486     PetscInt pStart, pEnd, gsize;
6487 
6488     ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr);
6489     ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
6490     shift += gsize;
6491   }
6492   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
6493   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
6494   PetscFunctionReturn(0);
6495 }
6496 
6497 
6498 /*@
6499   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6500 
6501   Input Parameter:
6502 . dm - The DMPlex object
6503 
6504   Output Parameter:
6505 . ranks - The rank field
6506 
6507   Options Database Keys:
6508 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6509 
6510   Level: intermediate
6511 
6512 .seealso: DMView()
6513 @*/
6514 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6515 {
6516   DM             rdm;
6517   PetscDS        prob;
6518   PetscFE        fe;
6519   PetscScalar   *r;
6520   PetscMPIInt    rank;
6521   PetscInt       dim, cStart, cEnd, c;
6522   PetscErrorCode ierr;
6523 
6524   PetscFunctionBeginUser;
6525   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
6526   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
6527   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
6528   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, NULL, -1, &fe);CHKERRQ(ierr);
6529   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
6530   ierr = DMGetDS(rdm, &prob);CHKERRQ(ierr);
6531   ierr = PetscDSSetDiscretization(prob, 0, (PetscObject) fe);CHKERRQ(ierr);
6532   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
6533   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6534   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
6535   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
6536   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
6537   for (c = cStart; c < cEnd; ++c) {
6538     PetscScalar *lr;
6539 
6540     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
6541     *lr = rank;
6542   }
6543   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
6544   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
6545   PetscFunctionReturn(0);
6546 }
6547 
6548 /*@
6549   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6550 
6551   Input Parameter:
6552 . dm - The DMPlex object
6553 
6554   Note: This is a useful diagnostic when creating meshes programmatically.
6555 
6556   Level: developer
6557 
6558 .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6559 @*/
6560 PetscErrorCode DMPlexCheckSymmetry(DM dm)
6561 {
6562   PetscSection    coneSection, supportSection;
6563   const PetscInt *cone, *support;
6564   PetscInt        coneSize, c, supportSize, s;
6565   PetscInt        pStart, pEnd, p, csize, ssize;
6566   PetscErrorCode  ierr;
6567 
6568   PetscFunctionBegin;
6569   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6570   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
6571   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
6572   /* Check that point p is found in the support of its cone points, and vice versa */
6573   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6574   for (p = pStart; p < pEnd; ++p) {
6575     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
6576     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
6577     for (c = 0; c < coneSize; ++c) {
6578       PetscBool dup = PETSC_FALSE;
6579       PetscInt  d;
6580       for (d = c-1; d >= 0; --d) {
6581         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6582       }
6583       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
6584       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
6585       for (s = 0; s < supportSize; ++s) {
6586         if (support[s] == p) break;
6587       }
6588       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6589         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
6590         for (s = 0; s < coneSize; ++s) {
6591           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
6592         }
6593         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6594         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
6595         for (s = 0; s < supportSize; ++s) {
6596           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
6597         }
6598         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6599         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6600         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6601       }
6602     }
6603     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
6604     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
6605     for (s = 0; s < supportSize; ++s) {
6606       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6607       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6608       for (c = 0; c < coneSize; ++c) {
6609         if (cone[c] == p) break;
6610       }
6611       if (c >= coneSize) {
6612         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
6613         for (c = 0; c < supportSize; ++c) {
6614           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
6615         }
6616         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6617         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
6618         for (c = 0; c < coneSize; ++c) {
6619           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
6620         }
6621         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6622         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6623       }
6624     }
6625   }
6626   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
6627   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
6628   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6629   PetscFunctionReturn(0);
6630 }
6631 
6632 /*@
6633   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6634 
6635   Input Parameters:
6636 + dm - The DMPlex object
6637 . isSimplex - Are the cells simplices or tensor products
6638 - cellHeight - Normally 0
6639 
6640   Note: This is a useful diagnostic when creating meshes programmatically.
6641 
6642   Level: developer
6643 
6644 .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6645 @*/
6646 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6647 {
6648   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6649   PetscErrorCode ierr;
6650 
6651   PetscFunctionBegin;
6652   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6653   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6654   switch (dim) {
6655   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6656   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6657   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6658   default:
6659     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6660   }
6661   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6662   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6663   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6664   cMax = cMax >= 0 ? cMax : cEnd;
6665   for (c = cStart; c < cMax; ++c) {
6666     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6667 
6668     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6669     for (cl = 0; cl < closureSize*2; cl += 2) {
6670       const PetscInt p = closure[cl];
6671       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6672     }
6673     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6674     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6675   }
6676   for (c = cMax; c < cEnd; ++c) {
6677     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6678 
6679     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6680     for (cl = 0; cl < closureSize*2; cl += 2) {
6681       const PetscInt p = closure[cl];
6682       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6683     }
6684     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6685     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6686   }
6687   PetscFunctionReturn(0);
6688 }
6689 
6690 /*@
6691   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6692 
6693   Input Parameters:
6694 + dm - The DMPlex object
6695 . isSimplex - Are the cells simplices or tensor products
6696 - cellHeight - Normally 0
6697 
6698   Note: This is a useful diagnostic when creating meshes programmatically.
6699 
6700   Level: developer
6701 
6702 .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6703 @*/
6704 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6705 {
6706   PetscInt       pMax[4];
6707   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;
6708   PetscErrorCode ierr;
6709 
6710   PetscFunctionBegin;
6711   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6712   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6713   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6714   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
6715   for (h = cellHeight; h < dim; ++h) {
6716     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
6717     for (c = cStart; c < cEnd; ++c) {
6718       const PetscInt *cone, *ornt, *faces;
6719       PetscInt        numFaces, faceSize, coneSize,f;
6720       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
6721 
6722       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6723       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6724       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6725       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6726       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6727       for (cl = 0; cl < closureSize*2; cl += 2) {
6728         const PetscInt p = closure[cl];
6729         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6730       }
6731       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
6732       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6733       for (f = 0; f < numFaces; ++f) {
6734         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6735 
6736         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
6737         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6738           const PetscInt p = fclosure[cl];
6739           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6740         }
6741         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);
6742         for (v = 0; v < fnumCorners; ++v) {
6743           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]);
6744         }
6745         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
6746       }
6747       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
6748       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6749     }
6750   }
6751   PetscFunctionReturn(0);
6752 }
6753 
6754 /* Pointwise interpolation
6755      Just code FEM for now
6756      u^f = I u^c
6757      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6758      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6759      I_{ij} = psi^f_i phi^c_j
6760 */
6761 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6762 {
6763   PetscSection   gsc, gsf;
6764   PetscInt       m, n;
6765   void          *ctx;
6766   DM             cdm;
6767   PetscBool      regular, ismatis;
6768   PetscErrorCode ierr;
6769 
6770   PetscFunctionBegin;
6771   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
6772   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
6773   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
6774   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
6775 
6776   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
6777   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
6778   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6779   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
6780   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
6781 
6782   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
6783   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
6784   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
6785   else                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
6786   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
6787   /* Use naive scaling */
6788   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
6789   PetscFunctionReturn(0);
6790 }
6791 
6792 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6793 {
6794   PetscErrorCode ierr;
6795   VecScatter     ctx;
6796 
6797   PetscFunctionBegin;
6798   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
6799   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
6800   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
6801   PetscFunctionReturn(0);
6802 }
6803 
6804 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6805 {
6806   PetscSection   gsc, gsf;
6807   PetscInt       m, n;
6808   void          *ctx;
6809   DM             cdm;
6810   PetscBool      regular;
6811   PetscErrorCode ierr;
6812 
6813   PetscFunctionBegin;
6814   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
6815   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
6816   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
6817   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
6818 
6819   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
6820   ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6821   ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
6822   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
6823 
6824   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
6825   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
6826   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
6827   else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
6828   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
6829   PetscFunctionReturn(0);
6830 }
6831 
6832 PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6833 {
6834   PetscSection   section;
6835   IS            *bcPoints, *bcComps;
6836   PetscBool     *isFE;
6837   PetscInt      *bcFields, *numComp, *numDof;
6838   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6839   PetscInt       cStart, cEnd, cEndInterior;
6840   PetscErrorCode ierr;
6841 
6842   PetscFunctionBegin;
6843   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
6844   /* FE and FV boundary conditions are handled slightly differently */
6845   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
6846   for (f = 0; f < numFields; ++f) {
6847     PetscObject  obj;
6848     PetscClassId id;
6849 
6850     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
6851     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
6852     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6853     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6854     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6855   }
6856   /* Allocate boundary point storage for FEM boundaries */
6857   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6858   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6859   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6860   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
6861   ierr = PetscDSGetNumBoundary(dm->prob, &numBd);CHKERRQ(ierr);
6862   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)");
6863   for (bd = 0; bd < numBd; ++bd) {
6864     PetscInt                field;
6865     DMBoundaryConditionType type;
6866     const char             *labelName;
6867     DMLabel                 label;
6868 
6869     ierr = PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
6870     ierr = DMGetLabel(dm,labelName,&label);CHKERRQ(ierr);
6871     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6872   }
6873   /* Add ghost cell boundaries for FVM */
6874   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6875   ierr = PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);CHKERRQ(ierr);
6876   /* Constrain ghost cells for FV */
6877   for (f = 0; f < numFields; ++f) {
6878     PetscInt *newidx, c;
6879 
6880     if (isFE[f] || cEndInterior < 0) continue;
6881     ierr = PetscMalloc1(cEnd-cEndInterior,&newidx);CHKERRQ(ierr);
6882     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6883     bcFields[bc] = f;
6884     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
6885   }
6886   /* Handle FEM Dirichlet boundaries */
6887   for (bd = 0; bd < numBd; ++bd) {
6888     const char             *bdLabel;
6889     DMLabel                 label;
6890     const PetscInt         *comps;
6891     const PetscInt         *values;
6892     PetscInt                bd2, field, numComps, numValues;
6893     DMBoundaryConditionType type;
6894     PetscBool               duplicate = PETSC_FALSE;
6895 
6896     ierr = PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);CHKERRQ(ierr);
6897     ierr = DMGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
6898     if (!isFE[field] || !label) continue;
6899     /* Only want to modify label once */
6900     for (bd2 = 0; bd2 < bd; ++bd2) {
6901       const char *bdname;
6902       ierr = PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
6903       ierr = PetscStrcmp(bdname, bdLabel, &duplicate);CHKERRQ(ierr);
6904       if (duplicate) break;
6905     }
6906     if (!duplicate && (isFE[field])) {
6907       /* don't complete cells, which are just present to give orientation to the boundary */
6908       ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
6909     }
6910     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6911     if (type & DM_BC_ESSENTIAL) {
6912       PetscInt       *newidx;
6913       PetscInt        n, newn = 0, p, v;
6914 
6915       bcFields[bc] = field;
6916       if (numComps) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);CHKERRQ(ierr);}
6917       for (v = 0; v < numValues; ++v) {
6918         IS              tmp;
6919         const PetscInt *idx;
6920 
6921         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
6922         if (!tmp) continue;
6923         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
6924         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
6925         if (isFE[field]) {
6926           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6927         } else {
6928           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6929         }
6930         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
6931         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
6932       }
6933       ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr);
6934       newn = 0;
6935       for (v = 0; v < numValues; ++v) {
6936         IS              tmp;
6937         const PetscInt *idx;
6938 
6939         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
6940         if (!tmp) continue;
6941         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
6942         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
6943         if (isFE[field]) {
6944           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6945         } else {
6946           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6947         }
6948         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
6949         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
6950       }
6951       ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
6952     }
6953   }
6954   /* Handle discretization */
6955   ierr = PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr);
6956   for (f = 0; f < numFields; ++f) {
6957     PetscObject obj;
6958 
6959     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
6960     if (isFE[f]) {
6961       PetscFE         fe = (PetscFE) obj;
6962       const PetscInt *numFieldDof;
6963       PetscInt        d;
6964 
6965       ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
6966       ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr);
6967       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6968     } else {
6969       PetscFV fv = (PetscFV) obj;
6970 
6971       ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
6972       numDof[f*(dim+1)+dim] = numComp[f];
6973     }
6974   }
6975   for (f = 0; f < numFields; ++f) {
6976     PetscInt d;
6977     for (d = 1; d < dim; ++d) {
6978       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.");
6979     }
6980   }
6981   ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);CHKERRQ(ierr);
6982   for (f = 0; f < numFields; ++f) {
6983     PetscFE     fe;
6984     const char *name;
6985 
6986     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
6987     ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr);
6988     ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr);
6989   }
6990   ierr = DMSetSection(dm, section);CHKERRQ(ierr);
6991   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6992   for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);ierr = ISDestroy(&bcComps[bc]);CHKERRQ(ierr);}
6993   ierr = PetscFree3(bcFields,bcPoints,bcComps);CHKERRQ(ierr);
6994   ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr);
6995   ierr = PetscFree(isFE);CHKERRQ(ierr);
6996   PetscFunctionReturn(0);
6997 }
6998 
6999 /*@
7000   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7001 
7002   Input Parameter:
7003 . dm - The DMPlex object
7004 
7005   Output Parameter:
7006 . regular - The flag
7007 
7008   Level: intermediate
7009 
7010 .seealso: DMPlexSetRegularRefinement()
7011 @*/
7012 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7013 {
7014   PetscFunctionBegin;
7015   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7016   PetscValidPointer(regular, 2);
7017   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7018   PetscFunctionReturn(0);
7019 }
7020 
7021 /*@
7022   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7023 
7024   Input Parameters:
7025 + dm - The DMPlex object
7026 - regular - The flag
7027 
7028   Level: intermediate
7029 
7030 .seealso: DMPlexGetRegularRefinement()
7031 @*/
7032 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7033 {
7034   PetscFunctionBegin;
7035   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7036   ((DM_Plex *) dm->data)->regularRefinement = regular;
7037   PetscFunctionReturn(0);
7038 }
7039 
7040 /* anchors */
7041 /*@
7042   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
7043   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
7044 
7045   not collective
7046 
7047   Input Parameters:
7048 . dm - The DMPlex object
7049 
7050   Output Parameters:
7051 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
7052 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
7053 
7054 
7055   Level: intermediate
7056 
7057 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7058 @*/
7059 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7060 {
7061   DM_Plex *plex = (DM_Plex *)dm->data;
7062   PetscErrorCode ierr;
7063 
7064   PetscFunctionBegin;
7065   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7066   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
7067   if (anchorSection) *anchorSection = plex->anchorSection;
7068   if (anchorIS) *anchorIS = plex->anchorIS;
7069   PetscFunctionReturn(0);
7070 }
7071 
7072 /*@
7073   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
7074   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
7075   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
7076 
7077   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
7078   DMGetConstraints() and filling in the entries in the constraint matrix.
7079 
7080   collective on dm
7081 
7082   Input Parameters:
7083 + dm - The DMPlex object
7084 . 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).
7085 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
7086 
7087   The reference counts of anchorSection and anchorIS are incremented.
7088 
7089   Level: intermediate
7090 
7091 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7092 @*/
7093 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7094 {
7095   DM_Plex        *plex = (DM_Plex *)dm->data;
7096   PetscMPIInt    result;
7097   PetscErrorCode ierr;
7098 
7099   PetscFunctionBegin;
7100   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7101   if (anchorSection) {
7102     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
7103     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
7104     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7105   }
7106   if (anchorIS) {
7107     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
7108     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
7109     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7110   }
7111 
7112   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
7113   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
7114   plex->anchorSection = anchorSection;
7115 
7116   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
7117   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
7118   plex->anchorIS = anchorIS;
7119 
7120 #if defined(PETSC_USE_DEBUG)
7121   if (anchorIS && anchorSection) {
7122     PetscInt size, a, pStart, pEnd;
7123     const PetscInt *anchors;
7124 
7125     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
7126     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
7127     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
7128     for (a = 0; a < size; a++) {
7129       PetscInt p;
7130 
7131       p = anchors[a];
7132       if (p >= pStart && p < pEnd) {
7133         PetscInt dof;
7134 
7135         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
7136         if (dof) {
7137           PetscErrorCode ierr2;
7138 
7139           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7140           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7141         }
7142       }
7143     }
7144     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
7145   }
7146 #endif
7147   /* reset the generic constraints */
7148   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
7149   PetscFunctionReturn(0);
7150 }
7151 
7152 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7153 {
7154   PetscSection anchorSection;
7155   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
7156   PetscErrorCode ierr;
7157 
7158   PetscFunctionBegin;
7159   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7160   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
7161   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
7162   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
7163   if (numFields) {
7164     PetscInt f;
7165     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
7166 
7167     for (f = 0; f < numFields; f++) {
7168       PetscInt numComp;
7169 
7170       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
7171       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
7172     }
7173   }
7174   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
7175   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
7176   pStart = PetscMax(pStart,sStart);
7177   pEnd   = PetscMin(pEnd,sEnd);
7178   pEnd   = PetscMax(pStart,pEnd);
7179   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
7180   for (p = pStart; p < pEnd; p++) {
7181     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
7182     if (dof) {
7183       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
7184       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
7185       for (f = 0; f < numFields; f++) {
7186         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
7187         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
7188       }
7189     }
7190   }
7191   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
7192   PetscFunctionReturn(0);
7193 }
7194 
7195 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7196 {
7197   PetscSection aSec;
7198   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7199   const PetscInt *anchors;
7200   PetscInt numFields, f;
7201   IS aIS;
7202   PetscErrorCode ierr;
7203 
7204   PetscFunctionBegin;
7205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7206   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
7207   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
7208   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
7209   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
7210   ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr);
7211   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
7212   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
7213   /* cSec will be a subset of aSec and section */
7214   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
7215   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
7216   i[0] = 0;
7217   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
7218   for (p = pStart; p < pEnd; p++) {
7219     PetscInt rDof, rOff, r;
7220 
7221     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7222     if (!rDof) continue;
7223     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7224     if (numFields) {
7225       for (f = 0; f < numFields; f++) {
7226         annz = 0;
7227         for (r = 0; r < rDof; r++) {
7228           a = anchors[rOff + r];
7229           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
7230           annz += aDof;
7231         }
7232         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
7233         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
7234         for (q = 0; q < dof; q++) {
7235           i[off + q + 1] = i[off + q] + annz;
7236         }
7237       }
7238     }
7239     else {
7240       annz = 0;
7241       for (q = 0; q < dof; q++) {
7242         a = anchors[off + q];
7243         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
7244         annz += aDof;
7245       }
7246       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
7247       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
7248       for (q = 0; q < dof; q++) {
7249         i[off + q + 1] = i[off + q] + annz;
7250       }
7251     }
7252   }
7253   nnz = i[m];
7254   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
7255   offset = 0;
7256   for (p = pStart; p < pEnd; p++) {
7257     if (numFields) {
7258       for (f = 0; f < numFields; f++) {
7259         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
7260         for (q = 0; q < dof; q++) {
7261           PetscInt rDof, rOff, r;
7262           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7263           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7264           for (r = 0; r < rDof; r++) {
7265             PetscInt s;
7266 
7267             a = anchors[rOff + r];
7268             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
7269             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
7270             for (s = 0; s < aDof; s++) {
7271               j[offset++] = aOff + s;
7272             }
7273           }
7274         }
7275       }
7276     }
7277     else {
7278       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
7279       for (q = 0; q < dof; q++) {
7280         PetscInt rDof, rOff, r;
7281         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7282         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7283         for (r = 0; r < rDof; r++) {
7284           PetscInt s;
7285 
7286           a = anchors[rOff + r];
7287           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
7288           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
7289           for (s = 0; s < aDof; s++) {
7290             j[offset++] = aOff + s;
7291           }
7292         }
7293       }
7294     }
7295   }
7296   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
7297   ierr = PetscFree(i);CHKERRQ(ierr);
7298   ierr = PetscFree(j);CHKERRQ(ierr);
7299   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
7300   PetscFunctionReturn(0);
7301 }
7302 
7303 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7304 {
7305   DM_Plex        *plex = (DM_Plex *)dm->data;
7306   PetscSection   anchorSection, section, cSec;
7307   Mat            cMat;
7308   PetscErrorCode ierr;
7309 
7310   PetscFunctionBegin;
7311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7312   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
7313   if (anchorSection) {
7314     PetscDS  ds;
7315     PetscInt nf;
7316 
7317     ierr = DMGetSection(dm,&section);CHKERRQ(ierr);
7318     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
7319     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
7320     ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
7321     ierr = PetscDSGetNumFields(ds,&nf);CHKERRQ(ierr);
7322     if (nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
7323     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
7324     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
7325     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
7326   }
7327   PetscFunctionReturn(0);
7328 }
7329 
7330 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7331 {
7332   PetscDS        prob;
7333   IS             subis;
7334   PetscSection   section, subsection;
7335   PetscErrorCode ierr;
7336 
7337   PetscFunctionBegin;
7338   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7339   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7340   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7341   /* Create subdomain */
7342   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
7343   /* Create submodel */
7344   ierr = DMPlexCreateSubpointIS(*subdm, &subis);CHKERRQ(ierr);
7345   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
7346   ierr = ISDestroy(&subis);CHKERRQ(ierr);
7347   ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
7348   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
7349   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
7350   ierr = DMSetDS(*subdm, prob);CHKERRQ(ierr);
7351   /* Create map from submodel to global model */
7352   if (is) {
7353     PetscSection    sectionGlobal, subsectionGlobal;
7354     IS              spIS;
7355     const PetscInt *spmap;
7356     PetscInt       *subIndices;
7357     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
7358     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
7359 
7360     ierr = DMPlexCreateSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
7361     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
7362     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
7363     ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
7364     ierr = DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
7365     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
7366     for (p = pStart; p < pEnd; ++p) {
7367       PetscInt gdof, pSubSize  = 0;
7368 
7369       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
7370       if (gdof > 0) {
7371         for (f = 0; f < Nf; ++f) {
7372           PetscInt fdof, fcdof;
7373 
7374           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
7375           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
7376           pSubSize += fdof-fcdof;
7377         }
7378         subSize += pSubSize;
7379         if (pSubSize) {
7380           if (bs < 0) {
7381             bs = pSubSize;
7382           } else if (bs != pSubSize) {
7383             /* Layout does not admit a pointwise block size */
7384             bs = 1;
7385           }
7386         }
7387       }
7388     }
7389     /* Must have same blocksize on all procs (some might have no points) */
7390     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7391     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
7392     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7393     else                            {bs = bsMinMax[0];}
7394     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
7395     for (p = pStart; p < pEnd; ++p) {
7396       PetscInt gdof, goff;
7397 
7398       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
7399       if (gdof > 0) {
7400         const PetscInt point = spmap[p];
7401 
7402         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
7403         for (f = 0; f < Nf; ++f) {
7404           PetscInt fdof, fcdof, fc, f2, poff = 0;
7405 
7406           /* Can get rid of this loop by storing field information in the global section */
7407           for (f2 = 0; f2 < f; ++f2) {
7408             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
7409             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
7410             poff += fdof-fcdof;
7411           }
7412           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7413           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7414           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7415             subIndices[subOff] = goff+poff+fc;
7416           }
7417         }
7418       }
7419     }
7420     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
7421     ierr = ISDestroy(&spIS);CHKERRQ(ierr);
7422     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
7423     if (bs > 1) {
7424       /* We need to check that the block size does not come from non-contiguous fields */
7425       PetscInt i, j, set = 1;
7426       for (i = 0; i < subSize; i += bs) {
7427         for (j = 0; j < bs; ++j) {
7428           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7429         }
7430       }
7431       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
7432     }
7433     /* Attach nullspace */
7434     for (f = 0; f < Nf; ++f) {
7435       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7436       if ((*subdm)->nullspaceConstructors[f]) break;
7437     }
7438     if (f < Nf) {
7439       MatNullSpace nullSpace;
7440 
7441       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);CHKERRQ(ierr);
7442       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
7443       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
7444     }
7445   }
7446   PetscFunctionReturn(0);
7447 }
7448