xref: /petsc/src/dm/impls/plex/plex.c (revision 503335f2bb2e737c72788c1ddaf9ea14155ebaae)
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, cdof, maxDof = 0, 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   for (p = pStart; p < pEnd; ++p) {ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); maxDof = PetscMax(maxDof, cdof);}
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        fdof, fcdof, c;
3194 
3195       ierr = PetscSectionGetFieldDof(section, p, field, &fdof);CHKERRQ(ierr);
3196       if (!fdof) continue;
3197       if (Nc < 0) {
3198         for (d = 0; d < fdof; ++d) indices[d] = d;
3199         fcdof = fdof;
3200       } else {
3201         ierr = PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);CHKERRQ(ierr);
3202         ierr = PetscSectionGetFieldConstraintIndices(section, p, field, &find);CHKERRQ(ierr);
3203         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3204         for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
3205         ierr = PetscSortRemoveDupsInt(&d, indices);CHKERRQ(ierr);
3206         for (c = d; c < fcdof; ++c) indices[c] = -1;
3207         fcdof = d;
3208       }
3209       ierr = PetscSectionSetFieldConstraintDof(section, p, field, fcdof);CHKERRQ(ierr);
3210       ierr = PetscSectionSetFieldConstraintIndices(section, p, field, indices);CHKERRQ(ierr);
3211     }
3212     if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3213     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3214   }
3215   /* Handle anchors */
3216   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
3217   if (aSec) {
3218     PetscInt aStart, aEnd, a;
3219 
3220     for (d = 0; d < maxDof; ++d) indices[d] = d;
3221     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
3222     for (a = aStart; a < aEnd; a++) {
3223       PetscInt dof, f;
3224 
3225       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
3226       if (dof) {
3227         /* if there are point-to-point constraints, then all dofs are constrained */
3228         for (f = 0; f < numFields; f++) {
3229           ierr = PetscSectionSetFieldConstraintIndices(section, a, f, indices);CHKERRQ(ierr);
3230         }
3231       }
3232     }
3233   }
3234   ierr = PetscFree(indices);CHKERRQ(ierr);
3235   PetscFunctionReturn(0);
3236 }
3237 
3238 /* Set the constrained indices on each point */
3239 static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3240 {
3241   PetscInt      *indices;
3242   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;
3243   PetscErrorCode ierr;
3244 
3245   PetscFunctionBegin;
3246   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3247   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
3248   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3249   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
3250   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3251   for (p = pStart; p < pEnd; ++p) {
3252     PetscInt cdof, d;
3253 
3254     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
3255     if (cdof) {
3256       if (numFields) {
3257         PetscInt numConst = 0, foff = 0;
3258 
3259         for (f = 0; f < numFields; ++f) {
3260           const PetscInt *find;
3261           PetscInt        fcdof, fdof;
3262 
3263           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
3264           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
3265           /* Change constraint numbering from field component to local dof number */
3266           ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &find);CHKERRQ(ierr);
3267           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3268           numConst += fcdof;
3269           foff     += fdof;
3270         }
3271         if (cdof != numConst) {ierr = PetscSectionSetConstraintDof(section, p, numConst);CHKERRQ(ierr);}
3272       } else {
3273         for (d = 0; d < cdof; ++d) indices[d] = d;
3274       }
3275       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
3276     }
3277   }
3278   ierr = PetscFree(indices);CHKERRQ(ierr);
3279   PetscFunctionReturn(0);
3280 }
3281 
3282 /*@C
3283   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
3284 
3285   Not Collective
3286 
3287   Input Parameters:
3288 + dm        - The DMPlex object
3289 . dim       - The spatial dimension of the problem
3290 . numFields - The number of fields in the problem
3291 . numComp   - An array of size numFields that holds the number of components for each field
3292 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3293 . numBC     - The number of boundary conditions
3294 . bcField   - An array of size numBC giving the field number for each boundry condition
3295 . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3296 . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3297 - perm      - Optional permutation of the chart, or NULL
3298 
3299   Output Parameter:
3300 . section - The PetscSection object
3301 
3302   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
3303   number of dof for field 0 on each edge.
3304 
3305   The chart permutation is the same one set using PetscSectionSetPermutation()
3306 
3307   Level: developer
3308 
3309   Fortran Notes:
3310   A Fortran 90 version is available as DMPlexCreateSectionF90()
3311 
3312 .keywords: mesh, elements
3313 .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3314 @*/
3315 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)
3316 {
3317   PetscSection   aSec;
3318   PetscErrorCode ierr;
3319 
3320   PetscFunctionBegin;
3321   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
3322   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
3323   if (perm) {ierr = PetscSectionSetPermutation(*section, perm);CHKERRQ(ierr);}
3324   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3325   ierr = DMPlexGetAnchors(dm,&aSec,NULL);CHKERRQ(ierr);
3326   if (numBC || aSec) {
3327     ierr = DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
3328     ierr = DMPlexCreateSectionBCIndices(dm, *section);CHKERRQ(ierr);
3329   }
3330   ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr);
3331   PetscFunctionReturn(0);
3332 }
3333 
3334 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3335 {
3336   PetscSection   section, s;
3337   Mat            m;
3338   PetscInt       maxHeight;
3339   PetscErrorCode ierr;
3340 
3341   PetscFunctionBegin;
3342   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
3343   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
3344   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
3345   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
3346   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
3347   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
3348   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
3349   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
3350   ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr);
3351   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
3352   ierr = MatDestroy(&m);CHKERRQ(ierr);
3353   PetscFunctionReturn(0);
3354 }
3355 
3356 /*@C
3357   DMPlexGetConeSection - Return a section which describes the layout of cone data
3358 
3359   Not Collective
3360 
3361   Input Parameters:
3362 . dm        - The DMPlex object
3363 
3364   Output Parameter:
3365 . section - The PetscSection object
3366 
3367   Level: developer
3368 
3369 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3370 @*/
3371 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3372 {
3373   DM_Plex *mesh = (DM_Plex*) dm->data;
3374 
3375   PetscFunctionBegin;
3376   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3377   if (section) *section = mesh->coneSection;
3378   PetscFunctionReturn(0);
3379 }
3380 
3381 /*@C
3382   DMPlexGetSupportSection - Return a section which describes the layout of support data
3383 
3384   Not Collective
3385 
3386   Input Parameters:
3387 . dm        - The DMPlex object
3388 
3389   Output Parameter:
3390 . section - The PetscSection object
3391 
3392   Level: developer
3393 
3394 .seealso: DMPlexGetConeSection()
3395 @*/
3396 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3397 {
3398   DM_Plex *mesh = (DM_Plex*) dm->data;
3399 
3400   PetscFunctionBegin;
3401   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3402   if (section) *section = mesh->supportSection;
3403   PetscFunctionReturn(0);
3404 }
3405 
3406 /*@C
3407   DMPlexGetCones - Return cone data
3408 
3409   Not Collective
3410 
3411   Input Parameters:
3412 . dm        - The DMPlex object
3413 
3414   Output Parameter:
3415 . cones - The cone for each point
3416 
3417   Level: developer
3418 
3419 .seealso: DMPlexGetConeSection()
3420 @*/
3421 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3422 {
3423   DM_Plex *mesh = (DM_Plex*) dm->data;
3424 
3425   PetscFunctionBegin;
3426   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3427   if (cones) *cones = mesh->cones;
3428   PetscFunctionReturn(0);
3429 }
3430 
3431 /*@C
3432   DMPlexGetConeOrientations - Return cone orientation data
3433 
3434   Not Collective
3435 
3436   Input Parameters:
3437 . dm        - The DMPlex object
3438 
3439   Output Parameter:
3440 . coneOrientations - The cone orientation for each point
3441 
3442   Level: developer
3443 
3444 .seealso: DMPlexGetConeSection()
3445 @*/
3446 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3447 {
3448   DM_Plex *mesh = (DM_Plex*) dm->data;
3449 
3450   PetscFunctionBegin;
3451   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3452   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3453   PetscFunctionReturn(0);
3454 }
3455 
3456 /******************************** FEM Support **********************************/
3457 
3458 PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3459 {
3460   PetscInt      *perm;
3461   PetscInt       dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3462   PetscErrorCode ierr;
3463 
3464   PetscFunctionBegin;
3465   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3466   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3467   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
3468   if (dim <= 1) PetscFunctionReturn(0);
3469   for (f = 0; f < Nf; ++f) {
3470     /* An order k SEM disc has k-1 dofs on an edge */
3471     ierr = DMPlexGetDepthStratum(dm, 1, &eStart, NULL);CHKERRQ(ierr);
3472     ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3473     ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3474     k = k/Nc + 1;
3475     size += PetscPowInt(k+1, dim)*Nc;
3476   }
3477   ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
3478   for (f = 0; f < Nf; ++f) {
3479     switch (dim) {
3480     case 2:
3481       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3482       ierr = DMPlexGetDepthStratum(dm, 1, &eStart, NULL);CHKERRQ(ierr);
3483       ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3484       ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3485       k = k/Nc + 1;
3486       /* The SEM order is
3487 
3488          v_lb, {e_b}, v_rb,
3489          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3490          v_lt, reverse {e_t}, v_rt
3491       */
3492       {
3493         const PetscInt of   = 0;
3494         const PetscInt oeb  = of   + PetscSqr(k-1);
3495         const PetscInt oer  = oeb  + (k-1);
3496         const PetscInt oet  = oer  + (k-1);
3497         const PetscInt oel  = oet  + (k-1);
3498         const PetscInt ovlb = oel  + (k-1);
3499         const PetscInt ovrb = ovlb + 1;
3500         const PetscInt ovrt = ovrb + 1;
3501         const PetscInt ovlt = ovrt + 1;
3502         PetscInt       o;
3503 
3504         /* bottom */
3505         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3506         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3507         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3508         /* middle */
3509         for (i = 0; i < k-1; ++i) {
3510           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3511           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;
3512           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3513         }
3514         /* top */
3515         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3516         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3517         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3518         foffset = offset;
3519       }
3520       break;
3521     case 3:
3522       /* The original hex closure is
3523 
3524          {c,
3525           f_b, f_t, f_f, f_b, f_r, f_l,
3526           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3527           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3528       */
3529       ierr = DMPlexGetDepthStratum(dm, 1, &eStart, NULL);CHKERRQ(ierr);
3530       ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3531       ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3532       k = k/Nc + 1;
3533       /* The SEM order is
3534          Bottom Slice
3535          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3536          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3537          v_blb, {e_bb}, v_brb,
3538 
3539          Middle Slice (j)
3540          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3541          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3542          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3543 
3544          Top Slice
3545          v_tlf, {e_tf}, v_trf,
3546          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3547          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3548       */
3549       {
3550         const PetscInt oc    = 0;
3551         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3552         const PetscInt oft   = ofb   + PetscSqr(k-1);
3553         const PetscInt off   = oft   + PetscSqr(k-1);
3554         const PetscInt ofk   = off   + PetscSqr(k-1);
3555         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3556         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3557         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3558         const PetscInt oebb  = oebl  + (k-1);
3559         const PetscInt oebr  = oebb  + (k-1);
3560         const PetscInt oebf  = oebr  + (k-1);
3561         const PetscInt oetf  = oebf  + (k-1);
3562         const PetscInt oetr  = oetf  + (k-1);
3563         const PetscInt oetb  = oetr  + (k-1);
3564         const PetscInt oetl  = oetb  + (k-1);
3565         const PetscInt oerf  = oetl  + (k-1);
3566         const PetscInt oelf  = oerf  + (k-1);
3567         const PetscInt oelb  = oelf  + (k-1);
3568         const PetscInt oerb  = oelb  + (k-1);
3569         const PetscInt ovblf = oerb  + (k-1);
3570         const PetscInt ovblb = ovblf + 1;
3571         const PetscInt ovbrb = ovblb + 1;
3572         const PetscInt ovbrf = ovbrb + 1;
3573         const PetscInt ovtlf = ovbrf + 1;
3574         const PetscInt ovtrf = ovtlf + 1;
3575         const PetscInt ovtrb = ovtrf + 1;
3576         const PetscInt ovtlb = ovtrb + 1;
3577         PetscInt       o, n;
3578 
3579         /* Bottom Slice */
3580         /*   bottom */
3581         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3582         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3583         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3584         /*   middle */
3585         for (i = 0; i < k-1; ++i) {
3586           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3587           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;}
3588           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3589         }
3590         /*   top */
3591         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3592         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3593         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
3594 
3595         /* Middle Slice */
3596         for (j = 0; j < k-1; ++j) {
3597           /*   bottom */
3598           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3599           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;
3600           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3601           /*   middle */
3602           for (i = 0; i < k-1; ++i) {
3603             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3604             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;
3605             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3606           }
3607           /*   top */
3608           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3609           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;
3610           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3611         }
3612 
3613         /* Top Slice */
3614         /*   bottom */
3615         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3616         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3617         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3618         /*   middle */
3619         for (i = 0; i < k-1; ++i) {
3620           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3621           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3622           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3623         }
3624         /*   top */
3625         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3626         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3627         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
3628 
3629         foffset = offset;
3630       }
3631       break;
3632     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3633     }
3634   }
3635   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3636   /* Check permutation */
3637   {
3638     PetscInt *check;
3639 
3640     ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
3641     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]);}
3642     for (i = 0; i < size; ++i) check[perm[i]] = i;
3643     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3644     ierr = PetscFree(check);CHKERRQ(ierr);
3645   }
3646   ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
3647   PetscFunctionReturn(0);
3648 }
3649 
3650 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3651 {
3652   PetscDS        prob;
3653   PetscInt       depth, Nf, h;
3654   DMLabel        label;
3655   PetscErrorCode ierr;
3656 
3657   PetscFunctionBeginHot;
3658   prob    = dm->prob;
3659   Nf      = prob->Nf;
3660   label   = dm->depthLabel;
3661   *dspace = NULL;
3662   if (field < Nf) {
3663     PetscObject disc = prob->disc[field];
3664 
3665     if (disc->classid == PETSCFE_CLASSID) {
3666       PetscDualSpace dsp;
3667 
3668       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3669       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
3670       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
3671       h    = depth - 1 - h;
3672       if (h) {
3673         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
3674       } else {
3675         *dspace = dsp;
3676       }
3677     }
3678   }
3679   PetscFunctionReturn(0);
3680 }
3681 
3682 
3683 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3684 {
3685   PetscScalar    *array, *vArray;
3686   const PetscInt *cone, *coneO;
3687   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3688   PetscErrorCode  ierr;
3689 
3690   PetscFunctionBeginHot;
3691   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3692   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3693   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3694   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3695   if (!values || !*values) {
3696     if ((point >= pStart) && (point < pEnd)) {
3697       PetscInt dof;
3698 
3699       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3700       size += dof;
3701     }
3702     for (p = 0; p < numPoints; ++p) {
3703       const PetscInt cp = cone[p];
3704       PetscInt       dof;
3705 
3706       if ((cp < pStart) || (cp >= pEnd)) continue;
3707       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3708       size += dof;
3709     }
3710     if (!values) {
3711       if (csize) *csize = size;
3712       PetscFunctionReturn(0);
3713     }
3714     ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
3715   } else {
3716     array = *values;
3717   }
3718   size = 0;
3719   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
3720   if ((point >= pStart) && (point < pEnd)) {
3721     PetscInt     dof, off, d;
3722     PetscScalar *varr;
3723 
3724     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3725     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3726     varr = &vArray[off];
3727     for (d = 0; d < dof; ++d, ++offset) {
3728       array[offset] = varr[d];
3729     }
3730     size += dof;
3731   }
3732   for (p = 0; p < numPoints; ++p) {
3733     const PetscInt cp = cone[p];
3734     PetscInt       o  = coneO[p];
3735     PetscInt       dof, off, d;
3736     PetscScalar   *varr;
3737 
3738     if ((cp < pStart) || (cp >= pEnd)) continue;
3739     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3740     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
3741     varr = &vArray[off];
3742     if (o >= 0) {
3743       for (d = 0; d < dof; ++d, ++offset) {
3744         array[offset] = varr[d];
3745       }
3746     } else {
3747       for (d = dof-1; d >= 0; --d, ++offset) {
3748         array[offset] = varr[d];
3749       }
3750     }
3751     size += dof;
3752   }
3753   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
3754   if (!*values) {
3755     if (csize) *csize = size;
3756     *values = array;
3757   } else {
3758     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3759     *csize = size;
3760   }
3761   PetscFunctionReturn(0);
3762 }
3763 
3764 static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3765 {
3766   const PetscInt *cla;
3767   PetscInt       np, *pts = NULL;
3768   PetscErrorCode ierr;
3769 
3770   PetscFunctionBeginHot;
3771   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
3772   if (!*clPoints) {
3773     PetscInt pStart, pEnd, p, q;
3774 
3775     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3776     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
3777     /* Compress out points not in the section */
3778     for (p = 0, q = 0; p < np; p++) {
3779       PetscInt r = pts[2*p];
3780       if ((r >= pStart) && (r < pEnd)) {
3781         pts[q*2]   = r;
3782         pts[q*2+1] = pts[2*p+1];
3783         ++q;
3784       }
3785     }
3786     np = q;
3787     cla = NULL;
3788   } else {
3789     PetscInt dof, off;
3790 
3791     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
3792     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
3793     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
3794     np   = dof/2;
3795     pts  = (PetscInt *) &cla[off];
3796   }
3797   *numPoints = np;
3798   *points    = pts;
3799   *clp       = cla;
3800 
3801   PetscFunctionReturn(0);
3802 }
3803 
3804 static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3805 {
3806   PetscErrorCode ierr;
3807 
3808   PetscFunctionBeginHot;
3809   if (!*clPoints) {
3810     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
3811   } else {
3812     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
3813   }
3814   *numPoints = 0;
3815   *points    = NULL;
3816   *clSec     = NULL;
3817   *clPoints  = NULL;
3818   *clp       = NULL;
3819   PetscFunctionReturn(0);
3820 }
3821 
3822 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[])
3823 {
3824   PetscInt          offset = 0, p;
3825   const PetscInt    **perms = NULL;
3826   const PetscScalar **flips = NULL;
3827   PetscErrorCode    ierr;
3828 
3829   PetscFunctionBeginHot;
3830   *size = 0;
3831   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
3832   for (p = 0; p < numPoints; p++) {
3833     const PetscInt    point = points[2*p];
3834     const PetscInt    *perm = perms ? perms[p] : NULL;
3835     const PetscScalar *flip = flips ? flips[p] : NULL;
3836     PetscInt          dof, off, d;
3837     const PetscScalar *varr;
3838 
3839     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3840     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3841     varr = &vArray[off];
3842     if (clperm) {
3843       if (perm) {
3844         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3845       } else {
3846         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3847       }
3848       if (flip) {
3849         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3850       }
3851     } else {
3852       if (perm) {
3853         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3854       } else {
3855         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3856       }
3857       if (flip) {
3858         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3859       }
3860     }
3861     offset += dof;
3862   }
3863   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
3864   *size = offset;
3865   PetscFunctionReturn(0);
3866 }
3867 
3868 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[])
3869 {
3870   PetscInt          offset = 0, f;
3871   PetscErrorCode    ierr;
3872 
3873   PetscFunctionBeginHot;
3874   *size = 0;
3875   for (f = 0; f < numFields; ++f) {
3876     PetscInt          p;
3877     const PetscInt    **perms = NULL;
3878     const PetscScalar **flips = NULL;
3879 
3880     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
3881     for (p = 0; p < numPoints; p++) {
3882       const PetscInt    point = points[2*p];
3883       PetscInt          fdof, foff, b;
3884       const PetscScalar *varr;
3885       const PetscInt    *perm = perms ? perms[p] : NULL;
3886       const PetscScalar *flip = flips ? flips[p] : NULL;
3887 
3888       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3889       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3890       varr = &vArray[foff];
3891       if (clperm) {
3892         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
3893         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
3894         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
3895       } else {
3896         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
3897         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
3898         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
3899       }
3900       offset += fdof;
3901     }
3902     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
3903   }
3904   *size = offset;
3905   PetscFunctionReturn(0);
3906 }
3907 
3908 /*@C
3909   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
3910 
3911   Not collective
3912 
3913   Input Parameters:
3914 + dm - The DM
3915 . section - The section describing the layout in v, or NULL to use the default section
3916 . v - The local vector
3917 - point - The sieve point in the DM
3918 
3919   Output Parameters:
3920 + csize - The number of values in the closure, or NULL
3921 - values - The array of values, which is a borrowed array and should not be freed
3922 
3923   Fortran Notes:
3924   Since it returns an array, this routine is only available in Fortran 90, and you must
3925   include petsc.h90 in your code.
3926 
3927   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
3928 
3929   Level: intermediate
3930 
3931 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3932 @*/
3933 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3934 {
3935   PetscSection       clSection;
3936   IS                 clPoints;
3937   PetscScalar       *array;
3938   const PetscScalar *vArray;
3939   PetscInt          *points = NULL;
3940   const PetscInt    *clp, *perm;
3941   PetscInt           depth, numFields, numPoints, size;
3942   PetscErrorCode     ierr;
3943 
3944   PetscFunctionBeginHot;
3945   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3946   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3947   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3948   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
3949   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3950   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3951   if (depth == 1 && numFields < 2) {
3952     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
3953     PetscFunctionReturn(0);
3954   }
3955   /* Get points */
3956   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
3957   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr);
3958   /* Get array */
3959   if (!values || !*values) {
3960     PetscInt asize = 0, dof, p;
3961 
3962     for (p = 0; p < numPoints*2; p += 2) {
3963       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3964       asize += dof;
3965     }
3966     if (!values) {
3967       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
3968       if (csize) *csize = asize;
3969       PetscFunctionReturn(0);
3970     }
3971     ierr = DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);CHKERRQ(ierr);
3972   } else {
3973     array = *values;
3974   }
3975   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
3976   /* Get values */
3977   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
3978   else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);CHKERRQ(ierr);}
3979   /* Cleanup points */
3980   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
3981   /* Cleanup array */
3982   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
3983   if (!*values) {
3984     if (csize) *csize = size;
3985     *values = array;
3986   } else {
3987     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3988     *csize = size;
3989   }
3990   PetscFunctionReturn(0);
3991 }
3992 
3993 /*@C
3994   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
3995 
3996   Not collective
3997 
3998   Input Parameters:
3999 + dm - The DM
4000 . section - The section describing the layout in v, or NULL to use the default section
4001 . v - The local vector
4002 . point - The sieve point in the DM
4003 . csize - The number of values in the closure, or NULL
4004 - values - The array of values, which is a borrowed array and should not be freed
4005 
4006   Fortran Notes:
4007   Since it returns an array, this routine is only available in Fortran 90, and you must
4008   include petsc.h90 in your code.
4009 
4010   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4011 
4012   Level: intermediate
4013 
4014 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4015 @*/
4016 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4017 {
4018   PetscInt       size = 0;
4019   PetscErrorCode ierr;
4020 
4021   PetscFunctionBegin;
4022   /* Should work without recalculating size */
4023   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
4024   PetscFunctionReturn(0);
4025 }
4026 
4027 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
4028 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
4029 
4030 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[])
4031 {
4032   PetscInt        cdof;   /* The number of constraints on this point */
4033   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4034   PetscScalar    *a;
4035   PetscInt        off, cind = 0, k;
4036   PetscErrorCode  ierr;
4037 
4038   PetscFunctionBegin;
4039   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4040   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4041   a    = &array[off];
4042   if (!cdof || setBC) {
4043     if (clperm) {
4044       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4045       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4046     } else {
4047       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4048       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4049     }
4050   } else {
4051     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4052     if (clperm) {
4053       if (perm) {for (k = 0; k < dof; ++k) {
4054           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4055           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4056         }
4057       } else {
4058         for (k = 0; k < dof; ++k) {
4059           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4060           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4061         }
4062       }
4063     } else {
4064       if (perm) {
4065         for (k = 0; k < dof; ++k) {
4066           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4067           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4068         }
4069       } else {
4070         for (k = 0; k < dof; ++k) {
4071           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4072           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4073         }
4074       }
4075     }
4076   }
4077   PetscFunctionReturn(0);
4078 }
4079 
4080 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[])
4081 {
4082   PetscInt        cdof;   /* The number of constraints on this point */
4083   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4084   PetscScalar    *a;
4085   PetscInt        off, cind = 0, k;
4086   PetscErrorCode  ierr;
4087 
4088   PetscFunctionBegin;
4089   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4090   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4091   a    = &array[off];
4092   if (cdof) {
4093     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4094     if (clperm) {
4095       if (perm) {
4096         for (k = 0; k < dof; ++k) {
4097           if ((cind < cdof) && (k == cdofs[cind])) {
4098             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4099             cind++;
4100           }
4101         }
4102       } else {
4103         for (k = 0; k < dof; ++k) {
4104           if ((cind < cdof) && (k == cdofs[cind])) {
4105             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4106             cind++;
4107           }
4108         }
4109       }
4110     } else {
4111       if (perm) {
4112         for (k = 0; k < dof; ++k) {
4113           if ((cind < cdof) && (k == cdofs[cind])) {
4114             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4115             cind++;
4116           }
4117         }
4118       } else {
4119         for (k = 0; k < dof; ++k) {
4120           if ((cind < cdof) && (k == cdofs[cind])) {
4121             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4122             cind++;
4123           }
4124         }
4125       }
4126     }
4127   }
4128   PetscFunctionReturn(0);
4129 }
4130 
4131 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[])
4132 {
4133   PetscScalar    *a;
4134   PetscInt        fdof, foff, fcdof, foffset = *offset;
4135   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4136   PetscInt        cind = 0, b;
4137   PetscErrorCode  ierr;
4138 
4139   PetscFunctionBegin;
4140   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4141   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4142   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4143   a    = &array[foff];
4144   if (!fcdof || setBC) {
4145     if (clperm) {
4146       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4147       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4148     } else {
4149       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4150       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4151     }
4152   } else {
4153     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4154     if (clperm) {
4155       if (perm) {
4156         for (b = 0; b < fdof; b++) {
4157           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4158           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4159         }
4160       } else {
4161         for (b = 0; b < fdof; b++) {
4162           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4163           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4164         }
4165       }
4166     } else {
4167       if (perm) {
4168         for (b = 0; b < fdof; b++) {
4169           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4170           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4171         }
4172       } else {
4173         for (b = 0; b < fdof; b++) {
4174           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4175           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4176         }
4177       }
4178     }
4179   }
4180   *offset += fdof;
4181   PetscFunctionReturn(0);
4182 }
4183 
4184 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[])
4185 {
4186   PetscScalar    *a;
4187   PetscInt        fdof, foff, fcdof, foffset = *offset;
4188   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4189   PetscInt        cind = 0, b;
4190   PetscErrorCode  ierr;
4191 
4192   PetscFunctionBegin;
4193   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4194   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4195   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4196   a    = &array[foff];
4197   if (fcdof) {
4198     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4199     if (clperm) {
4200       if (perm) {
4201         for (b = 0; b < fdof; b++) {
4202           if ((cind < fcdof) && (b == fcdofs[cind])) {
4203             fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4204             ++cind;
4205           }
4206         }
4207       } else {
4208         for (b = 0; b < fdof; b++) {
4209           if ((cind < fcdof) && (b == fcdofs[cind])) {
4210             fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4211             ++cind;
4212           }
4213         }
4214       }
4215     } else {
4216       if (perm) {
4217         for (b = 0; b < fdof; b++) {
4218           if ((cind < fcdof) && (b == fcdofs[cind])) {
4219             fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4220             ++cind;
4221           }
4222         }
4223       } else {
4224         for (b = 0; b < fdof; b++) {
4225           if ((cind < fcdof) && (b == fcdofs[cind])) {
4226             fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4227             ++cind;
4228           }
4229         }
4230       }
4231     }
4232   }
4233   *offset += fdof;
4234   PetscFunctionReturn(0);
4235 }
4236 
4237 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4238 {
4239   PetscScalar    *array;
4240   const PetscInt *cone, *coneO;
4241   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4242   PetscErrorCode  ierr;
4243 
4244   PetscFunctionBeginHot;
4245   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4246   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4247   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4248   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4249   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4250   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4251     const PetscInt cp = !p ? point : cone[p-1];
4252     const PetscInt o  = !p ? 0     : coneO[p-1];
4253 
4254     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4255     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4256     /* ADD_VALUES */
4257     {
4258       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4259       PetscScalar    *a;
4260       PetscInt        cdof, coff, cind = 0, k;
4261 
4262       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
4263       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
4264       a    = &array[coff];
4265       if (!cdof) {
4266         if (o >= 0) {
4267           for (k = 0; k < dof; ++k) {
4268             a[k] += values[off+k];
4269           }
4270         } else {
4271           for (k = 0; k < dof; ++k) {
4272             a[k] += values[off+dof-k-1];
4273           }
4274         }
4275       } else {
4276         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
4277         if (o >= 0) {
4278           for (k = 0; k < dof; ++k) {
4279             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4280             a[k] += values[off+k];
4281           }
4282         } else {
4283           for (k = 0; k < dof; ++k) {
4284             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4285             a[k] += values[off+dof-k-1];
4286           }
4287         }
4288       }
4289     }
4290   }
4291   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4292   PetscFunctionReturn(0);
4293 }
4294 
4295 /*@C
4296   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4297 
4298   Not collective
4299 
4300   Input Parameters:
4301 + dm - The DM
4302 . section - The section describing the layout in v, or NULL to use the default section
4303 . v - The local vector
4304 . point - The sieve point in the DM
4305 . values - The array of values
4306 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
4307 
4308   Fortran Notes:
4309   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4310 
4311   Level: intermediate
4312 
4313 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4314 @*/
4315 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4316 {
4317   PetscSection    clSection;
4318   IS              clPoints;
4319   PetscScalar    *array;
4320   PetscInt       *points = NULL;
4321   const PetscInt *clp, *clperm;
4322   PetscInt        depth, numFields, numPoints, p;
4323   PetscErrorCode  ierr;
4324 
4325   PetscFunctionBeginHot;
4326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4327   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4328   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4329   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4330   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4331   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4332   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4333     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
4334     PetscFunctionReturn(0);
4335   }
4336   /* Get points */
4337   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
4338   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4339   /* Get array */
4340   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4341   /* Get values */
4342   if (numFields > 0) {
4343     PetscInt offset = 0, f;
4344     for (f = 0; f < numFields; ++f) {
4345       const PetscInt    **perms = NULL;
4346       const PetscScalar **flips = NULL;
4347 
4348       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4349       switch (mode) {
4350       case INSERT_VALUES:
4351         for (p = 0; p < numPoints; p++) {
4352           const PetscInt    point = points[2*p];
4353           const PetscInt    *perm = perms ? perms[p] : NULL;
4354           const PetscScalar *flip = flips ? flips[p] : NULL;
4355           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4356         } break;
4357       case INSERT_ALL_VALUES:
4358         for (p = 0; p < numPoints; p++) {
4359           const PetscInt    point = points[2*p];
4360           const PetscInt    *perm = perms ? perms[p] : NULL;
4361           const PetscScalar *flip = flips ? flips[p] : NULL;
4362           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4363         } break;
4364       case INSERT_BC_VALUES:
4365         for (p = 0; p < numPoints; p++) {
4366           const PetscInt    point = points[2*p];
4367           const PetscInt    *perm = perms ? perms[p] : NULL;
4368           const PetscScalar *flip = flips ? flips[p] : NULL;
4369           updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4370         } break;
4371       case ADD_VALUES:
4372         for (p = 0; p < numPoints; p++) {
4373           const PetscInt    point = points[2*p];
4374           const PetscInt    *perm = perms ? perms[p] : NULL;
4375           const PetscScalar *flip = flips ? flips[p] : NULL;
4376           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4377         } break;
4378       case ADD_ALL_VALUES:
4379         for (p = 0; p < numPoints; p++) {
4380           const PetscInt    point = points[2*p];
4381           const PetscInt    *perm = perms ? perms[p] : NULL;
4382           const PetscScalar *flip = flips ? flips[p] : NULL;
4383           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4384         } break;
4385       case ADD_BC_VALUES:
4386         for (p = 0; p < numPoints; p++) {
4387           const PetscInt    point = points[2*p];
4388           const PetscInt    *perm = perms ? perms[p] : NULL;
4389           const PetscScalar *flip = flips ? flips[p] : NULL;
4390           updatePointFieldsBC_private(section, point, perm, flip, f, add, clperm, values, &offset, array);
4391         } break;
4392       default:
4393         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4394       }
4395       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4396     }
4397   } else {
4398     PetscInt dof, off;
4399     const PetscInt    **perms = NULL;
4400     const PetscScalar **flips = NULL;
4401 
4402     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4403     switch (mode) {
4404     case INSERT_VALUES:
4405       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4406         const PetscInt    point = points[2*p];
4407         const PetscInt    *perm = perms ? perms[p] : NULL;
4408         const PetscScalar *flip = flips ? flips[p] : NULL;
4409         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4410         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4411       } break;
4412     case INSERT_ALL_VALUES:
4413       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4414         const PetscInt    point = points[2*p];
4415         const PetscInt    *perm = perms ? perms[p] : NULL;
4416         const PetscScalar *flip = flips ? flips[p] : NULL;
4417         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4418         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4419       } break;
4420     case INSERT_BC_VALUES:
4421       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4422         const PetscInt    point = points[2*p];
4423         const PetscInt    *perm = perms ? perms[p] : NULL;
4424         const PetscScalar *flip = flips ? flips[p] : NULL;
4425         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4426         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4427       } break;
4428     case ADD_VALUES:
4429       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4430         const PetscInt    point = points[2*p];
4431         const PetscInt    *perm = perms ? perms[p] : NULL;
4432         const PetscScalar *flip = flips ? flips[p] : NULL;
4433         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4434         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4435       } break;
4436     case ADD_ALL_VALUES:
4437       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4438         const PetscInt    point = points[2*p];
4439         const PetscInt    *perm = perms ? perms[p] : NULL;
4440         const PetscScalar *flip = flips ? flips[p] : NULL;
4441         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4442         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4443       } break;
4444     case ADD_BC_VALUES:
4445       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4446         const PetscInt    point = points[2*p];
4447         const PetscInt    *perm = perms ? perms[p] : NULL;
4448         const PetscScalar *flip = flips ? flips[p] : NULL;
4449         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4450         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4451       } break;
4452     default:
4453       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4454     }
4455     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4456   }
4457   /* Cleanup points */
4458   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4459   /* Cleanup array */
4460   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4461   PetscFunctionReturn(0);
4462 }
4463 
4464 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4465 {
4466   PetscSection      clSection;
4467   IS                clPoints;
4468   PetscScalar       *array;
4469   PetscInt          *points = NULL;
4470   const PetscInt    *clp, *clperm;
4471   PetscInt          numFields, numPoints, p;
4472   PetscInt          offset = 0, f;
4473   PetscErrorCode    ierr;
4474 
4475   PetscFunctionBeginHot;
4476   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4477   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4478   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4479   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4480   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4481   /* Get points */
4482   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
4483   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4484   /* Get array */
4485   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4486   /* Get values */
4487   for (f = 0; f < numFields; ++f) {
4488     const PetscInt    **perms = NULL;
4489     const PetscScalar **flips = NULL;
4490 
4491     if (!fieldActive[f]) {
4492       for (p = 0; p < numPoints*2; p += 2) {
4493         PetscInt fdof;
4494         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4495         offset += fdof;
4496       }
4497       continue;
4498     }
4499     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4500     switch (mode) {
4501     case INSERT_VALUES:
4502       for (p = 0; p < numPoints; p++) {
4503         const PetscInt    point = points[2*p];
4504         const PetscInt    *perm = perms ? perms[p] : NULL;
4505         const PetscScalar *flip = flips ? flips[p] : NULL;
4506         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4507       } break;
4508     case INSERT_ALL_VALUES:
4509       for (p = 0; p < numPoints; p++) {
4510         const PetscInt    point = points[2*p];
4511         const PetscInt    *perm = perms ? perms[p] : NULL;
4512         const PetscScalar *flip = flips ? flips[p] : NULL;
4513         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4514         } break;
4515     case INSERT_BC_VALUES:
4516       for (p = 0; p < numPoints; p++) {
4517         const PetscInt    point = points[2*p];
4518         const PetscInt    *perm = perms ? perms[p] : NULL;
4519         const PetscScalar *flip = flips ? flips[p] : NULL;
4520         updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4521       } break;
4522     case ADD_VALUES:
4523       for (p = 0; p < numPoints; p++) {
4524         const PetscInt    point = points[2*p];
4525         const PetscInt    *perm = perms ? perms[p] : NULL;
4526         const PetscScalar *flip = flips ? flips[p] : NULL;
4527         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4528       } break;
4529     case ADD_ALL_VALUES:
4530       for (p = 0; p < numPoints; p++) {
4531         const PetscInt    point = points[2*p];
4532         const PetscInt    *perm = perms ? perms[p] : NULL;
4533         const PetscScalar *flip = flips ? flips[p] : NULL;
4534         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4535       } break;
4536     default:
4537       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4538     }
4539     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4540   }
4541   /* Cleanup points */
4542   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4543   /* Cleanup array */
4544   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4545   PetscFunctionReturn(0);
4546 }
4547 
4548 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4549 {
4550   PetscMPIInt    rank;
4551   PetscInt       i, j;
4552   PetscErrorCode ierr;
4553 
4554   PetscFunctionBegin;
4555   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
4556   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
4557   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
4558   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
4559   numCIndices = numCIndices ? numCIndices : numRIndices;
4560   for (i = 0; i < numRIndices; i++) {
4561     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
4562     for (j = 0; j < numCIndices; j++) {
4563 #if defined(PETSC_USE_COMPLEX)
4564       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
4565 #else
4566       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
4567 #endif
4568     }
4569     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
4570   }
4571   PetscFunctionReturn(0);
4572 }
4573 
4574 /* . off - The global offset of this point */
4575 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4576 {
4577   PetscInt        dof;    /* The number of unknowns on this point */
4578   PetscInt        cdof;   /* The number of constraints on this point */
4579   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4580   PetscInt        cind = 0, k;
4581   PetscErrorCode  ierr;
4582 
4583   PetscFunctionBegin;
4584   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4585   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4586   if (!cdof || setBC) {
4587     if (perm) {
4588       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4589     } else {
4590       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4591     }
4592   } else {
4593     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4594     if (perm) {
4595       for (k = 0; k < dof; ++k) {
4596         if ((cind < cdof) && (k == cdofs[cind])) {
4597           /* Insert check for returning constrained indices */
4598           indices[*loff+perm[k]] = -(off+k+1);
4599           ++cind;
4600         } else {
4601           indices[*loff+perm[k]] = off+k-cind;
4602         }
4603       }
4604     } else {
4605       for (k = 0; k < dof; ++k) {
4606         if ((cind < cdof) && (k == cdofs[cind])) {
4607           /* Insert check for returning constrained indices */
4608           indices[*loff+k] = -(off+k+1);
4609           ++cind;
4610         } else {
4611           indices[*loff+k] = off+k-cind;
4612         }
4613       }
4614     }
4615   }
4616   *loff += dof;
4617   PetscFunctionReturn(0);
4618 }
4619 
4620 /* . off - The global offset of this point */
4621 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4622 {
4623   PetscInt       numFields, foff, f;
4624   PetscErrorCode ierr;
4625 
4626   PetscFunctionBegin;
4627   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4628   for (f = 0, foff = 0; f < numFields; ++f) {
4629     PetscInt        fdof, cfdof;
4630     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4631     PetscInt        cind = 0, b;
4632     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4633 
4634     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4635     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
4636     if (!cfdof || setBC) {
4637       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4638       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4639     } else {
4640       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4641       if (perm) {
4642         for (b = 0; b < fdof; b++) {
4643           if ((cind < cfdof) && (b == fcdofs[cind])) {
4644             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4645             ++cind;
4646           } else {
4647             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4648           }
4649         }
4650       } else {
4651         for (b = 0; b < fdof; b++) {
4652           if ((cind < cfdof) && (b == fcdofs[cind])) {
4653             indices[foffs[f]+b] = -(off+foff+b+1);
4654             ++cind;
4655           } else {
4656             indices[foffs[f]+b] = off+foff+b-cind;
4657           }
4658         }
4659       }
4660     }
4661     foff     += (setBC ? fdof : (fdof - cfdof));
4662     foffs[f] += fdof;
4663   }
4664   PetscFunctionReturn(0);
4665 }
4666 
4667 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)
4668 {
4669   Mat             cMat;
4670   PetscSection    aSec, cSec;
4671   IS              aIS;
4672   PetscInt        aStart = -1, aEnd = -1;
4673   const PetscInt  *anchors;
4674   PetscInt        numFields, f, p, q, newP = 0;
4675   PetscInt        newNumPoints = 0, newNumIndices = 0;
4676   PetscInt        *newPoints, *indices, *newIndices;
4677   PetscInt        maxAnchor, maxDof;
4678   PetscInt        newOffsets[32];
4679   PetscInt        *pointMatOffsets[32];
4680   PetscInt        *newPointOffsets[32];
4681   PetscScalar     *pointMat[32];
4682   PetscScalar     *newValues=NULL,*tmpValues;
4683   PetscBool       anyConstrained = PETSC_FALSE;
4684   PetscErrorCode  ierr;
4685 
4686   PetscFunctionBegin;
4687   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4688   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4689   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4690 
4691   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
4692   /* if there are point-to-point constraints */
4693   if (aSec) {
4694     ierr = PetscMemzero(newOffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4695     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
4696     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
4697     /* figure out how many points are going to be in the new element matrix
4698      * (we allow double counting, because it's all just going to be summed
4699      * into the global matrix anyway) */
4700     for (p = 0; p < 2*numPoints; p+=2) {
4701       PetscInt b    = points[p];
4702       PetscInt bDof = 0, bSecDof;
4703 
4704       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
4705       if (!bSecDof) {
4706         continue;
4707       }
4708       if (b >= aStart && b < aEnd) {
4709         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
4710       }
4711       if (bDof) {
4712         /* this point is constrained */
4713         /* it is going to be replaced by its anchors */
4714         PetscInt bOff, q;
4715 
4716         anyConstrained = PETSC_TRUE;
4717         newNumPoints  += bDof;
4718         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
4719         for (q = 0; q < bDof; q++) {
4720           PetscInt a = anchors[bOff + q];
4721           PetscInt aDof;
4722 
4723           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
4724           newNumIndices += aDof;
4725           for (f = 0; f < numFields; ++f) {
4726             PetscInt fDof;
4727 
4728             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
4729             newOffsets[f+1] += fDof;
4730           }
4731         }
4732       }
4733       else {
4734         /* this point is not constrained */
4735         newNumPoints++;
4736         newNumIndices += bSecDof;
4737         for (f = 0; f < numFields; ++f) {
4738           PetscInt fDof;
4739 
4740           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4741           newOffsets[f+1] += fDof;
4742         }
4743       }
4744     }
4745   }
4746   if (!anyConstrained) {
4747     if (outNumPoints)  *outNumPoints  = 0;
4748     if (outNumIndices) *outNumIndices = 0;
4749     if (outPoints)     *outPoints     = NULL;
4750     if (outValues)     *outValues     = NULL;
4751     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
4752     PetscFunctionReturn(0);
4753   }
4754 
4755   if (outNumPoints)  *outNumPoints  = newNumPoints;
4756   if (outNumIndices) *outNumIndices = newNumIndices;
4757 
4758   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
4759 
4760   if (!outPoints && !outValues) {
4761     if (offsets) {
4762       for (f = 0; f <= numFields; f++) {
4763         offsets[f] = newOffsets[f];
4764       }
4765     }
4766     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
4767     PetscFunctionReturn(0);
4768   }
4769 
4770   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
4771 
4772   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
4773 
4774   /* workspaces */
4775   if (numFields) {
4776     for (f = 0; f < numFields; f++) {
4777       ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
4778       ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr);
4779     }
4780   }
4781   else {
4782     ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
4783     ierr = DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr);
4784   }
4785 
4786   /* get workspaces for the point-to-point matrices */
4787   if (numFields) {
4788     PetscInt totalOffset, totalMatOffset;
4789 
4790     for (p = 0; p < numPoints; p++) {
4791       PetscInt b    = points[2*p];
4792       PetscInt bDof = 0, bSecDof;
4793 
4794       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
4795       if (!bSecDof) {
4796         for (f = 0; f < numFields; f++) {
4797           newPointOffsets[f][p + 1] = 0;
4798           pointMatOffsets[f][p + 1] = 0;
4799         }
4800         continue;
4801       }
4802       if (b >= aStart && b < aEnd) {
4803         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4804       }
4805       if (bDof) {
4806         for (f = 0; f < numFields; f++) {
4807           PetscInt fDof, q, bOff, allFDof = 0;
4808 
4809           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4810           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4811           for (q = 0; q < bDof; q++) {
4812             PetscInt a = anchors[bOff + q];
4813             PetscInt aFDof;
4814 
4815             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
4816             allFDof += aFDof;
4817           }
4818           newPointOffsets[f][p+1] = allFDof;
4819           pointMatOffsets[f][p+1] = fDof * allFDof;
4820         }
4821       }
4822       else {
4823         for (f = 0; f < numFields; f++) {
4824           PetscInt fDof;
4825 
4826           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4827           newPointOffsets[f][p+1] = fDof;
4828           pointMatOffsets[f][p+1] = 0;
4829         }
4830       }
4831     }
4832     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4833       newPointOffsets[f][0] = totalOffset;
4834       pointMatOffsets[f][0] = totalMatOffset;
4835       for (p = 0; p < numPoints; p++) {
4836         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4837         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4838       }
4839       totalOffset    = newPointOffsets[f][numPoints];
4840       totalMatOffset = pointMatOffsets[f][numPoints];
4841       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr);
4842     }
4843   }
4844   else {
4845     for (p = 0; p < numPoints; p++) {
4846       PetscInt b    = points[2*p];
4847       PetscInt bDof = 0, bSecDof;
4848 
4849       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
4850       if (!bSecDof) {
4851         newPointOffsets[0][p + 1] = 0;
4852         pointMatOffsets[0][p + 1] = 0;
4853         continue;
4854       }
4855       if (b >= aStart && b < aEnd) {
4856         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4857       }
4858       if (bDof) {
4859         PetscInt bOff, q, allDof = 0;
4860 
4861         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4862         for (q = 0; q < bDof; q++) {
4863           PetscInt a = anchors[bOff + q], aDof;
4864 
4865           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
4866           allDof += aDof;
4867         }
4868         newPointOffsets[0][p+1] = allDof;
4869         pointMatOffsets[0][p+1] = bSecDof * allDof;
4870       }
4871       else {
4872         newPointOffsets[0][p+1] = bSecDof;
4873         pointMatOffsets[0][p+1] = 0;
4874       }
4875     }
4876     newPointOffsets[0][0] = 0;
4877     pointMatOffsets[0][0] = 0;
4878     for (p = 0; p < numPoints; p++) {
4879       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4880       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4881     }
4882     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr);
4883   }
4884 
4885   /* output arrays */
4886   ierr = DMGetWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
4887 
4888   /* get the point-to-point matrices; construct newPoints */
4889   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
4890   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4891   ierr = DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr);
4892   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr);
4893   if (numFields) {
4894     for (p = 0, newP = 0; p < numPoints; p++) {
4895       PetscInt b    = points[2*p];
4896       PetscInt o    = points[2*p+1];
4897       PetscInt bDof = 0, bSecDof;
4898 
4899       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
4900       if (!bSecDof) {
4901         continue;
4902       }
4903       if (b >= aStart && b < aEnd) {
4904         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4905       }
4906       if (bDof) {
4907         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
4908 
4909         fStart[0] = 0;
4910         fEnd[0]   = 0;
4911         for (f = 0; f < numFields; f++) {
4912           PetscInt fDof;
4913 
4914           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
4915           fStart[f+1] = fStart[f] + fDof;
4916           fEnd[f+1]   = fStart[f+1];
4917         }
4918         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
4919         ierr = DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);CHKERRQ(ierr);
4920 
4921         fAnchorStart[0] = 0;
4922         fAnchorEnd[0]   = 0;
4923         for (f = 0; f < numFields; f++) {
4924           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
4925 
4926           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4927           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4928         }
4929         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4930         for (q = 0; q < bDof; q++) {
4931           PetscInt a = anchors[bOff + q], aOff;
4932 
4933           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4934           newPoints[2*(newP + q)]     = a;
4935           newPoints[2*(newP + q) + 1] = 0;
4936           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
4937           ierr = DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);CHKERRQ(ierr);
4938         }
4939         newP += bDof;
4940 
4941         if (outValues) {
4942           /* get the point-to-point submatrix */
4943           for (f = 0; f < numFields; f++) {
4944             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
4945           }
4946         }
4947       }
4948       else {
4949         newPoints[2 * newP]     = b;
4950         newPoints[2 * newP + 1] = o;
4951         newP++;
4952       }
4953     }
4954   } else {
4955     for (p = 0; p < numPoints; p++) {
4956       PetscInt b    = points[2*p];
4957       PetscInt o    = points[2*p+1];
4958       PetscInt bDof = 0, bSecDof;
4959 
4960       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
4961       if (!bSecDof) {
4962         continue;
4963       }
4964       if (b >= aStart && b < aEnd) {
4965         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4966       }
4967       if (bDof) {
4968         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
4969 
4970         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
4971         ierr = DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);CHKERRQ(ierr);
4972 
4973         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
4974         for (q = 0; q < bDof; q++) {
4975           PetscInt a = anchors[bOff + q], aOff;
4976 
4977           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4978 
4979           newPoints[2*(newP + q)]     = a;
4980           newPoints[2*(newP + q) + 1] = 0;
4981           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
4982           ierr = DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);CHKERRQ(ierr);
4983         }
4984         newP += bDof;
4985 
4986         /* get the point-to-point submatrix */
4987         if (outValues) {
4988           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
4989         }
4990       }
4991       else {
4992         newPoints[2 * newP]     = b;
4993         newPoints[2 * newP + 1] = o;
4994         newP++;
4995       }
4996     }
4997   }
4998 
4999   if (outValues) {
5000     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr);
5001     ierr = PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));CHKERRQ(ierr);
5002     /* multiply constraints on the right */
5003     if (numFields) {
5004       for (f = 0; f < numFields; f++) {
5005         PetscInt oldOff = offsets[f];
5006 
5007         for (p = 0; p < numPoints; p++) {
5008           PetscInt cStart = newPointOffsets[f][p];
5009           PetscInt b      = points[2 * p];
5010           PetscInt c, r, k;
5011           PetscInt dof;
5012 
5013           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5014           if (!dof) {
5015             continue;
5016           }
5017           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5018             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5019             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5020 
5021             for (r = 0; r < numIndices; r++) {
5022               for (c = 0; c < nCols; c++) {
5023                 for (k = 0; k < dof; k++) {
5024                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5025                 }
5026               }
5027             }
5028           }
5029           else {
5030             /* copy this column as is */
5031             for (r = 0; r < numIndices; r++) {
5032               for (c = 0; c < dof; c++) {
5033                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5034               }
5035             }
5036           }
5037           oldOff += dof;
5038         }
5039       }
5040     }
5041     else {
5042       PetscInt oldOff = 0;
5043       for (p = 0; p < numPoints; p++) {
5044         PetscInt cStart = newPointOffsets[0][p];
5045         PetscInt b      = points[2 * p];
5046         PetscInt c, r, k;
5047         PetscInt dof;
5048 
5049         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5050         if (!dof) {
5051           continue;
5052         }
5053         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5054           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5055           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5056 
5057           for (r = 0; r < numIndices; r++) {
5058             for (c = 0; c < nCols; c++) {
5059               for (k = 0; k < dof; k++) {
5060                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5061               }
5062             }
5063           }
5064         }
5065         else {
5066           /* copy this column as is */
5067           for (r = 0; r < numIndices; r++) {
5068             for (c = 0; c < dof; c++) {
5069               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5070             }
5071           }
5072         }
5073         oldOff += dof;
5074       }
5075     }
5076 
5077     if (multiplyLeft) {
5078       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr);
5079       ierr = PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));CHKERRQ(ierr);
5080       /* multiply constraints transpose on the left */
5081       if (numFields) {
5082         for (f = 0; f < numFields; f++) {
5083           PetscInt oldOff = offsets[f];
5084 
5085           for (p = 0; p < numPoints; p++) {
5086             PetscInt rStart = newPointOffsets[f][p];
5087             PetscInt b      = points[2 * p];
5088             PetscInt c, r, k;
5089             PetscInt dof;
5090 
5091             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5092             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5093               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
5094               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5095 
5096               for (r = 0; r < nRows; r++) {
5097                 for (c = 0; c < newNumIndices; c++) {
5098                   for (k = 0; k < dof; k++) {
5099                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5100                   }
5101                 }
5102               }
5103             }
5104             else {
5105               /* copy this row as is */
5106               for (r = 0; r < dof; r++) {
5107                 for (c = 0; c < newNumIndices; c++) {
5108                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5109                 }
5110               }
5111             }
5112             oldOff += dof;
5113           }
5114         }
5115       }
5116       else {
5117         PetscInt oldOff = 0;
5118 
5119         for (p = 0; p < numPoints; p++) {
5120           PetscInt rStart = newPointOffsets[0][p];
5121           PetscInt b      = points[2 * p];
5122           PetscInt c, r, k;
5123           PetscInt dof;
5124 
5125           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5126           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5127             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
5128             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5129 
5130             for (r = 0; r < nRows; r++) {
5131               for (c = 0; c < newNumIndices; c++) {
5132                 for (k = 0; k < dof; k++) {
5133                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5134                 }
5135               }
5136             }
5137           }
5138           else {
5139             /* copy this row as is */
5140             for (r = 0; r < dof; r++) {
5141               for (c = 0; c < newNumIndices; c++) {
5142                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5143               }
5144             }
5145           }
5146           oldOff += dof;
5147         }
5148       }
5149 
5150       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr);
5151     }
5152     else {
5153       newValues = tmpValues;
5154     }
5155   }
5156 
5157   /* clean up */
5158   ierr = DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr);
5159   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr);
5160 
5161   if (numFields) {
5162     for (f = 0; f < numFields; f++) {
5163       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr);
5164       ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
5165       ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr);
5166     }
5167   }
5168   else {
5169     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr);
5170     ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
5171     ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr);
5172   }
5173   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
5174 
5175   /* output */
5176   if (outPoints) {
5177     *outPoints = newPoints;
5178   }
5179   else {
5180     ierr = DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
5181   }
5182   if (outValues) {
5183     *outValues = newValues;
5184   }
5185   for (f = 0; f <= numFields; f++) {
5186     offsets[f] = newOffsets[f];
5187   }
5188   PetscFunctionReturn(0);
5189 }
5190 
5191 /*@C
5192   DMPlexGetClosureIndices - Get the indices in a vector v for all points in the closure of the given point
5193 
5194   Not collective
5195 
5196   Input Parameters:
5197 + dm - The DM
5198 . section - The section describing the layout in v, or NULL to use the default section
5199 . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5200 - point - The mesh point
5201 
5202   Output parameters:
5203 + numIndices - The number of indices
5204 . indices - The indices
5205 - outOffsets - Field offset if not NULL
5206 
5207   Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5208 
5209   Level: advanced
5210 
5211 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5212 @*/
5213 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5214 {
5215   PetscSection    clSection;
5216   IS              clPoints;
5217   const PetscInt *clp;
5218   const PetscInt  **perms[32] = {NULL};
5219   PetscInt       *points = NULL, *pointsNew;
5220   PetscInt        numPoints, numPointsNew;
5221   PetscInt        offsets[32];
5222   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5223   PetscErrorCode  ierr;
5224 
5225   PetscFunctionBegin;
5226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5227   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5228   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5229   if (numIndices) PetscValidPointer(numIndices, 4);
5230   PetscValidPointer(indices, 5);
5231   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
5232   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5233   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5234   /* Get points in closure */
5235   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5236   /* Get number of indices and indices per field */
5237   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5238     PetscInt dof, fdof;
5239 
5240     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5241     for (f = 0; f < Nf; ++f) {
5242       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5243       offsets[f+1] += fdof;
5244     }
5245     Nind += dof;
5246   }
5247   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5248   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5249   if (!Nf) offsets[1] = Nind;
5250   /* Get dual space symmetries */
5251   for (f = 0; f < PetscMax(1,Nf); f++) {
5252     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5253     else    {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5254   }
5255   /* Correct for hanging node constraints */
5256   {
5257     ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
5258     if (numPointsNew) {
5259       for (f = 0; f < PetscMax(1,Nf); f++) {
5260         if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5261         else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5262       }
5263       for (f = 0; f < PetscMax(1,Nf); f++) {
5264         if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
5265         else    {ierr = PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
5266       }
5267       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5268       numPoints = numPointsNew;
5269       Nind      = NindNew;
5270       points    = pointsNew;
5271     }
5272   }
5273   /* Calculate indices */
5274   ierr = DMGetWorkArray(dm, Nind, PETSC_INT, indices);CHKERRQ(ierr);
5275   if (Nf) {
5276     if (outOffsets) {
5277       PetscInt f;
5278 
5279       for (f = 0; f <= Nf; f++) {
5280         outOffsets[f] = offsets[f];
5281       }
5282     }
5283     for (p = 0; p < numPoints; p++) {
5284       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5285       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5286     }
5287   } else {
5288     for (p = 0, off = 0; p < numPoints; p++) {
5289       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5290 
5291       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5292       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5293     }
5294   }
5295   /* Cleanup points */
5296   for (f = 0; f < PetscMax(1,Nf); f++) {
5297     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5298     else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5299   }
5300   if (numPointsNew) {
5301     ierr = DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);CHKERRQ(ierr);
5302   } else {
5303     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5304   }
5305   if (numIndices) *numIndices = Nind;
5306   PetscFunctionReturn(0);
5307 }
5308 
5309 /*@C
5310   DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5311 
5312   Not collective
5313 
5314   Input Parameters:
5315 + dm - The DM
5316 . section - The section describing the layout in v, or NULL to use the default section
5317 . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5318 . point - The mesh point
5319 . numIndices - The number of indices
5320 . indices - The indices
5321 - outOffsets - Field offset if not NULL
5322 
5323   Level: advanced
5324 
5325 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5326 @*/
5327 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5328 {
5329   PetscErrorCode ierr;
5330 
5331   PetscFunctionBegin;
5332   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5333   PetscValidPointer(indices, 5);
5334   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, indices);CHKERRQ(ierr);
5335   PetscFunctionReturn(0);
5336 }
5337 
5338 /*@C
5339   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5340 
5341   Not collective
5342 
5343   Input Parameters:
5344 + dm - The DM
5345 . section - The section describing the layout in v, or NULL to use the default section
5346 . globalSection - The section describing the layout in v, or NULL to use the default global section
5347 . A - The matrix
5348 . point - The sieve point in the DM
5349 . values - The array of values
5350 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5351 
5352   Fortran Notes:
5353   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5354 
5355   Level: intermediate
5356 
5357 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5358 @*/
5359 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5360 {
5361   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5362   PetscSection        clSection;
5363   IS                  clPoints;
5364   PetscInt           *points = NULL, *newPoints;
5365   const PetscInt     *clp;
5366   PetscInt           *indices;
5367   PetscInt            offsets[32];
5368   const PetscInt    **perms[32] = {NULL};
5369   const PetscScalar **flips[32] = {NULL};
5370   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5371   PetscScalar        *valCopy = NULL;
5372   PetscScalar        *newValues;
5373   PetscErrorCode      ierr;
5374 
5375   PetscFunctionBegin;
5376   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5377   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
5378   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5379   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
5380   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5381   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
5382   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5383   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5384   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5385   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5386   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5387     PetscInt fdof;
5388 
5389     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5390     for (f = 0; f < numFields; ++f) {
5391       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5392       offsets[f+1] += fdof;
5393     }
5394     numIndices += dof;
5395   }
5396   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5397 
5398   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5399   /* Get symmetries */
5400   for (f = 0; f < PetscMax(1,numFields); f++) {
5401     if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5402     else           {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5403     if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5404       PetscInt foffset = offsets[f];
5405 
5406       for (p = 0; p < numPoints; p++) {
5407         PetscInt point          = points[2*p], fdof;
5408         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5409 
5410         if (!numFields) {
5411           ierr = PetscSectionGetDof(section,point,&fdof);CHKERRQ(ierr);
5412         } else {
5413           ierr = PetscSectionGetFieldDof(section,point,f,&fdof);CHKERRQ(ierr);
5414         }
5415         if (flip) {
5416           PetscInt i, j, k;
5417 
5418           if (!valCopy) {
5419             ierr = DMGetWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);CHKERRQ(ierr);
5420             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5421             values = valCopy;
5422           }
5423           for (i = 0; i < fdof; i++) {
5424             PetscScalar fval = flip[i];
5425 
5426             for (k = 0; k < numIndices; k++) {
5427               valCopy[numIndices * (foffset + i) + k] *= fval;
5428               valCopy[numIndices * k + (foffset + i)] *= fval;
5429             }
5430           }
5431         }
5432         foffset += fdof;
5433       }
5434     }
5435   }
5436   ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr);
5437   if (newNumPoints) {
5438     if (valCopy) {
5439       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);CHKERRQ(ierr);
5440     }
5441     for (f = 0; f < PetscMax(1,numFields); f++) {
5442       if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5443       else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5444     }
5445     for (f = 0; f < PetscMax(1,numFields); f++) {
5446       if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
5447       else           {ierr = PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
5448     }
5449     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5450     numPoints  = newNumPoints;
5451     numIndices = newNumIndices;
5452     points     = newPoints;
5453     values     = newValues;
5454   }
5455   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5456   if (numFields) {
5457     for (p = 0; p < numPoints; p++) {
5458       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5459       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5460     }
5461   } else {
5462     for (p = 0, off = 0; p < numPoints; p++) {
5463       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5464       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5465       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5466     }
5467   }
5468   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
5469   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5470   if (mesh->printFEM > 1) {
5471     PetscInt i;
5472     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
5473     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
5474     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5475   }
5476   if (ierr) {
5477     PetscMPIInt    rank;
5478     PetscErrorCode ierr2;
5479 
5480     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5481     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5482     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5483     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5484     CHKERRQ(ierr);
5485   }
5486   for (f = 0; f < PetscMax(1,numFields); f++) {
5487     if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5488     else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5489   }
5490   if (newNumPoints) {
5491     ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr);
5492     ierr = DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
5493   }
5494   else {
5495     if (valCopy) {
5496       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);CHKERRQ(ierr);
5497     }
5498     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5499   }
5500   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5501   PetscFunctionReturn(0);
5502 }
5503 
5504 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5505 {
5506   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5507   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5508   PetscInt       *cpoints = NULL;
5509   PetscInt       *findices, *cindices;
5510   PetscInt        foffsets[32], coffsets[32];
5511   CellRefiner     cellRefiner;
5512   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5513   PetscErrorCode  ierr;
5514 
5515   PetscFunctionBegin;
5516   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
5517   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
5518   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
5519   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
5520   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
5521   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
5522   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
5523   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
5524   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
5525   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
5526   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
5527   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
5528   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5529   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5530   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5531   /* Column indices */
5532   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5533   maxFPoints = numCPoints;
5534   /* Compress out points not in the section */
5535   /*   TODO: Squeeze out points with 0 dof as well */
5536   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
5537   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5538     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5539       cpoints[q*2]   = cpoints[p];
5540       cpoints[q*2+1] = cpoints[p+1];
5541       ++q;
5542     }
5543   }
5544   numCPoints = q;
5545   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5546     PetscInt fdof;
5547 
5548     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
5549     if (!dof) continue;
5550     for (f = 0; f < numFields; ++f) {
5551       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
5552       coffsets[f+1] += fdof;
5553     }
5554     numCIndices += dof;
5555   }
5556   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5557   /* Row indices */
5558   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
5559   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
5560   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5561   for (r = 0, q = 0; r < numSubcells; ++r) {
5562     /* TODO Map from coarse to fine cells */
5563     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5564     /* Compress out points not in the section */
5565     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
5566     for (p = 0; p < numFPoints*2; p += 2) {
5567       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5568         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
5569         if (!dof) continue;
5570         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5571         if (s < q) continue;
5572         ftotpoints[q*2]   = fpoints[p];
5573         ftotpoints[q*2+1] = fpoints[p+1];
5574         ++q;
5575       }
5576     }
5577     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5578   }
5579   numFPoints = q;
5580   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5581     PetscInt fdof;
5582 
5583     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
5584     if (!dof) continue;
5585     for (f = 0; f < numFields; ++f) {
5586       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
5587       foffsets[f+1] += fdof;
5588     }
5589     numFIndices += dof;
5590   }
5591   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5592 
5593   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5594   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5595   ierr = DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
5596   ierr = DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
5597   if (numFields) {
5598     const PetscInt **permsF[32] = {NULL};
5599     const PetscInt **permsC[32] = {NULL};
5600 
5601     for (f = 0; f < numFields; f++) {
5602       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
5603       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
5604     }
5605     for (p = 0; p < numFPoints; p++) {
5606       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
5607       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5608     }
5609     for (p = 0; p < numCPoints; p++) {
5610       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
5611       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5612     }
5613     for (f = 0; f < numFields; f++) {
5614       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
5615       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
5616     }
5617   } else {
5618     const PetscInt **permsF = NULL;
5619     const PetscInt **permsC = NULL;
5620 
5621     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
5622     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
5623     for (p = 0, off = 0; p < numFPoints; p++) {
5624       const PetscInt *perm = permsF ? permsF[p] : NULL;
5625 
5626       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
5627       ierr = DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);CHKERRQ(ierr);
5628     }
5629     for (p = 0, off = 0; p < numCPoints; p++) {
5630       const PetscInt *perm = permsC ? permsC[p] : NULL;
5631 
5632       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
5633       ierr = DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);CHKERRQ(ierr);
5634     }
5635     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
5636     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
5637   }
5638   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
5639   /* TODO: flips */
5640   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5641   if (ierr) {
5642     PetscMPIInt    rank;
5643     PetscErrorCode ierr2;
5644 
5645     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5646     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5647     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5648     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5649     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5650     CHKERRQ(ierr);
5651   }
5652   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5653   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5654   ierr = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
5655   ierr = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
5656   PetscFunctionReturn(0);
5657 }
5658 
5659 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5660 {
5661   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5662   PetscInt      *cpoints = NULL;
5663   PetscInt       foffsets[32], coffsets[32];
5664   CellRefiner    cellRefiner;
5665   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5666   PetscErrorCode ierr;
5667 
5668   PetscFunctionBegin;
5669   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
5670   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
5671   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
5672   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
5673   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
5674   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
5675   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
5676   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
5677   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
5678   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
5679   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
5680   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5681   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5682   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5683   /* Column indices */
5684   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5685   maxFPoints = numCPoints;
5686   /* Compress out points not in the section */
5687   /*   TODO: Squeeze out points with 0 dof as well */
5688   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
5689   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5690     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5691       cpoints[q*2]   = cpoints[p];
5692       cpoints[q*2+1] = cpoints[p+1];
5693       ++q;
5694     }
5695   }
5696   numCPoints = q;
5697   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5698     PetscInt fdof;
5699 
5700     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
5701     if (!dof) continue;
5702     for (f = 0; f < numFields; ++f) {
5703       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
5704       coffsets[f+1] += fdof;
5705     }
5706     numCIndices += dof;
5707   }
5708   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5709   /* Row indices */
5710   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
5711   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
5712   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5713   for (r = 0, q = 0; r < numSubcells; ++r) {
5714     /* TODO Map from coarse to fine cells */
5715     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5716     /* Compress out points not in the section */
5717     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
5718     for (p = 0; p < numFPoints*2; p += 2) {
5719       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5720         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
5721         if (!dof) continue;
5722         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5723         if (s < q) continue;
5724         ftotpoints[q*2]   = fpoints[p];
5725         ftotpoints[q*2+1] = fpoints[p+1];
5726         ++q;
5727       }
5728     }
5729     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5730   }
5731   numFPoints = q;
5732   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5733     PetscInt fdof;
5734 
5735     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
5736     if (!dof) continue;
5737     for (f = 0; f < numFields; ++f) {
5738       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
5739       foffsets[f+1] += fdof;
5740     }
5741     numFIndices += dof;
5742   }
5743   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5744 
5745   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5746   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5747   if (numFields) {
5748     const PetscInt **permsF[32] = {NULL};
5749     const PetscInt **permsC[32] = {NULL};
5750 
5751     for (f = 0; f < numFields; f++) {
5752       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
5753       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
5754     }
5755     for (p = 0; p < numFPoints; p++) {
5756       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
5757       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5758     }
5759     for (p = 0; p < numCPoints; p++) {
5760       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
5761       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5762     }
5763     for (f = 0; f < numFields; f++) {
5764       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
5765       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
5766     }
5767   } else {
5768     const PetscInt **permsF = NULL;
5769     const PetscInt **permsC = NULL;
5770 
5771     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
5772     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
5773     for (p = 0, off = 0; p < numFPoints; p++) {
5774       const PetscInt *perm = permsF ? permsF[p] : NULL;
5775 
5776       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
5777       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5778     }
5779     for (p = 0, off = 0; p < numCPoints; p++) {
5780       const PetscInt *perm = permsC ? permsC[p] : NULL;
5781 
5782       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
5783       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5784     }
5785     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
5786     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
5787   }
5788   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5789   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5790   PetscFunctionReturn(0);
5791 }
5792 
5793 /*@
5794   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
5795 
5796   Input Parameter:
5797 . dm - The DMPlex object
5798 
5799   Output Parameters:
5800 + cMax - The first hybrid cell
5801 . fMax - The first hybrid face
5802 . eMax - The first hybrid edge
5803 - vMax - The first hybrid vertex
5804 
5805   Level: developer
5806 
5807 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5808 @*/
5809 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5810 {
5811   DM_Plex       *mesh = (DM_Plex*) dm->data;
5812   PetscInt       dim;
5813   PetscErrorCode ierr;
5814 
5815   PetscFunctionBegin;
5816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5817   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5818   if (cMax) *cMax = mesh->hybridPointMax[dim];
5819   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5820   if (eMax) *eMax = mesh->hybridPointMax[1];
5821   if (vMax) *vMax = mesh->hybridPointMax[0];
5822   PetscFunctionReturn(0);
5823 }
5824 
5825 /*@
5826   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
5827 
5828   Input Parameters:
5829 . dm   - The DMPlex object
5830 . cMax - The first hybrid cell
5831 . fMax - The first hybrid face
5832 . eMax - The first hybrid edge
5833 - vMax - The first hybrid vertex
5834 
5835   Level: developer
5836 
5837 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5838 @*/
5839 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5840 {
5841   DM_Plex       *mesh = (DM_Plex*) dm->data;
5842   PetscInt       dim;
5843   PetscErrorCode ierr;
5844 
5845   PetscFunctionBegin;
5846   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5847   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5848   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5849   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5850   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5851   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5852   PetscFunctionReturn(0);
5853 }
5854 
5855 /*@C
5856   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
5857 
5858   Input Parameter:
5859 . dm   - The DMPlex object
5860 
5861   Output Parameter:
5862 . cellHeight - The height of a cell
5863 
5864   Level: developer
5865 
5866 .seealso DMPlexSetVTKCellHeight()
5867 @*/
5868 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5869 {
5870   DM_Plex *mesh = (DM_Plex*) dm->data;
5871 
5872   PetscFunctionBegin;
5873   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5874   PetscValidPointer(cellHeight, 2);
5875   *cellHeight = mesh->vtkCellHeight;
5876   PetscFunctionReturn(0);
5877 }
5878 
5879 /*@C
5880   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
5881 
5882   Input Parameters:
5883 + dm   - The DMPlex object
5884 - cellHeight - The height of a cell
5885 
5886   Level: developer
5887 
5888 .seealso DMPlexGetVTKCellHeight()
5889 @*/
5890 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5891 {
5892   DM_Plex *mesh = (DM_Plex*) dm->data;
5893 
5894   PetscFunctionBegin;
5895   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5896   mesh->vtkCellHeight = cellHeight;
5897   PetscFunctionReturn(0);
5898 }
5899 
5900 /* We can easily have a form that takes an IS instead */
5901 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5902 {
5903   PetscSection   section, globalSection;
5904   PetscInt      *numbers, p;
5905   PetscErrorCode ierr;
5906 
5907   PetscFunctionBegin;
5908   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
5909   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
5910   for (p = pStart; p < pEnd; ++p) {
5911     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
5912   }
5913   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
5914   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
5915   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
5916   for (p = pStart; p < pEnd; ++p) {
5917     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
5918     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5919     else                       numbers[p-pStart] += shift;
5920   }
5921   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
5922   if (globalSize) {
5923     PetscLayout layout;
5924     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
5925     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
5926     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
5927   }
5928   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5929   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
5930   PetscFunctionReturn(0);
5931 }
5932 
5933 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5934 {
5935   PetscInt       cellHeight, cStart, cEnd, cMax;
5936   PetscErrorCode ierr;
5937 
5938   PetscFunctionBegin;
5939   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
5940   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5941   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5942   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5943   ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
5944   PetscFunctionReturn(0);
5945 }
5946 
5947 /*@C
5948   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
5949 
5950   Input Parameter:
5951 . dm   - The DMPlex object
5952 
5953   Output Parameter:
5954 . globalCellNumbers - Global cell numbers for all cells on this process
5955 
5956   Level: developer
5957 
5958 .seealso DMPlexGetVertexNumbering()
5959 @*/
5960 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5961 {
5962   DM_Plex       *mesh = (DM_Plex*) dm->data;
5963   PetscErrorCode ierr;
5964 
5965   PetscFunctionBegin;
5966   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5967   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
5968   *globalCellNumbers = mesh->globalCellNumbers;
5969   PetscFunctionReturn(0);
5970 }
5971 
5972 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
5973 {
5974   PetscInt       vStart, vEnd, vMax;
5975   PetscErrorCode ierr;
5976 
5977   PetscFunctionBegin;
5978   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5979   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5980   ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
5981   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
5982   ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
5983   PetscFunctionReturn(0);
5984 }
5985 
5986 /*@C
5987   DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process
5988 
5989   Input Parameter:
5990 . dm   - The DMPlex object
5991 
5992   Output Parameter:
5993 . globalVertexNumbers - Global vertex numbers for all vertices on this process
5994 
5995   Level: developer
5996 
5997 .seealso DMPlexGetCellNumbering()
5998 @*/
5999 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6000 {
6001   DM_Plex       *mesh = (DM_Plex*) dm->data;
6002   PetscErrorCode ierr;
6003 
6004   PetscFunctionBegin;
6005   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6006   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
6007   *globalVertexNumbers = mesh->globalVertexNumbers;
6008   PetscFunctionReturn(0);
6009 }
6010 
6011 /*@C
6012   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6013 
6014   Input Parameter:
6015 . dm   - The DMPlex object
6016 
6017   Output Parameter:
6018 . globalPointNumbers - Global numbers for all points on this process
6019 
6020   Level: developer
6021 
6022 .seealso DMPlexGetCellNumbering()
6023 @*/
6024 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6025 {
6026   IS             nums[4];
6027   PetscInt       depths[4];
6028   PetscInt       depth, d, shift = 0;
6029   PetscErrorCode ierr;
6030 
6031   PetscFunctionBegin;
6032   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6033   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6034   /* For unstratified meshes use dim instead of depth */
6035   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
6036   depths[0] = depth; depths[1] = 0;
6037   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6038   for (d = 0; d <= depth; ++d) {
6039     PetscInt pStart, pEnd, gsize;
6040 
6041     ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr);
6042     ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
6043     shift += gsize;
6044   }
6045   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
6046   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
6047   PetscFunctionReturn(0);
6048 }
6049 
6050 /*@
6051   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6052 
6053   Input Parameters:
6054   + dm - The DMPlex object
6055 
6056   Note: This is a useful diagnostic when creating meshes programmatically.
6057 
6058   Level: developer
6059 
6060 .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6061 @*/
6062 PetscErrorCode DMPlexCheckSymmetry(DM dm)
6063 {
6064   PetscSection    coneSection, supportSection;
6065   const PetscInt *cone, *support;
6066   PetscInt        coneSize, c, supportSize, s;
6067   PetscInt        pStart, pEnd, p, csize, ssize;
6068   PetscErrorCode  ierr;
6069 
6070   PetscFunctionBegin;
6071   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6072   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
6073   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
6074   /* Check that point p is found in the support of its cone points, and vice versa */
6075   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6076   for (p = pStart; p < pEnd; ++p) {
6077     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
6078     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
6079     for (c = 0; c < coneSize; ++c) {
6080       PetscBool dup = PETSC_FALSE;
6081       PetscInt  d;
6082       for (d = c-1; d >= 0; --d) {
6083         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6084       }
6085       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
6086       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
6087       for (s = 0; s < supportSize; ++s) {
6088         if (support[s] == p) break;
6089       }
6090       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6091         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
6092         for (s = 0; s < coneSize; ++s) {
6093           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
6094         }
6095         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6096         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
6097         for (s = 0; s < supportSize; ++s) {
6098           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
6099         }
6100         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6101         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6102         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6103       }
6104     }
6105     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
6106     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
6107     for (s = 0; s < supportSize; ++s) {
6108       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6109       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6110       for (c = 0; c < coneSize; ++c) {
6111         if (cone[c] == p) break;
6112       }
6113       if (c >= coneSize) {
6114         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
6115         for (c = 0; c < supportSize; ++c) {
6116           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
6117         }
6118         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6119         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
6120         for (c = 0; c < coneSize; ++c) {
6121           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
6122         }
6123         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6124         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6125       }
6126     }
6127   }
6128   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
6129   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
6130   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6131   PetscFunctionReturn(0);
6132 }
6133 
6134 /*@
6135   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6136 
6137   Input Parameters:
6138 + dm - The DMPlex object
6139 . isSimplex - Are the cells simplices or tensor products
6140 - cellHeight - Normally 0
6141 
6142   Note: This is a useful diagnostic when creating meshes programmatically.
6143 
6144   Level: developer
6145 
6146 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6147 @*/
6148 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6149 {
6150   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6151   PetscErrorCode ierr;
6152 
6153   PetscFunctionBegin;
6154   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6155   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6156   switch (dim) {
6157   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6158   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6159   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6160   default:
6161     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6162   }
6163   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6164   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6165   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6166   cMax = cMax >= 0 ? cMax : cEnd;
6167   for (c = cStart; c < cMax; ++c) {
6168     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6169 
6170     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6171     for (cl = 0; cl < closureSize*2; cl += 2) {
6172       const PetscInt p = closure[cl];
6173       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6174     }
6175     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6176     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6177   }
6178   for (c = cMax; c < cEnd; ++c) {
6179     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6180 
6181     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6182     for (cl = 0; cl < closureSize*2; cl += 2) {
6183       const PetscInt p = closure[cl];
6184       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6185     }
6186     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6187     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6188   }
6189   PetscFunctionReturn(0);
6190 }
6191 
6192 /*@
6193   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6194 
6195   Input Parameters:
6196 + dm - The DMPlex object
6197 . isSimplex - Are the cells simplices or tensor products
6198 - cellHeight - Normally 0
6199 
6200   Note: This is a useful diagnostic when creating meshes programmatically.
6201 
6202   Level: developer
6203 
6204 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6205 @*/
6206 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6207 {
6208   PetscInt       pMax[4];
6209   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;
6210   PetscErrorCode ierr;
6211 
6212   PetscFunctionBegin;
6213   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6214   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6215   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6216   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
6217   for (h = cellHeight; h < dim; ++h) {
6218     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
6219     for (c = cStart; c < cEnd; ++c) {
6220       const PetscInt *cone, *ornt, *faces;
6221       PetscInt        numFaces, faceSize, coneSize,f;
6222       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
6223 
6224       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6225       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6226       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6227       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6228       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6229       for (cl = 0; cl < closureSize*2; cl += 2) {
6230         const PetscInt p = closure[cl];
6231         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6232       }
6233       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
6234       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6235       for (f = 0; f < numFaces; ++f) {
6236         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6237 
6238         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
6239         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6240           const PetscInt p = fclosure[cl];
6241           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6242         }
6243         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);
6244         for (v = 0; v < fnumCorners; ++v) {
6245           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]);
6246         }
6247         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
6248       }
6249       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
6250       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6251     }
6252   }
6253   PetscFunctionReturn(0);
6254 }
6255 
6256 /* Pointwise interpolation
6257      Just code FEM for now
6258      u^f = I u^c
6259      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6260      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6261      I_{ij} = psi^f_i phi^c_j
6262 */
6263 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6264 {
6265   PetscSection   gsc, gsf;
6266   PetscInt       m, n;
6267   void          *ctx;
6268   DM             cdm;
6269   PetscBool      regular;
6270   PetscErrorCode ierr;
6271 
6272   PetscFunctionBegin;
6273   ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
6274   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
6275   ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
6276   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
6277 
6278   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
6279   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6280   ierr = MatSetType(*interpolation, dmCoarse->mattype);CHKERRQ(ierr);
6281   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
6282 
6283   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
6284   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
6285   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
6286   else                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
6287   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
6288   /* Use naive scaling */
6289   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
6290   PetscFunctionReturn(0);
6291 }
6292 
6293 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6294 {
6295   PetscErrorCode ierr;
6296   VecScatter     ctx;
6297 
6298   PetscFunctionBegin;
6299   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
6300   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
6301   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
6302   PetscFunctionReturn(0);
6303 }
6304 
6305 PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6306 {
6307   PetscSection   section;
6308   IS            *bcPoints, *bcComps;
6309   PetscBool     *isFE;
6310   PetscInt      *bcFields, *numComp, *numDof;
6311   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6312   PetscInt       cStart, cEnd, cEndInterior;
6313   PetscErrorCode ierr;
6314 
6315   PetscFunctionBegin;
6316   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
6317   if (!numFields) PetscFunctionReturn(0);
6318   /* FE and FV boundary conditions are handled slightly differently */
6319   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
6320   for (f = 0; f < numFields; ++f) {
6321     PetscObject  obj;
6322     PetscClassId id;
6323 
6324     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
6325     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
6326     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6327     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6328     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6329   }
6330   /* Allocate boundary point storage for FEM boundaries */
6331   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6332   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6333   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6334   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
6335   ierr = PetscDSGetNumBoundary(dm->prob, &numBd);CHKERRQ(ierr);
6336   for (bd = 0; bd < numBd; ++bd) {
6337     PetscInt                field;
6338     DMBoundaryConditionType type;
6339     const char             *labelName;
6340     DMLabel                 label;
6341 
6342     ierr = PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
6343     ierr = DMGetLabel(dm,labelName,&label);CHKERRQ(ierr);
6344     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6345   }
6346   /* Add ghost cell boundaries for FVM */
6347   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6348   ierr = PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);CHKERRQ(ierr);
6349   /* Constrain ghost cells for FV */
6350   for (f = 0; f < numFields; ++f) {
6351     PetscInt *newidx, c;
6352 
6353     if (isFE[f] || cEndInterior < 0) continue;
6354     ierr = PetscMalloc1(cEnd-cEndInterior,&newidx);CHKERRQ(ierr);
6355     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6356     bcFields[bc] = f;
6357     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
6358   }
6359   /* Handle FEM Dirichlet boundaries */
6360   for (bd = 0; bd < numBd; ++bd) {
6361     const char             *bdLabel;
6362     DMLabel                 label;
6363     const PetscInt         *comps;
6364     const PetscInt         *values;
6365     PetscInt                bd2, field, numComps, numValues;
6366     DMBoundaryConditionType type;
6367     PetscBool               duplicate = PETSC_FALSE;
6368 
6369     ierr = PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);CHKERRQ(ierr);
6370     ierr = DMGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
6371     if (!isFE[field] || !label) continue;
6372     /* Only want to modify label once */
6373     for (bd2 = 0; bd2 < bd; ++bd2) {
6374       const char *bdname;
6375       ierr = PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
6376       ierr = PetscStrcmp(bdname, bdLabel, &duplicate);CHKERRQ(ierr);
6377       if (duplicate) break;
6378     }
6379     if (!duplicate && (isFE[field])) {
6380       /* don't complete cells, which are just present to give orientation to the boundary */
6381       ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
6382     }
6383     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6384     if (type & DM_BC_ESSENTIAL) {
6385       PetscInt       *newidx;
6386       PetscInt        n, newn = 0, p, v;
6387 
6388       bcFields[bc] = field;
6389       if (numComps) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);CHKERRQ(ierr);}
6390       for (v = 0; v < numValues; ++v) {
6391         IS              tmp;
6392         const PetscInt *idx;
6393 
6394         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
6395         if (!tmp) continue;
6396         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
6397         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
6398         if (isFE[field]) {
6399           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6400         } else {
6401           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6402         }
6403         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
6404         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
6405       }
6406       ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr);
6407       newn = 0;
6408       for (v = 0; v < numValues; ++v) {
6409         IS              tmp;
6410         const PetscInt *idx;
6411 
6412         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
6413         if (!tmp) continue;
6414         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
6415         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
6416         if (isFE[field]) {
6417           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6418         } else {
6419           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6420         }
6421         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
6422         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
6423       }
6424       ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
6425     }
6426   }
6427   /* Handle discretization */
6428   ierr = PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr);
6429   for (f = 0; f < numFields; ++f) {
6430     PetscObject obj;
6431 
6432     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
6433     if (isFE[f]) {
6434       PetscFE         fe = (PetscFE) obj;
6435       const PetscInt *numFieldDof;
6436       PetscInt        d;
6437 
6438       ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
6439       ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr);
6440       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6441     } else {
6442       PetscFV fv = (PetscFV) obj;
6443 
6444       ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
6445       numDof[f*(dim+1)+dim] = numComp[f];
6446     }
6447   }
6448   for (f = 0; f < numFields; ++f) {
6449     PetscInt d;
6450     for (d = 1; d < dim; ++d) {
6451       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.");
6452     }
6453   }
6454   ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);CHKERRQ(ierr);
6455   for (f = 0; f < numFields; ++f) {
6456     PetscFE     fe;
6457     const char *name;
6458 
6459     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
6460     ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr);
6461     ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr);
6462   }
6463   ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr);
6464   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6465   for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);ierr = ISDestroy(&bcComps[bc]);CHKERRQ(ierr);}
6466   ierr = PetscFree3(bcFields,bcPoints,bcComps);CHKERRQ(ierr);
6467   ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr);
6468   ierr = PetscFree(isFE);CHKERRQ(ierr);
6469   PetscFunctionReturn(0);
6470 }
6471 
6472 /*@
6473   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6474 
6475   Input Parameter:
6476 . dm - The DMPlex object
6477 
6478   Output Parameter:
6479 . regular - The flag
6480 
6481   Level: intermediate
6482 
6483 .seealso: DMPlexSetRegularRefinement()
6484 @*/
6485 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6486 {
6487   PetscFunctionBegin;
6488   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6489   PetscValidPointer(regular, 2);
6490   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6491   PetscFunctionReturn(0);
6492 }
6493 
6494 /*@
6495   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6496 
6497   Input Parameters:
6498 + dm - The DMPlex object
6499 - regular - The flag
6500 
6501   Level: intermediate
6502 
6503 .seealso: DMPlexGetRegularRefinement()
6504 @*/
6505 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6506 {
6507   PetscFunctionBegin;
6508   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6509   ((DM_Plex *) dm->data)->regularRefinement = regular;
6510   PetscFunctionReturn(0);
6511 }
6512 
6513 /* anchors */
6514 /*@
6515   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
6516   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
6517 
6518   not collective
6519 
6520   Input Parameters:
6521 . dm - The DMPlex object
6522 
6523   Output Parameters:
6524 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
6525 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
6526 
6527 
6528   Level: intermediate
6529 
6530 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6531 @*/
6532 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6533 {
6534   DM_Plex *plex = (DM_Plex *)dm->data;
6535   PetscErrorCode ierr;
6536 
6537   PetscFunctionBegin;
6538   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6539   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
6540   if (anchorSection) *anchorSection = plex->anchorSection;
6541   if (anchorIS) *anchorIS = plex->anchorIS;
6542   PetscFunctionReturn(0);
6543 }
6544 
6545 /*@
6546   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
6547   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
6548   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
6549 
6550   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
6551   DMGetConstraints() and filling in the entries in the constraint matrix.
6552 
6553   collective on dm
6554 
6555   Input Parameters:
6556 + dm - The DMPlex object
6557 . 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).
6558 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
6559 
6560   The reference counts of anchorSection and anchorIS are incremented.
6561 
6562   Level: intermediate
6563 
6564 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6565 @*/
6566 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6567 {
6568   DM_Plex        *plex = (DM_Plex *)dm->data;
6569   PetscMPIInt    result;
6570   PetscErrorCode ierr;
6571 
6572   PetscFunctionBegin;
6573   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6574   if (anchorSection) {
6575     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
6576     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
6577     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6578   }
6579   if (anchorIS) {
6580     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
6581     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
6582     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6583   }
6584 
6585   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
6586   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
6587   plex->anchorSection = anchorSection;
6588 
6589   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
6590   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
6591   plex->anchorIS = anchorIS;
6592 
6593 #if defined(PETSC_USE_DEBUG)
6594   if (anchorIS && anchorSection) {
6595     PetscInt size, a, pStart, pEnd;
6596     const PetscInt *anchors;
6597 
6598     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
6599     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
6600     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
6601     for (a = 0; a < size; a++) {
6602       PetscInt p;
6603 
6604       p = anchors[a];
6605       if (p >= pStart && p < pEnd) {
6606         PetscInt dof;
6607 
6608         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
6609         if (dof) {
6610           PetscErrorCode ierr2;
6611 
6612           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6613           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6614         }
6615       }
6616     }
6617     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
6618   }
6619 #endif
6620   /* reset the generic constraints */
6621   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
6622   PetscFunctionReturn(0);
6623 }
6624 
6625 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6626 {
6627   PetscSection anchorSection;
6628   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
6629   PetscErrorCode ierr;
6630 
6631   PetscFunctionBegin;
6632   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6633   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
6634   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
6635   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
6636   if (numFields) {
6637     PetscInt f;
6638     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
6639 
6640     for (f = 0; f < numFields; f++) {
6641       PetscInt numComp;
6642 
6643       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
6644       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
6645     }
6646   }
6647   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
6648   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
6649   pStart = PetscMax(pStart,sStart);
6650   pEnd   = PetscMin(pEnd,sEnd);
6651   pEnd   = PetscMax(pStart,pEnd);
6652   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
6653   for (p = pStart; p < pEnd; p++) {
6654     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
6655     if (dof) {
6656       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
6657       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
6658       for (f = 0; f < numFields; f++) {
6659         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
6660         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
6661       }
6662     }
6663   }
6664   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
6665   PetscFunctionReturn(0);
6666 }
6667 
6668 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6669 {
6670   PetscSection aSec;
6671   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6672   const PetscInt *anchors;
6673   PetscInt numFields, f;
6674   IS aIS;
6675   PetscErrorCode ierr;
6676 
6677   PetscFunctionBegin;
6678   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6679   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
6680   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
6681   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
6682   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
6683   ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr);
6684   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
6685   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
6686   /* cSec will be a subset of aSec and section */
6687   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
6688   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
6689   i[0] = 0;
6690   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
6691   for (p = pStart; p < pEnd; p++) {
6692     PetscInt rDof, rOff, r;
6693 
6694     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
6695     if (!rDof) continue;
6696     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
6697     if (numFields) {
6698       for (f = 0; f < numFields; f++) {
6699         annz = 0;
6700         for (r = 0; r < rDof; r++) {
6701           a = anchors[rOff + r];
6702           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
6703           annz += aDof;
6704         }
6705         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
6706         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
6707         for (q = 0; q < dof; q++) {
6708           i[off + q + 1] = i[off + q] + annz;
6709         }
6710       }
6711     }
6712     else {
6713       annz = 0;
6714       for (q = 0; q < dof; q++) {
6715         a = anchors[off + q];
6716         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6717         annz += aDof;
6718       }
6719       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
6720       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
6721       for (q = 0; q < dof; q++) {
6722         i[off + q + 1] = i[off + q] + annz;
6723       }
6724     }
6725   }
6726   nnz = i[m];
6727   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
6728   offset = 0;
6729   for (p = pStart; p < pEnd; p++) {
6730     if (numFields) {
6731       for (f = 0; f < numFields; f++) {
6732         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
6733         for (q = 0; q < dof; q++) {
6734           PetscInt rDof, rOff, r;
6735           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
6736           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
6737           for (r = 0; r < rDof; r++) {
6738             PetscInt s;
6739 
6740             a = anchors[rOff + r];
6741             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
6742             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
6743             for (s = 0; s < aDof; s++) {
6744               j[offset++] = aOff + s;
6745             }
6746           }
6747         }
6748       }
6749     }
6750     else {
6751       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
6752       for (q = 0; q < dof; q++) {
6753         PetscInt rDof, rOff, r;
6754         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
6755         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
6756         for (r = 0; r < rDof; r++) {
6757           PetscInt s;
6758 
6759           a = anchors[rOff + r];
6760           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6761           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
6762           for (s = 0; s < aDof; s++) {
6763             j[offset++] = aOff + s;
6764           }
6765         }
6766       }
6767     }
6768   }
6769   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
6770   ierr = PetscFree(i);CHKERRQ(ierr);
6771   ierr = PetscFree(j);CHKERRQ(ierr);
6772   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
6773   PetscFunctionReturn(0);
6774 }
6775 
6776 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6777 {
6778   DM_Plex        *plex = (DM_Plex *)dm->data;
6779   PetscSection   anchorSection, section, cSec;
6780   Mat            cMat;
6781   PetscErrorCode ierr;
6782 
6783   PetscFunctionBegin;
6784   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6785   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
6786   if (anchorSection) {
6787     PetscDS  ds;
6788     PetscInt nf;
6789 
6790     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
6791     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
6792     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
6793     ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
6794     ierr = PetscDSGetNumFields(ds,&nf);CHKERRQ(ierr);
6795     if (nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
6796     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
6797     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
6798     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
6799   }
6800   PetscFunctionReturn(0);
6801 }
6802