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