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