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