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