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