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