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