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