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