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