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