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