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