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