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