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