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