Actual source code: plex.c

petsc-master 2017-02-27
Report Typos and Errors
  1:  #include <petsc/private/dmpleximpl.h>
  2:  #include <petsc/private/isimpl.h>
  3:  #include <petsc/private/vecimpl.h>
  4:  #include <petscsf.h>
  5:  #include <petscds.h>
  6:  #include <petscdraw.h>

  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;

 11: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
 12: PETSC_EXTERN PetscErrorCode VecLoad_Default(Vec, PetscViewer);

 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;

 20:   *ft  = PETSC_VTK_POINT_FIELD;
 21:   DMGetDimension(dm, &dim);
 22:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
 23:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
 24:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
 25:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
 26:   PetscSectionGetChart(section, &pStart, &pEnd);
 27:   if (field >= 0) {
 28:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vdof);}
 29:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &cdof);}
 30:   } else {
 31:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vdof);}
 32:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &cdof);}
 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:   return(0);
 46: }

 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;

 66:   PetscViewerDrawGetDraw(viewer, 0, &draw);
 67:   PetscDrawIsNull(draw, &isnull);
 68:   if (isnull) return(0);

 70:   VecGetDM(v, &dm);
 71:   DMGetCoordinateDim(dm, &dim);
 72:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
 73:   DMGetDefaultSection(dm, &s);
 74:   PetscSectionGetNumFields(s, &Nf);
 75:   DMGetCoarsenLevel(dm, &level);
 76:   DMGetCoordinateDM(dm, &cdm);
 77:   DMGetDefaultSection(cdm, &coordSection);
 78:   DMGetCoordinatesLocal(dm, &coordinates);
 79:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
 80:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

 82:   PetscObjectGetName((PetscObject) v, &name);
 83:   DMGetOutputSequenceNumber(dm, &step, &time);

 85:   VecGetLocalSize(coordinates, &N);
 86:   VecGetArrayRead(coordinates, &coords);
 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:   VecRestoreArrayRead(coordinates, &coords);
 92:   PetscDrawClear(draw);

 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;

102:     PetscSectionGetFieldComponents(s, f, &Nc);
103:     PetscSectionGetFieldName(s, f, &fname);

105:     if (v->hdr.prefix) {PetscStrcpy(prefix, v->hdr.prefix);}
106:     else               {prefix[0] = '\0';}
107:     if (Nf > 1) {
108:       DMCreateSubDM(dm, 1, &f, &fis, &fdm);
109:       VecGetSubVector(v, fis, &fv);
110:       PetscStrcat(prefix, fname);
111:       PetscStrcat(prefix, "_");
112:     }
113:     for (comp = 0; comp < Nc; ++comp, ++w) {
114:       PetscInt nmax = 2;

116:       PetscViewerDrawGetDraw(viewer, w, &draw);
117:       if (Nc > 1) {PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);}
118:       else        {PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);}
119:       PetscDrawSetTitle(draw, title);

121:       /* TODO Get max and min only for this component */
122:       PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
123:       if (!flg) {
124:         VecMin(fv, NULL, &vbound[0]);
125:         VecMax(fv, NULL, &vbound[1]);
126:         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
127:       }
128:       PetscDrawGetPopup(draw, &popup);
129:       PetscDrawScalePopup(popup, vbound[0], vbound[1]);
130:       PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);

132:       VecGetArrayRead(fv, &array);
133:       for (c = cStart; c < cEnd; ++c) {
134:         PetscScalar *coords = NULL, *a = NULL;
135:         PetscInt     numCoords, color[4];

137:         DMPlexPointLocalRead(fdm, c, array, &a);
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;

145:           DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
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:           DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
159:         }
160:         DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
161:         switch (numCoords) {
162:         case 6:
163:           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]);
164:           break;
165:         case 8:
166:           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]);
167:           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]);
168:           break;
169:         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
170:         }
171:         DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
172:       }
173:       VecRestoreArrayRead(fv, &array);
174:       PetscDrawFlush(draw);
175:       PetscDrawPause(draw);
176:       PetscDrawSave(draw);
177:     }
178:     if (Nf > 1) {
179:       VecRestoreSubVector(v, fis, &fv);
180:       ISDestroy(&fis);
181:       DMDestroy(&fdm);
182:     }
183:   }
184:   return(0);
185: }

187: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
188: {
189:   DM             dm;
190:   PetscBool      isvtk, ishdf5, isdraw, isseq;

194:   VecGetDM(v, &dm);
195:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
196:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
197:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
198:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
199:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
200:   if (isvtk || ishdf5) {
201:     PetscInt  numFields;
202:     PetscBool fem = PETSC_FALSE;

204:     DMGetNumFields(dm, &numFields);
205:     if (numFields) {
206:       PetscObject fe;

208:       DMGetField(dm, 0, &fe);
209:       if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE;
210:     }
211:     if (fem) {DMPlexInsertBoundaryValues(dm, PETSC_TRUE, v, 0.0, NULL, NULL, NULL);}
212:   }
213:   if (isvtk) {
214:     PetscSection            section;
215:     PetscViewerVTKFieldType ft;
216:     PetscInt                pStart, pEnd;

218:     DMGetDefaultSection(dm, &section);
219:     DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
220:     PetscObjectReference((PetscObject) v);  /* viewer drops reference */
221:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
222:   } else if (ishdf5) {
223: #if defined(PETSC_HAVE_HDF5)
224:     VecView_Plex_Local_HDF5_Internal(v, viewer);
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:     VecView_Plex_Local_Draw(v, viewer);
230:   } else {
231:     if (isseq) {VecView_Seq(v, viewer);}
232:     else       {VecView_MPI(v, viewer);}
233:   }
234:   return(0);
235: }

237: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
238: {
239:   DM             dm;
240:   PetscReal      time = 0.0;
241:   PetscBool      isvtk, ishdf5, isdraw, isseq;

245:   VecGetDM(v, &dm);
246:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
247:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
248:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
249:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
250:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
251:   if (isvtk) {
252:     Vec         locv;
253:     const char *name;

255:     DMGetLocalVector(dm, &locv);
256:     PetscObjectGetName((PetscObject) v, &name);
257:     PetscObjectSetName((PetscObject) locv, name);
258:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
259:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
260:     DMGetOutputSequenceNumber(dm, NULL, &time);
261:     DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
262:     VecView_Plex_Local(locv, viewer);
263:     DMRestoreLocalVector(dm, &locv);
264:   } else if (ishdf5) {
265: #if defined(PETSC_HAVE_HDF5)
266:     VecView_Plex_HDF5_Internal(v, viewer);
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;

274:     DMGetLocalVector(dm, &locv);
275:     PetscObjectGetName((PetscObject) v, &name);
276:     PetscObjectSetName((PetscObject) locv, name);
277:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
278:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
279:     DMGetOutputSequenceNumber(dm, NULL, &time);
280:     DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
281:     VecView_Plex_Local(locv, viewer);
282:     DMRestoreLocalVector(dm, &locv);
283:   } else {
284:     if (isseq) {VecView_Seq(v, viewer);}
285:     else       {VecView_MPI(v, viewer);}
286:   }
287:   return(0);
288: }

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;

300:   VecGetDM(originalv, &dm);
301:   PetscObjectGetComm((PetscObject) originalv, &comm);
302:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
303:   PetscViewerGetFormat(viewer, &format);
304:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
305:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
306:   if (format == PETSC_VIEWER_NATIVE) {
307:     const char *vecname;
308:     PetscInt    n, nroots;

310:     if (dm->sfNatural) {
311:       VecGetLocalSize(originalv, &n);
312:       PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
313:       if (n == nroots) {
314:         DMGetGlobalVector(dm, &v);
315:         DMPlexGlobalToNaturalBegin(dm, originalv, v);
316:         DMPlexGlobalToNaturalEnd(dm, originalv, v);
317:         PetscObjectGetName((PetscObject) originalv, &vecname);
318:         PetscObjectSetName((PetscObject) v, vecname);
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:     VecView_Plex_HDF5_Native_Internal(v, viewer);
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;

336:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
337:     if (isseq) {VecView_Seq(v, viewer);}
338:     else       {VecView_MPI(v, viewer);}
339:   }
340:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
341:   return(0);
342: }

344: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
345: {
346:   DM             dm;
347:   PetscBool      ishdf5;

351:   VecGetDM(v, &dm);
352:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
353:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
354:   if (ishdf5) {
355:     DM          dmBC;
356:     Vec         gv;
357:     const char *name;

359:     DMGetOutputDM(dm, &dmBC);
360:     DMGetGlobalVector(dmBC, &gv);
361:     PetscObjectGetName((PetscObject) v, &name);
362:     PetscObjectSetName((PetscObject) gv, name);
363:     VecLoad_Default(gv, viewer);
364:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
365:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
366:     DMRestoreGlobalVector(dmBC, &gv);
367:   } else {
368:     VecLoad_Default(v, viewer);
369:   }
370:   return(0);
371: }

373: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
374: {
375:   DM             dm;
376:   PetscBool      ishdf5;

380:   VecGetDM(v, &dm);
381:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
382:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
383:   if (ishdf5) {
384: #if defined(PETSC_HAVE_HDF5)
385:     VecLoad_Plex_HDF5_Internal(v, viewer);
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:     VecLoad_Default(v, viewer);
391:   }
392:   return(0);
393: }

395: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
396: {
397:   DM                dm;
398:   PetscViewerFormat format;
399:   PetscBool         ishdf5;
400:   PetscErrorCode    ierr;

403:   VecGetDM(originalv, &dm);
404:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
405:   PetscViewerGetFormat(viewer, &format);
406:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
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;

414:         DMGetGlobalVector(dm, &v);
415:         PetscObjectGetName((PetscObject) originalv, &vecname);
416:         PetscObjectSetName((PetscObject) v, vecname);
417:         VecLoad_Plex_HDF5_Native_Internal(v, viewer);
418:         DMPlexNaturalToGlobalBegin(dm, v, originalv);
419:         DMPlexNaturalToGlobalEnd(dm, v, originalv);
420:         DMRestoreGlobalVector(dm, &v);
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:   return(0);
428: }

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;

441:   DMGetDimension(dm, &dim);
442:   DMGetCoordinatesLocal(dm, &coordinates);
443:   DMGetCoordinateSection(dm, &coordSection);
444:   DMPlexGetDepthLabel(dm, &depthLabel);
445:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
446:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
447:   VecGetArrayRead(coordinates, &a);
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;

456:     PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);
457:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
458:     PetscViewerASCIIPushTab(viewer);
459:     for (cl = 0; cl < closureSize*2; cl += 2) {
460:       PetscInt point = closure[cl], depth, dof, off, d, p;

462:       if ((point < pStart) || (point >= pEnd)) continue;
463:       PetscSectionGetDof(coordSection, point, &dof);
464:       if (!dof) continue;
465:       DMLabelGetValue(depthLabel, point, &depth);
466:       PetscSectionGetOffset(coordSection, point, &off);
467:       PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
468:       for (p = 0; p < dof/dim; ++p) {
469:         PetscViewerASCIIPrintf(viewer, " (");
470:         for (d = 0; d < dim; ++d) {
471:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
472:           PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
473:         }
474:         PetscViewerASCIIPrintf(viewer, ")");
475:       }
476:       PetscViewerASCIIPrintf(viewer, "\n");
477:     }
478:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
479:     PetscViewerASCIIPopTab(viewer);
480:   }
481:   VecRestoreArrayRead(coordinates, &a);
482:   return(0);
483: }

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;

496:   DMGetCoordinateDM(dm, &cdm);
497:   DMGetDefaultSection(cdm, &coordSection);
498:   DMGetCoordinatesLocal(dm, &coordinates);
499:   PetscViewerGetFormat(viewer, &format);
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;

506:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
507:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
508:     PetscObjectGetName((PetscObject) dm, &name);
509:     DMPlexGetChart(dm, &pStart, &pEnd);
510:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
511:     PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);
512:     PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
513:     PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
514:     PetscViewerASCIIPushSynchronized(viewer);
515:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);
516:     for (p = pStart; p < pEnd; ++p) {
517:       PetscInt dof, off, s;

519:       PetscSectionGetDof(mesh->supportSection, p, &dof);
520:       PetscSectionGetOffset(mesh->supportSection, p, &off);
521:       for (s = off; s < off+dof; ++s) {
522:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
523:       }
524:     }
525:     PetscViewerFlush(viewer);
526:     PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
527:     for (p = pStart; p < pEnd; ++p) {
528:       PetscInt dof, off, c;

530:       PetscSectionGetDof(mesh->coneSection, p, &dof);
531:       PetscSectionGetOffset(mesh->coneSection, p, &off);
532:       for (c = off; c < off+dof; ++c) {
533:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
534:       }
535:     }
536:     PetscViewerFlush(viewer);
537:     PetscViewerASCIIPopSynchronized(viewer);
538:     PetscSectionGetChart(coordSection, &pStart, NULL);
539:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
540:     DMGetLabel(dm, "marker", &markers);
541:     DMLabelView(markers,viewer);
542:     if (size > 1) {
543:       PetscSF sf;

545:       DMGetPointSF(dm, &sf);
546:       PetscSFView(sf, viewer);
547:     }
548:     PetscViewerFlush(viewer);
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;

561:     DMGetDimension(dm, &dim);
562:     DMPlexGetDepth(dm, &depth);
563:     DMGetNumLabels(dm, &numLabels);
564:     numLabels  = PetscMax(numLabels, 10);
565:     numColors  = 10;
566:     numLColors = 10;
567:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
568:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
569:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
570:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
571:     if (!useLabels) numLabels = 0;
572:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
573:     if (!useColors) {
574:       numColors = 3;
575:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
576:     }
577:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
578:     if (!useColors) {
579:       numLColors = 4;
580:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
581:     }
582:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
583:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
584:     PetscObjectGetName((PetscObject) dm, &name);
585:     PetscViewerASCIIPrintf(viewer, "\
586: \\documentclass[tikz]{standalone}\n\n\
587: \\usepackage{pgflibraryshapes}\n\
588: \\usetikzlibrary{backgrounds}\n\
589: \\usetikzlibrary{arrows}\n\
590: \\begin{document}\n");
591:     if (size > 1) {
592:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
593:       for (p = 0; p < size; ++p) {
594:         if (p > 0 && p == size-1) {
595:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
596:         } else if (p > 0) {
597:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
598:         }
599:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
600:       }
601:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
602:     }
603:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);
604:     /* Plot vertices */
605:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
606:     VecGetArray(coordinates, &coords);
607:     PetscViewerASCIIPushSynchronized(viewer);
608:     for (v = vStart; v < vEnd; ++v) {
609:       PetscInt  off, dof, d;
610:       PetscBool isLabeled = PETSC_FALSE;

612:       PetscSectionGetDof(coordSection, v, &dof);
613:       PetscSectionGetOffset(coordSection, v, &off);
614:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
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) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
624:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
625:       }
626:       color = colors[rank%numColors];
627:       for (l = 0; l < numLabels; ++l) {
628:         PetscInt val;
629:         DMGetLabelValue(dm, names[l], v, &val);
630:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
631:       }
632:       if (useNumbers) {
633:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
634:       } else {
635:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
636:       }
637:     }
638:     VecRestoreArray(coordinates, &coords);
639:     PetscViewerFlush(viewer);
640:     /* Plot edges */
641:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
642:     if (dim < 3 && useNumbers) {
643:       VecGetArray(coordinates, &coords);
644:       PetscViewerASCIIPrintf(viewer, "\\path\n");
645:       for (e = eStart; e < eEnd; ++e) {
646:         const PetscInt *cone;
647:         PetscInt        coneSize, offA, offB, dof, d;

649:         DMPlexGetConeSize(dm, e, &coneSize);
650:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
651:         DMPlexGetCone(dm, e, &cone);
652:         PetscSectionGetDof(coordSection, cone[0], &dof);
653:         PetscSectionGetOffset(coordSection, cone[0], &offA);
654:         PetscSectionGetOffset(coordSection, cone[1], &offB);
655:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
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) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
664:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
665:         }
666:         color = colors[rank%numColors];
667:         for (l = 0; l < numLabels; ++l) {
668:           PetscInt val;
669:           DMGetLabelValue(dm, names[l], v, &val);
670:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
671:         }
672:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
673:       }
674:       VecRestoreArray(coordinates, &coords);
675:       PetscViewerFlush(viewer);
676:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
677:     }
678:     /* Plot cells */
679:     if (dim == 3 || !useNumbers) {
680:       for (e = eStart; e < eEnd; ++e) {
681:         const PetscInt *cone;

683:         color = colors[rank%numColors];
684:         for (l = 0; l < numLabels; ++l) {
685:           PetscInt val;
686:           DMGetLabelValue(dm, names[l], e, &val);
687:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
688:         }
689:         DMPlexGetCone(dm, e, &cone);
690:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
691:       }
692:     } else {
693:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
694:       for (c = cStart; c < cEnd; ++c) {
695:         PetscInt *closure = NULL;
696:         PetscInt  closureSize, firstPoint = -1;

698:         DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
699:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
700:         for (p = 0; p < closureSize*2; p += 2) {
701:           const PetscInt point = closure[p];

703:           if ((point < vStart) || (point >= vEnd)) continue;
704:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
705:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
706:           if (firstPoint < 0) firstPoint = point;
707:         }
708:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
709:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
710:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
711:       }
712:     }
713:     PetscViewerFlush(viewer);
714:     PetscViewerASCIIPopSynchronized(viewer);
715:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
716:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
717:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
718:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
719:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
720:     PetscFree3(names, colors, lcolors);
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;

730:     PetscObjectGetComm((PetscObject)dm,&comm);
731:     MPI_Comm_size(comm, &size);
732:     DMGetDimension(dm, &dim);
733:     PetscObjectGetName((PetscObject) dm, &name);
734:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);}
735:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);}
736:     DMPlexGetDepth(dm, &locDepth);
737:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
738:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
739:     PetscMalloc2(size,&sizes,size,&hybsizes);
740:     if (depth == 1) {
741:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
742:       pEnd = pEnd - pStart;
743:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
744:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
745:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
746:       PetscViewerASCIIPrintf(viewer, "\n");
747:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
748:       pEnd = pEnd - pStart;
749:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
750:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
751:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
752:       PetscViewerASCIIPrintf(viewer, "\n");
753:     } else {
754:       PetscMPIInt rank;
755:       MPI_Comm_rank(comm, &rank);
756:       for (d = 0; d <= dim; d++) {
757:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
758:         pEnd    -= pStart;
759:         pMax[d] -= pStart;
760:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
761:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
762:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
763:         for (p = 0; p < size; ++p) {
764:           if (!rank) {
765:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
766:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
767:           }
768:         }
769:         PetscViewerASCIIPrintf(viewer, "\n");
770:       }
771:     }
772:     PetscFree2(sizes,hybsizes);
773:     DMGetNumLabels(dm, &numLabels);
774:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
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;

782:       DMGetLabelName(dm, l, &name);
783:       DMGetLabel(dm, name, &label);
784:       DMLabelGetNumValues(label, &numValues);
785:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata of sizes (", name, numValues);
786:       DMLabelGetValueIS(label, &valueIS);
787:       ISGetIndices(valueIS, &values);
788:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
789:       for (v = 0; v < numValues; ++v) {
790:         PetscInt size;

792:         DMLabelGetStratumSize(label, values[v], &size);
793:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
794:         PetscViewerASCIIPrintf(viewer, "%D", size);
795:       }
796:       PetscViewerASCIIPrintf(viewer, ")\n");
797:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
798:       ISRestoreIndices(valueIS, &values);
799:       ISDestroy(&valueIS);
800:     }
801:     DMGetCoarseDM(dm, &cdm);
802:     if (cdm) {
803:       PetscViewerASCIIPushTab(viewer);
804:       DMPlexView_Ascii(cdm, viewer);
805:       PetscViewerASCIIPopTab(viewer);
806:     }
807:   }
808:   return(0);
809: }

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;

824:   DMGetCoordinateDim(dm, &dim);
825:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
826:   DMGetCoordinateDM(dm, &cdm);
827:   DMGetDefaultSection(cdm, &coordSection);
828:   DMGetCoordinatesLocal(dm, &coordinates);
829:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
830:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

832:   PetscViewerDrawGetDraw(viewer, 0, &draw);
833:   PetscDrawIsNull(draw, &isnull);
834:   if (isnull) return(0);
835:   PetscDrawSetTitle(draw, "Mesh");

837:   VecGetLocalSize(coordinates, &N);
838:   VecGetArrayRead(coordinates, &coords);
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:   VecRestoreArrayRead(coordinates, &coords);
844:   PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
845:   PetscDrawClear(draw);

847:   for (c = cStart; c < cEnd; ++c) {
848:     PetscScalar *coords = NULL;
849:     PetscInt     numCoords;

851:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
852:     switch (numCoords) {
853:     case 6:
854:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
855:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
856:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
857:       break;
858:     case 8:
859:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
860:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
861:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
862:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
863:       break;
864:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
865:     }
866:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
867:   }
868:   PetscDrawFlush(draw);
869:   PetscDrawPause(draw);
870:   PetscDrawSave(draw);
871:   return(0);
872: }

874: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
875: {
876:   PetscBool      iascii, ishdf5, isvtk, isdraw;

882:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
883:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
884:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
885:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
886:   if (iascii) {
887:     DMPlexView_Ascii(dm, viewer);
888:   } else if (ishdf5) {
889: #if defined(PETSC_HAVE_HDF5)
890:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
891:     DMPlexView_HDF5_Internal(dm, viewer);
892:     PetscViewerPopFormat(viewer);
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:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
898:   } else if (isdraw) {
899:     DMPlexView_Draw(dm, viewer);
900:   }
901:   return(0);
902: }

904: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
905: {
906:   PetscBool      isbinary, ishdf5;

912:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
913:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
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:     DMPlexLoad_HDF5_Internal(dm, viewer);
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:   return(0);
923: }

925: PetscErrorCode DMDestroy_Plex(DM dm)
926: {
927:   DM_Plex       *mesh = (DM_Plex*) dm->data;

931:   if (--mesh->refct > 0) return(0);
932:   PetscSectionDestroy(&mesh->coneSection);
933:   PetscFree(mesh->cones);
934:   PetscFree(mesh->coneOrientations);
935:   PetscSectionDestroy(&mesh->supportSection);
936:   PetscSectionDestroy(&mesh->subdomainSection);
937:   PetscFree(mesh->supports);
938:   PetscFree(mesh->facesTmp);
939:   PetscFree(mesh->tetgenOpts);
940:   PetscFree(mesh->triangleOpts);
941:   PetscPartitionerDestroy(&mesh->partitioner);
942:   DMLabelDestroy(&mesh->subpointMap);
943:   ISDestroy(&mesh->globalVertexNumbers);
944:   ISDestroy(&mesh->globalCellNumbers);
945:   PetscSectionDestroy(&mesh->anchorSection);
946:   ISDestroy(&mesh->anchorIS);
947:   PetscSectionDestroy(&mesh->parentSection);
948:   PetscFree(mesh->parents);
949:   PetscFree(mesh->childIDs);
950:   PetscSectionDestroy(&mesh->childSection);
951:   PetscFree(mesh->children);
952:   DMDestroy(&mesh->referenceTree);
953:   PetscGridHashDestroy(&mesh->lbox);
954:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
955:   PetscFree(mesh);
956:   PetscObjectComposeFunction((PetscObject)dm,"DMAdaptLabel_C",NULL);
957:   return(0);
958: }

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;

971:   MatInitializePackage();
972:   mtype = dm->mattype;
973:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
974:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
975:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
976:   MatCreate(PetscObjectComm((PetscObject)dm), J);
977:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
978:   MatSetType(*J, mtype);
979:   MatSetFromOptions(*J);
980:   MatGetBlockSize(*J, &mbs);
981:   if (mbs > 1) bs = mbs;
982:   PetscStrcmp(mtype, MATSHELL, &isShell);
983:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
984:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
985:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
986:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
987:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
988:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
989:   PetscStrcmp(mtype, MATIS, &isMatIS);
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;

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;

1001:       DMGetDefaultSection(dm, &section);
1002:       PetscSectionGetStorageSize(section, &size);
1003:       PetscMalloc1(size,&ltogidx);
1004:       DMPlexGetSubdomainSection(dm, &subSection);
1005:     } else {
1006:       DMGetLocalToGlobalMapping(dm,&ltog);
1007:     }
1008:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1009:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1010:       PetscInt bdof;

1012:       PetscSectionGetDof(sectionGlobal, p, &dof);
1013:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
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:         PetscSectionGetOffset(subSection, p, &loff);
1023:         PetscSectionGetOffset(sectionGlobal, p, &off);
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:     MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1030:     bsLocal = bs < 0 ? bsMax : bs;
1031:     MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
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:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1040:     }
1041:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1042:     if (isMatIS) {
1043:       ISLocalToGlobalMappingDestroy(&ltog);
1044:     }
1045:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1046:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1047:     PetscFree4(dnz, onz, dnzu, onzu);
1048:   }
1049:   MatSetDM(*J, dm);
1050:   return(0);
1051: }

1053: /*@
1054:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1056:   Not collective

1058:   Input Parameter:
1059: . mesh - The DMPlex

1061:   Output Parameters:
1062: . subsection - The subdomain section

1064:   Level: developer

1066: .seealso:
1067: @*/
1068: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1069: {
1070:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1075:   if (!mesh->subdomainSection) {
1076:     PetscSection section;
1077:     PetscSF      sf;

1079:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1080:     DMGetDefaultSection(dm,&section);
1081:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1082:     PetscSFDestroy(&sf);
1083:   }
1084:   *subsection = mesh->subdomainSection;
1085:   return(0);
1086: }

1088: /*@
1089:   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)

1091:   Not collective

1093:   Input Parameter:
1094: . mesh - The DMPlex

1096:   Output Parameters:
1097: + pStart - The first mesh point
1098: - pEnd   - The upper bound for mesh points

1100:   Level: beginner

1102: .seealso: DMPlexCreate(), DMPlexSetChart()
1103: @*/
1104: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1105: {
1106:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1111:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1112:   return(0);
1113: }

1115: /*@
1116:   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)

1118:   Not collective

1120:   Input Parameters:
1121: + mesh - The DMPlex
1122: . pStart - The first mesh point
1123: - pEnd   - The upper bound for mesh points

1125:   Output Parameters:

1127:   Level: beginner

1129: .seealso: DMPlexCreate(), DMPlexGetChart()
1130: @*/
1131: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1132: {
1133:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1138:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1139:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1140:   return(0);
1141: }

1143: /*@
1144:   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG

1146:   Not collective

1148:   Input Parameters:
1149: + mesh - The DMPlex
1150: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1152:   Output Parameter:
1153: . size - The cone size for point p

1155:   Level: beginner

1157: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1158: @*/
1159: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1160: {
1161:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1167:   PetscSectionGetDof(mesh->coneSection, p, size);
1168:   return(0);
1169: }

1171: /*@
1172:   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG

1174:   Not collective

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

1181:   Output Parameter:

1183:   Note:
1184:   This should be called after DMPlexSetChart().

1186:   Level: beginner

1188: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1189: @*/
1190: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1191: {
1192:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1197:   PetscSectionSetDof(mesh->coneSection, p, size);

1199:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1200:   return(0);
1201: }

1203: /*@
1204:   DMPlexAddConeSize - Add the given number of in-edges to this point in the Sieve DAG

1206:   Not collective

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

1213:   Output Parameter:

1215:   Note:
1216:   This should be called after DMPlexSetChart().

1218:   Level: beginner

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;

1230:   PetscSectionAddDof(mesh->coneSection, p, size);
1231:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1233:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1234:   return(0);
1235: }

1237: /*@C
1238:   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG

1240:   Not collective

1242:   Input Parameters:
1243: + mesh - The DMPlex
1244: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1246:   Output Parameter:
1247: . cone - An array of points which are on the in-edges for point p

1249:   Level: beginner

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.

1255:   You must also call DMPlexRestoreCone() after you finish using the returned array.

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;

1268:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1269:   *cone = &mesh->cones[off];
1270:   return(0);
1271: }

1273: /*@
1274:   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG

1276:   Not collective

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

1283:   Output Parameter:

1285:   Note:
1286:   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().

1288:   Level: beginner

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;

1301:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1302:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1304:   PetscSectionGetOffset(mesh->coneSection, p, &off);
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:   return(0);
1311: }

1313: /*@C
1314:   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG

1316:   Not collective

1318:   Input Parameters:
1319: + mesh - The DMPlex
1320: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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.

1328:   Level: beginner

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.

1334:   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.

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;

1346: #if defined(PETSC_USE_DEBUG)
1347:   {
1348:     PetscInt dof;
1349:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1351:   }
1352: #endif
1353:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1355:   *coneOrientation = &mesh->coneOrientations[off];
1356:   return(0);
1357: }

1359: /*@
1360:   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG

1362:   Not collective

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.

1372:   Output Parameter:

1374:   Note:
1375:   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().

1377:   Level: beginner

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;

1390:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1391:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1393:   PetscSectionGetOffset(mesh->coneSection, p, &off);
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];

1398:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
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:   return(0);
1403: }

1405: /*@
1406:   DMPlexInsertCone - Insert a point into the in-edges for the point p in the Sieve DAG

1408:   Not collective

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

1416:   Level: beginner

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;

1429:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
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:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1433:   PetscSectionGetOffset(mesh->coneSection, p, &off);
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:   return(0);
1437: }

1439: /*@
1440:   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the Sieve DAG

1442:   Not collective

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

1450:   Level: beginner

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;

1463:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
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:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1466:   PetscSectionGetOffset(mesh->coneSection, p, &off);
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:   return(0);
1470: }

1472: /*@
1473:   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG

1475:   Not collective

1477:   Input Parameters:
1478: + mesh - The DMPlex
1479: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1481:   Output Parameter:
1482: . size - The support size for point p

1484:   Level: beginner

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;

1496:   PetscSectionGetDof(mesh->supportSection, p, size);
1497:   return(0);
1498: }

1500: /*@
1501:   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG

1503:   Not collective

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

1510:   Output Parameter:

1512:   Note:
1513:   This should be called after DMPlexSetChart().

1515:   Level: beginner

1517: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1518: @*/
1519: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1520: {
1521:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1526:   PetscSectionSetDof(mesh->supportSection, p, size);

1528:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1529:   return(0);
1530: }

1532: /*@C
1533:   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG

1535:   Not collective

1537:   Input Parameters:
1538: + mesh - The DMPlex
1539: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1541:   Output Parameter:
1542: . support - An array of points which are on the out-edges for point p

1544:   Level: beginner

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.

1550:   You must also call DMPlexRestoreSupport() after you finish using the returned array.

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;

1563:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1564:   *support = &mesh->supports[off];
1565:   return(0);
1566: }

1568: /*@
1569:   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG

1571:   Not collective

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

1578:   Output Parameter:

1580:   Note:
1581:   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().

1583:   Level: beginner

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;

1596:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1597:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1599:   PetscSectionGetOffset(mesh->supportSection, p, &off);
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:   return(0);
1606: }

1608: /*@
1609:   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the Sieve DAG

1611:   Not collective

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

1619:   Level: beginner

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;

1632:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1633:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1634:   PetscSectionGetOffset(mesh->supportSection, p, &off);
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:   return(0);
1640: }

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

1645:   Not collective

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

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, ...]

1657:   Note:
1658:   If using internal storage (points is NULL on input), each call overwrites the last output.

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.

1664:   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1666:   Level: beginner

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;

1682:   DMPlexGetDepth(dm, &depth);
1683:   /* This is only 1-level */
1684:   if (useCone) {
1685:     DMPlexGetConeSize(dm, p, &tmpSize);
1686:     DMPlexGetCone(dm, p, &tmp);
1687:     DMPlexGetConeOrientation(dm, p, &tmpO);
1688:   } else {
1689:     DMPlexGetSupportSize(dm, p, &tmpSize);
1690:     DMPlexGetSupport(dm, p, &tmp);
1691:   }
1692:   if (depth == 1) {
1693:     if (*points) {
1694:       closure = *points;
1695:     } else {
1696:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1697:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
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:     return(0);
1707:   }
1708:   {
1709:     PetscInt c, coneSeries, s,supportSeries;

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:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1718:   if (*points) {
1719:     closure = *points;
1720:   } else {
1721:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
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;

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;

1740:     if (useCone) {
1741:       DMPlexGetConeSize(dm, q, &tmpSize);
1742:       DMPlexGetCone(dm, q, &tmp);
1743:       DMPlexGetConeOrientation(dm, q, &tmpO);
1744:     } else {
1745:       DMPlexGetSupportSize(dm, q, &tmpSize);
1746:       DMPlexGetSupport(dm, q, &tmp);
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;

1758:       if (rev) {
1759:         PetscInt childSize, coff;
1760:         DMPlexGetConeSize(dm, cp, &childSize);
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:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1782:   return(0);
1783: }

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

1788:   Not collective

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

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, ...]

1801:   Note:
1802:   If using internal storage (points is NULL on input), each call overwrites the last output.

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.

1808:   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1810:   Level: beginner

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;

1826:   DMPlexGetDepth(dm, &depth);
1827:   /* This is only 1-level */
1828:   if (useCone) {
1829:     DMPlexGetConeSize(dm, p, &tmpSize);
1830:     DMPlexGetCone(dm, p, &tmp);
1831:     DMPlexGetConeOrientation(dm, p, &tmpO);
1832:   } else {
1833:     DMPlexGetSupportSize(dm, p, &tmpSize);
1834:     DMPlexGetSupport(dm, p, &tmp);
1835:   }
1836:   if (depth == 1) {
1837:     if (*points) {
1838:       closure = *points;
1839:     } else {
1840:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1841:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
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:     return(0);
1852:   }
1853:   {
1854:     PetscInt c, coneSeries, s,supportSeries;

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:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1863:   if (*points) {
1864:     closure = *points;
1865:   } else {
1866:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
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;

1874:     if (ornt < 0) {
1875:       PetscInt childSize, coff;
1876:       DMPlexGetConeSize(dm, cp, &childSize);
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;

1892:     if (useCone) {
1893:       DMPlexGetConeSize(dm, q, &tmpSize);
1894:       DMPlexGetCone(dm, q, &tmp);
1895:       DMPlexGetConeOrientation(dm, q, &tmpO);
1896:     } else {
1897:       DMPlexGetSupportSize(dm, q, &tmpSize);
1898:       DMPlexGetSupport(dm, q, &tmp);
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;

1910:       if (rev) {
1911:         PetscInt childSize, coff;
1912:         DMPlexGetConeSize(dm, cp, &childSize);
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:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1934:   return(0);
1935: }

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

1940:   Not collective

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

1949:   Note:
1950:   If not using internal storage (points is not NULL on input), this call is unnecessary

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.

1956:   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1958:   Level: beginner

1960: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1961: @*/
1962: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1963: {

1970:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
1971:   if (numPoints) *numPoints = 0;
1972:   return(0);
1973: }

1975: /*@
1976:   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG

1978:   Not collective

1980:   Input Parameter:
1981: . mesh - The DMPlex

1983:   Output Parameters:
1984: + maxConeSize - The maximum number of in-edges
1985: - maxSupportSize - The maximum number of out-edges

1987:   Level: beginner

1989: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1990: @*/
1991: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1992: {
1993:   DM_Plex *mesh = (DM_Plex*) dm->data;

1997:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1998:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1999:   return(0);
2000: }

2002: PetscErrorCode DMSetUp_Plex(DM dm)
2003: {
2004:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2005:   PetscInt       size;

2010:   PetscSectionSetUp(mesh->coneSection);
2011:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2012:   PetscMalloc1(size, &mesh->cones);
2013:   PetscCalloc1(size, &mesh->coneOrientations);
2014:   if (mesh->maxSupportSize) {
2015:     PetscSectionSetUp(mesh->supportSection);
2016:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2017:     PetscMalloc1(size, &mesh->supports);
2018:   }
2019:   return(0);
2020: }

2022: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
2023: {

2027:   if (subdm) {DMClone(dm, subdm);}
2028:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2029:   return(0);
2030: }

2032: /*@
2033:   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation

2035:   Not collective

2037:   Input Parameter:
2038: . mesh - The DMPlex

2040:   Output Parameter:

2042:   Note:
2043:   This should be called after all calls to DMPlexSetCone()

2045:   Level: beginner

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;

2059:   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2060:   /* Calculate support sizes */
2061:   DMPlexGetChart(dm, &pStart, &pEnd);
2062:   for (p = pStart; p < pEnd; ++p) {
2063:     PetscInt dof, off, c;

2065:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2066:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2067:     for (c = off; c < off+dof; ++c) {
2068:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2069:     }
2070:   }
2071:   for (p = pStart; p < pEnd; ++p) {
2072:     PetscInt dof;

2074:     PetscSectionGetDof(mesh->supportSection, p, &dof);

2076:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2077:   }
2078:   PetscSectionSetUp(mesh->supportSection);
2079:   /* Calculate supports */
2080:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2081:   PetscMalloc1(supportSize, &mesh->supports);
2082:   PetscCalloc1(pEnd - pStart, &offsets);
2083:   for (p = pStart; p < pEnd; ++p) {
2084:     PetscInt dof, off, c;

2086:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2087:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2088:     for (c = off; c < off+dof; ++c) {
2089:       const PetscInt q = mesh->cones[c];
2090:       PetscInt       offS;

2092:       PetscSectionGetOffset(mesh->supportSection, q, &offS);

2094:       mesh->supports[offS+offsets[q]] = p;
2095:       ++offsets[q];
2096:     }
2097:   }
2098:   PetscFree(offsets);
2099:   return(0);
2100: }

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.

2108:   Collective on dm

2110:   Input Parameter:
2111: . mesh - The DMPlex

2113:   Output Parameter:

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.

2121:   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()

2123:   Level: beginner

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;

2137:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2138:   /* Calculate depth */
2139:   DMPlexGetChart(dm, &pStart, &pEnd);
2140:   DMCreateLabel(dm, "depth");
2141:   DMPlexGetDepthLabel(dm, &label);
2142:   /* Initialize roots and count leaves */
2143:   for (p = pStart; p < pEnd; ++p) {
2144:     PetscInt coneSize, supportSize;

2146:     DMPlexGetConeSize(dm, p, &coneSize);
2147:     DMPlexGetSupportSize(dm, p, &supportSize);
2148:     if (!coneSize && supportSize) {
2149:       ++numRoots;
2150:       DMLabelSetValue(label, p, 0);
2151:     } else if (!supportSize && coneSize) {
2152:       ++numLeaves;
2153:     } else if (!supportSize && !coneSize) {
2154:       /* Isolated points */
2155:       DMLabelSetValue(label, p, 0);
2156:     }
2157:   }
2158:   if (numRoots + numLeaves == (pEnd - pStart)) {
2159:     for (p = pStart; p < pEnd; ++p) {
2160:       PetscInt coneSize, supportSize;

2162:       DMPlexGetConeSize(dm, p, &coneSize);
2163:       DMPlexGetSupportSize(dm, p, &supportSize);
2164:       if (!supportSize && coneSize) {
2165:         DMLabelSetValue(label, p, 1);
2166:       }
2167:     }
2168:   } else {
2169:     IS       pointIS;
2170:     PetscInt numPoints = 0, level = 0;

2172:     DMLabelGetStratumIS(label, level, &pointIS);
2173:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2174:     while (numPoints) {
2175:       const PetscInt *points;
2176:       const PetscInt  newLevel = level+1;

2178:       ISGetIndices(pointIS, &points);
2179:       for (p = 0; p < numPoints; ++p) {
2180:         const PetscInt  point = points[p];
2181:         const PetscInt *support;
2182:         PetscInt        supportSize, s;

2184:         DMPlexGetSupportSize(dm, point, &supportSize);
2185:         DMPlexGetSupport(dm, point, &support);
2186:         for (s = 0; s < supportSize; ++s) {
2187:           DMLabelSetValue(label, support[s], newLevel);
2188:         }
2189:       }
2190:       ISRestoreIndices(pointIS, &points);
2191:       ++level;
2192:       ISDestroy(&pointIS);
2193:       DMLabelGetStratumIS(label, level, &pointIS);
2194:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2195:       else         {numPoints = 0;}
2196:     }
2197:     ISDestroy(&pointIS);
2198:   }
2199:   { /* just in case there is an empty process */
2200:     PetscInt numValues, maxValues = 0, v;

2202:     DMLabelGetNumValues(label,&numValues);
2203:     for (v = 0; v < numValues; v++) {
2204:       IS pointIS;

2206:       DMLabelGetStratumIS(label, v, &pointIS);
2207:       if (pointIS) {
2208:         PetscInt  min, max, numPoints;
2209:         PetscInt  start;
2210:         PetscBool contig;

2212:         ISGetLocalSize(pointIS, &numPoints);
2213:         ISGetMinMax(pointIS, &min, &max);
2214:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2215:         if (start == 0 && contig) {
2216:           ISDestroy(&pointIS);
2217:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2218:           DMLabelSetStratumIS(label, v, pointIS);
2219:         }
2220:       }
2221:       ISDestroy(&pointIS);
2222:     }
2223:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2224:     for (v = numValues; v < maxValues; v++) {
2225:       DMLabelAddStratum(label,v);
2226:     }
2227:   }

2229:   DMLabelGetState(label, &mesh->depthState);
2230:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2231:   return(0);
2232: }

2234: /*@C
2235:   DMPlexGetJoin - Get an array for the join of the set of points

2237:   Not Collective

2239:   Input Parameters:
2240: + dm - The DMPlex object
2241: . numPoints - The number of input points for the join
2242: - points - The input points

2244:   Output Parameters:
2245: + numCoveredPoints - The number of points in the join
2246: - coveredPoints - The points in the join

2248:   Level: intermediate

2250:   Note: Currently, this is restricted to a single level join

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.

2256:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

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;

2274:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
2275:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
2276:   /* Copy in support of first point */
2277:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2278:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
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;

2286:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2287:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2288:     for (c = 0; c < dof; ++c) {
2289:       const PetscInt point = mesh->supports[off+c];

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:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2304:   return(0);
2305: }

2307: /*@C
2308:   DMPlexRestoreJoin - Restore an array for the join of the set of points

2310:   Not Collective

2312:   Input Parameters:
2313: + dm - The DMPlex object
2314: . numPoints - The number of input points for the join
2315: - points - The input points

2317:   Output Parameters:
2318: + numCoveredPoints - The number of points in the join
2319: - coveredPoints - The points in the join

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.

2325:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

2327:   Level: intermediate

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: {

2341:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2342:   if (numCoveredPoints) *numCoveredPoints = 0;
2343:   return(0);
2344: }

2346: /*@C
2347:   DMPlexGetFullJoin - Get an array for the join of the set of points

2349:   Not Collective

2351:   Input Parameters:
2352: + dm - The DMPlex object
2353: . numPoints - The number of input points for the join
2354: - points - The input points

2356:   Output Parameters:
2357: + numCoveredPoints - The number of points in the join
2358: - coveredPoints - The points in the join

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.

2364:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

2366:   Level: intermediate

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;


2386:   DMPlexGetDepth(dm, &depth);
2387:   PetscCalloc1(numPoints, &closures);
2388:   DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2389:   ms      = mesh->maxSupportSize;
2390:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2391:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
2392:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);

2394:   for (p = 0; p < numPoints; ++p) {
2395:     PetscInt closureSize;

2397:     DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);

2399:     offsets[p*(depth+2)+0] = 0;
2400:     for (d = 0; d < depth+1; ++d) {
2401:       PetscInt pStart, pEnd, i;

2403:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
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;

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;

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];

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:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2446:   }
2447:   PetscFree(closures);
2448:   DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2449:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2450:   return(0);
2451: }

2453: /*@C
2454:   DMPlexGetMeet - Get an array for the meet of the set of points

2456:   Not Collective

2458:   Input Parameters:
2459: + dm - The DMPlex object
2460: . numPoints - The number of input points for the meet
2461: - points - The input points

2463:   Output Parameters:
2464: + numCoveredPoints - The number of points in the meet
2465: - coveredPoints - The points in the meet

2467:   Level: intermediate

2469:   Note: Currently, this is restricted to a single level meet

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.

2475:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

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;

2493:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
2494:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
2495:   /* Copy in cone of first point */
2496:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2497:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
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;

2505:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2506:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2507:     for (c = 0; c < dof; ++c) {
2508:       const PetscInt point = mesh->cones[off+c];

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:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2523:   return(0);
2524: }

2526: /*@C
2527:   DMPlexRestoreMeet - Restore an array for the meet of the set of points

2529:   Not Collective

2531:   Input Parameters:
2532: + dm - The DMPlex object
2533: . numPoints - The number of input points for the meet
2534: - points - The input points

2536:   Output Parameters:
2537: + numCoveredPoints - The number of points in the meet
2538: - coveredPoints - The points in the meet

2540:   Level: intermediate

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.

2546:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

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: {

2560:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2561:   if (numCoveredPoints) *numCoveredPoints = 0;
2562:   return(0);
2563: }

2565: /*@C
2566:   DMPlexGetFullMeet - Get an array for the meet of the set of points

2568:   Not Collective

2570:   Input Parameters:
2571: + dm - The DMPlex object
2572: . numPoints - The number of input points for the meet
2573: - points - The input points

2575:   Output Parameters:
2576: + numCoveredPoints - The number of points in the meet
2577: - coveredPoints - The points in the meet

2579:   Level: intermediate

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.

2585:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

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;


2605:   DMPlexGetDepth(dm, &height);
2606:   PetscMalloc1(numPoints, &closures);
2607:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2608:   mc      = mesh->maxConeSize;
2609:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2610:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
2611:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

2613:   for (p = 0; p < numPoints; ++p) {
2614:     PetscInt closureSize;

2616:     DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);

2618:     offsets[p*(height+2)+0] = 0;
2619:     for (h = 0; h < height+1; ++h) {
2620:       PetscInt pStart, pEnd, i;

2622:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
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;

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;

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];

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:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2665:   }
2666:   PetscFree(closures);
2667:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2668:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2669:   return(0);
2670: }

2672: /*@C
2673:   DMPlexEqual - Determine if two DMs have the same topology

2675:   Not Collective

2677:   Input Parameters:
2678: + dmA - A DMPlex object
2679: - dmB - A DMPlex object

2681:   Output Parameters:
2682: . equal - PETSC_TRUE if the topologies are identical

2684:   Level: intermediate

2686:   Notes:
2687:   We are not solving graph isomorphism, so we do not permutation.

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;


2702:   *equal = PETSC_FALSE;
2703:   DMPlexGetDepth(dmA, &depth);
2704:   DMPlexGetDepth(dmB, &depthB);
2705:   if (depth != depthB) return(0);
2706:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2707:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2708:   if ((pStart != pStartB) || (pEnd != pEndB)) return(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;

2713:     DMPlexGetConeSize(dmA, p, &coneSize);
2714:     DMPlexGetCone(dmA, p, &cone);
2715:     DMPlexGetConeOrientation(dmA, p, &ornt);
2716:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2717:     DMPlexGetCone(dmB, p, &coneB);
2718:     DMPlexGetConeOrientation(dmB, p, &orntB);
2719:     if (coneSize != coneSizeB) return(0);
2720:     for (c = 0; c < coneSize; ++c) {
2721:       if (cone[c] != coneB[c]) return(0);
2722:       if (ornt[c] != orntB[c]) return(0);
2723:     }
2724:     DMPlexGetSupportSize(dmA, p, &supportSize);
2725:     DMPlexGetSupport(dmA, p, &support);
2726:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2727:     DMPlexGetSupport(dmB, p, &supportB);
2728:     if (supportSize != supportSizeB) return(0);
2729:     for (s = 0; s < supportSize; ++s) {
2730:       if (support[s] != supportB[s]) return(0);
2731:     }
2732:   }
2733:   *equal = PETSC_TRUE;
2734:   return(0);
2735: }

2737: /*@C
2738:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

2740:   Not Collective

2742:   Input Parameters:
2743: + dm         - The DMPlex
2744: . cellDim    - The cell dimension
2745: - numCorners - The number of vertices on a cell

2747:   Output Parameters:
2748: . numFaceVertices - The number of vertices on a face

2750:   Level: developer

2752:   Notes:
2753:   Of course this can only work for a restricted set of symmetric shapes

2755: .seealso: DMPlexGetCone()
2756: @*/
2757: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2758: {
2759:   MPI_Comm       comm;

2763:   PetscObjectGetComm((PetscObject)dm,&comm);
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:   return(0);
2824: }

2826: /*@
2827:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

2829:   Not Collective

2831:   Input Parameter:
2832: . dm    - The DMPlex object

2834:   Output Parameter:
2835: . depthLabel - The DMLabel recording point depth

2837:   Level: developer

2839: .keywords: mesh, points
2840: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2841: @*/
2842: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2843: {

2849:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
2850:   *depthLabel = dm->depthLabel;
2851:   return(0);
2852: }

2854: /*@
2855:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

2857:   Not Collective

2859:   Input Parameter:
2860: . dm    - The DMPlex object

2862:   Output Parameter:
2863: . depth - The number of strata (breadth first levels) in the DAG

2865:   Level: developer

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;

2879:   DMPlexGetDepthLabel(dm, &label);
2880:   if (label) {DMLabelGetNumValues(label, &d);}
2881:   *depth = d-1;
2882:   return(0);
2883: }

2885: /*@
2886:   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.

2888:   Not Collective

2890:   Input Parameters:
2891: + dm           - The DMPlex object
2892: - stratumValue - The requested depth

2894:   Output Parameters:
2895: + start - The first point at this depth
2896: - end   - One beyond the last point at this depth

2898:   Level: developer

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;

2913:   DMPlexGetChart(dm, &pStart, &pEnd);
2914:   if (pStart == pEnd) return(0);
2915:   if (stratumValue < 0) {
2916:     if (start) *start = pStart;
2917:     if (end)   *end   = pEnd;
2918:     return(0);
2919:   }
2920:   DMPlexGetDepthLabel(dm, &label);
2921:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2922:   DMLabelGetStratumBounds(label, stratumValue, start, end);
2923:   return(0);
2924: }

2926: /*@
2927:   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.

2929:   Not Collective

2931:   Input Parameters:
2932: + dm           - The DMPlex object
2933: - stratumValue - The requested height

2935:   Output Parameters:
2936: + start - The first point at this height
2937: - end   - One beyond the last point at this height

2939:   Level: developer

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;

2954:   DMPlexGetChart(dm, &pStart, &pEnd);
2955:   if (pStart == pEnd) return(0);
2956:   if (stratumValue < 0) {
2957:     if (start) *start = pStart;
2958:     if (end)   *end   = pEnd;
2959:     return(0);
2960:   }
2961:   DMPlexGetDepthLabel(dm, &label);
2962:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2963:   DMLabelGetNumValues(label, &depth);
2964:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
2965:   return(0);
2966: }

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;

2978:   PetscMalloc1(numFields, &isFE);
2979:   DMGetNumFields(dm, &Nf);
2980:   for (f = 0; f < numFields; ++f) {
2981:     PetscObject  obj;
2982:     PetscClassId id;

2984:     isFE[f] = PETSC_FALSE;
2985:     if (f >= Nf) continue;
2986:     DMGetField(dm, f, &obj);
2987:     PetscObjectGetClassId(obj, &id);
2988:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2989:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2990:   }
2991:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
2992:   if (numFields > 0) {
2993:     PetscSectionSetNumFields(*section, numFields);
2994:     if (numComp) {
2995:       for (f = 0; f < numFields; ++f) {
2996:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
2997:         if (isFE[f]) {
2998:           PetscFE           fe;
2999:           PetscDualSpace    dspace;
3000:           const PetscInt    ***perms;
3001:           const PetscScalar ***flips;
3002:           const PetscInt    *numDof;

3004:           DMGetField(dm,f,(PetscObject *) &fe);
3005:           PetscFEGetDualSpace(fe,&dspace);
3006:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3007:           PetscDualSpaceGetNumDof(dspace,&numDof);
3008:           if (perms || flips) {
3009:             DM               K;
3010:             DMLabel          depthLabel;
3011:             PetscInt         depth, h;
3012:             PetscSectionSym  sym;

3014:             PetscDualSpaceGetDM(dspace,&K);
3015:             DMPlexGetDepthLabel(dm,&depthLabel);
3016:             DMPlexGetDepth(dm,&depth);
3017:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
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;

3025:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3026:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3027:               if (!hspace) continue;
3028:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3029:               if (perms) perms0 = perms[0];
3030:               if (flips) flips0 = flips[0];
3031:               if (!(perms0 || flips0)) continue;
3032:               DMPlexGetConeSize(K,kStart,&kConeSize);
3033:               if (numComp[f] == 1) {
3034:                 PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3035:               } else {
3036:                 PetscInt    **fieldPerms = NULL, o;
3037:                 PetscScalar **fieldFlips = NULL;

3039:                 PetscCalloc1(2 * kConeSize,&fieldPerms);
3040:                 PetscCalloc1(2 * kConeSize,&fieldFlips);
3041:                 for (o = -kConeSize; o < kConeSize; o++) {
3042:                   if (perms0 && perms0[o]) {
3043:                     PetscInt r, s;

3045:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldPerms[o+kConeSize]);
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;

3055:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldFlips[o+kConeSize]);
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:                 PetscSectionSymLabelSetStratum(sym,depth - h,numComp[f] * numDof[depth - h],-kConeSize,kConeSize,PETSC_OWN_POINTER,(const PetscInt **) fieldPerms,(const PetscScalar **)fieldFlips);
3064:               }
3065:             }
3066:             PetscSectionSetFieldSym(*section,f,sym);
3067:             PetscSectionSymDestroy(&sym);
3068:           }
3069:         }
3070:       }
3071:     }
3072:   }
3073:   DMPlexGetChart(dm, &pStart, &pEnd);
3074:   PetscSectionSetChart(*section, pStart, pEnd);
3075:   DMPlexGetDepth(dm, &depth);
3076:   PetscMalloc1(depth+1,&pMax);
3077:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3078:   for (dep = 0; dep <= depth; ++dep) {
3079:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3080:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3081:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3082:     for (p = pStart; p < pEnd; ++p) {
3083:       PetscInt tot = 0;

3085:       for (f = 0; f < numFields; ++f) {
3086:         if (isFE[f] && p >= pMax[dep]) continue;
3087:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3088:         tot += numDof[f*(dim+1)+d];
3089:       }
3090:       PetscSectionSetDof(*section, p, tot);
3091:     }
3092:   }
3093:   PetscFree(pMax);
3094:   PetscFree(isFE);
3095:   return(0);
3096: }

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;

3109:   PetscSectionGetNumFields(section, &numFields);
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;

3116:     if (numFields) field = bcField[bc];
3117:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3118:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3119:     ISGetLocalSize(bcPoints[bc], &n);
3120:     ISGetIndices(bcPoints[bc], &idx);
3121:     for (i = 0; i < n; ++i) {
3122:       const PetscInt p = idx[i];
3123:       PetscInt       numConst;

3125:       if (numFields) {
3126:         PetscSectionGetFieldDof(section, p, field, &numConst);
3127:       } else {
3128:         PetscSectionGetDof(section, p, &numConst);
3129:       }
3130:       /* If Nc < 0, constrain every dof on the point */
3131:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3132:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3133:       PetscSectionAddConstraintDof(section, p, numConst);
3134:     }
3135:     ISRestoreIndices(bcPoints[bc], &idx);
3136:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3137:   }
3138:   DMPlexGetAnchors(dm, &aSec, NULL);
3139:   if (aSec) {
3140:     PetscInt aStart, aEnd, a;

3142:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3143:     for (a = aStart; a < aEnd; a++) {
3144:       PetscInt dof, f;

3146:       PetscSectionGetDof(aSec, a, &dof);
3147:       if (dof) {
3148:         /* if there are point-to-point constraints, then all dofs are constrained */
3149:         PetscSectionGetDof(section, a, &dof);
3150:         PetscSectionSetConstraintDof(section, a, dof);
3151:         for (f = 0; f < numFields; f++) {
3152:           PetscSectionGetFieldDof(section, a, f, &dof);
3153:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3154:         }
3155:       }
3156:     }
3157:   }
3158:   return(0);
3159: }

3161: /* Set the constrained field indices on each point
3162:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3163: */
3164: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3165: {
3166:   PetscSection   aSec;
3167:   PetscInt      *indices;
3168:   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;

3172:   PetscSectionGetNumFields(section, &numFields);
3173:   if (!numFields) return(0);
3174:   /* Initialize all field indices to -1 */
3175:   PetscSectionGetChart(section, &pStart, &pEnd);
3176:   PetscSectionGetMaxDof(section, &maxDof);
3177:   PetscMalloc1(maxDof, &indices);
3178:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3179:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
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;

3186:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3187:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3188:     ISGetLocalSize(bcPoints[bc], &n);
3189:     ISGetIndices(bcPoints[bc], &idx);
3190:     for (i = 0; i < n; ++i) {
3191:       const PetscInt  p = idx[i];
3192:       const PetscInt *find;
3193:       PetscInt        fcdof, c;

3195:       PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3196:       if (Nc < 0) {
3197:         for (d = 0; d < fcdof; ++d) indices[d] = d;
3198:       } else {
3199:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3200:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3201:         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
3202:         PetscSortInt(d+Nc, indices);
3203:         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3204:       }
3205:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3206:     }
3207:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3208:     ISRestoreIndices(bcPoints[bc], &idx);
3209:   }
3210:   /* Handle anchors */
3211:   DMPlexGetAnchors(dm, &aSec, NULL);
3212:   if (aSec) {
3213:     PetscInt aStart, aEnd, a;

3215:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3216:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3217:     for (a = aStart; a < aEnd; a++) {
3218:       PetscInt dof, fdof, f;

3220:       PetscSectionGetDof(aSec, a, &dof);
3221:       if (dof) {
3222:         /* if there are point-to-point constraints, then all dofs are constrained */
3223:         for (f = 0; f < numFields; f++) {
3224:           PetscSectionGetFieldDof(section, a, f, &fdof);
3225:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3226:         }
3227:       }
3228:     }
3229:   }
3230:   PetscFree(indices);
3231:   return(0);
3232: }

3234: /* Set the constrained indices on each point */
3235: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3236: {
3237:   PetscInt      *indices;
3238:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3242:   PetscSectionGetNumFields(section, &numFields);
3243:   PetscSectionGetMaxDof(section, &maxDof);
3244:   PetscSectionGetChart(section, &pStart, &pEnd);
3245:   PetscMalloc1(maxDof, &indices);
3246:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3247:   for (p = pStart; p < pEnd; ++p) {
3248:     PetscInt cdof, d;

3250:     PetscSectionGetConstraintDof(section, p, &cdof);
3251:     if (cdof) {
3252:       if (numFields) {
3253:         PetscInt numConst = 0, foff = 0;

3255:         for (f = 0; f < numFields; ++f) {
3256:           const PetscInt *find;
3257:           PetscInt        fcdof, fdof;

3259:           PetscSectionGetFieldDof(section, p, f, &fdof);
3260:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3261:           /* Change constraint numbering from field component to local dof number */
3262:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3263:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3264:           numConst += fcdof;
3265:           foff     += fdof;
3266:         }
3267:         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
3268:       } else {
3269:         for (d = 0; d < cdof; ++d) indices[d] = d;
3270:       }
3271:       PetscSectionSetConstraintIndices(section, p, indices);
3272:     }
3273:   }
3274:   PetscFree(indices);
3275:   return(0);
3276: }

3278: /*@C
3279:   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.

3281:   Not Collective

3283:   Input Parameters:
3284: + dm        - The DMPlex object
3285: . dim       - The spatial dimension of the problem
3286: . numFields - The number of fields in the problem
3287: . numComp   - An array of size numFields that holds the number of components for each field
3288: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3289: . numBC     - The number of boundary conditions
3290: . bcField   - An array of size numBC giving the field number for each boundry condition
3291: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3292: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3293: - perm      - Optional permutation of the chart, or NULL

3295:   Output Parameter:
3296: . section - The PetscSection object

3298:   Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the
3299:   number of dof for field 0 on each edge.

3301:   The chart permutation is the same one set using PetscSectionSetPermutation()

3303:   Level: developer

3305:   Fortran Notes:
3306:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3308: .keywords: mesh, elements
3309: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3310: @*/
3311: PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], IS perm, PetscSection *section)
3312: {
3313:   PetscSection   aSec;

3317:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3318:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3319:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3320:   PetscSectionSetUp(*section);
3321:   DMPlexGetAnchors(dm,&aSec,NULL);
3322:   if (numBC || aSec) {
3323:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3324:     DMPlexCreateSectionBCIndices(dm, *section);
3325:   }
3326:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3327:   return(0);
3328: }

3330: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3331: {
3332:   PetscSection   section, s;
3333:   Mat            m;
3334:   PetscInt       maxHeight;

3338:   DMClone(dm, cdm);
3339:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3340:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3341:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3342:   DMSetDefaultSection(*cdm, section);
3343:   PetscSectionDestroy(&section);
3344:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3345:   MatCreate(PETSC_COMM_SELF, &m);
3346:   DMSetDefaultConstraints(*cdm, s, m);
3347:   PetscSectionDestroy(&s);
3348:   MatDestroy(&m);
3349:   return(0);
3350: }

3352: /*@C
3353:   DMPlexGetConeSection - Return a section which describes the layout of cone data

3355:   Not Collective

3357:   Input Parameters:
3358: . dm        - The DMPlex object

3360:   Output Parameter:
3361: . section - The PetscSection object

3363:   Level: developer

3365: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3366: @*/
3367: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3368: {
3369:   DM_Plex *mesh = (DM_Plex*) dm->data;

3373:   if (section) *section = mesh->coneSection;
3374:   return(0);
3375: }

3377: /*@C
3378:   DMPlexGetSupportSection - Return a section which describes the layout of support data

3380:   Not Collective

3382:   Input Parameters:
3383: . dm        - The DMPlex object

3385:   Output Parameter:
3386: . section - The PetscSection object

3388:   Level: developer

3390: .seealso: DMPlexGetConeSection()
3391: @*/
3392: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3393: {
3394:   DM_Plex *mesh = (DM_Plex*) dm->data;

3398:   if (section) *section = mesh->supportSection;
3399:   return(0);
3400: }

3402: /*@C
3403:   DMPlexGetCones - Return cone data

3405:   Not Collective

3407:   Input Parameters:
3408: . dm        - The DMPlex object

3410:   Output Parameter:
3411: . cones - The cone for each point

3413:   Level: developer

3415: .seealso: DMPlexGetConeSection()
3416: @*/
3417: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3418: {
3419:   DM_Plex *mesh = (DM_Plex*) dm->data;

3423:   if (cones) *cones = mesh->cones;
3424:   return(0);
3425: }

3427: /*@C
3428:   DMPlexGetConeOrientations - Return cone orientation data

3430:   Not Collective

3432:   Input Parameters:
3433: . dm        - The DMPlex object

3435:   Output Parameter:
3436: . coneOrientations - The cone orientation for each point

3438:   Level: developer

3440: .seealso: DMPlexGetConeSection()
3441: @*/
3442: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3443: {
3444:   DM_Plex *mesh = (DM_Plex*) dm->data;

3448:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3449:   return(0);
3450: }

3452: /******************************** FEM Support **********************************/

3454: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3455: {
3456:   PetscInt      *perm;
3457:   PetscInt       dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3461:   if (!section) {DMGetDefaultSection(dm, &section);}
3462:   DMGetDimension(dm, &dim);
3463:   PetscSectionGetNumFields(section, &Nf);
3464:   if (dim <= 1) return(0);
3465:   for (f = 0; f < Nf; ++f) {
3466:     /* An order k SEM disc has k-1 dofs on an edge */
3467:     DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3468:     PetscSectionGetFieldDof(section, eStart, f, &k);
3469:     PetscSectionGetFieldComponents(section, f, &Nc);
3470:     k = k/Nc + 1;
3471:     size += PetscPowInt(k+1, dim)*Nc;
3472:   }
3473:   PetscMalloc1(size, &perm);
3474:   for (f = 0; f < Nf; ++f) {
3475:     switch (dim) {
3476:     case 2:
3477:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3478:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3479:       PetscSectionGetFieldDof(section, eStart, f, &k);
3480:       PetscSectionGetFieldComponents(section, f, &Nc);
3481:       k = k/Nc + 1;
3482:       /* The SEM order is

3484:          v_lb, {e_b}, v_rb,
3485:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3486:          v_lt, reverse {e_t}, v_rt
3487:       */
3488:       {
3489:         const PetscInt of   = 0;
3490:         const PetscInt oeb  = of   + PetscSqr(k-1);
3491:         const PetscInt oer  = oeb  + (k-1);
3492:         const PetscInt oet  = oer  + (k-1);
3493:         const PetscInt oel  = oet  + (k-1);
3494:         const PetscInt ovlb = oel  + (k-1);
3495:         const PetscInt ovrb = ovlb + 1;
3496:         const PetscInt ovrt = ovrb + 1;
3497:         const PetscInt ovlt = ovrt + 1;
3498:         PetscInt       o;

3500:         /* bottom */
3501:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3502:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3503:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3504:         /* middle */
3505:         for (i = 0; i < k-1; ++i) {
3506:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3507:           for (o = of+(k-1)*i; o < of+(k-1)*(i+1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3508:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3509:         }
3510:         /* top */
3511:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3512:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3513:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3514:         foffset = offset;
3515:       }
3516:       break;
3517:     case 3:
3518:       /* The original hex closure is

3520:          {c,
3521:           f_b, f_t, f_f, f_b, f_r, f_l,
3522:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3523:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3524:       */
3525:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3526:       PetscSectionGetFieldDof(section, eStart, f, &k);
3527:       PetscSectionGetFieldComponents(section, f, &Nc);
3528:       k = k/Nc + 1;
3529:       /* The SEM order is
3530:          Bottom Slice
3531:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3532:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3533:          v_blb, {e_bb}, v_brb,

3535:          Middle Slice (j)
3536:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3537:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3538:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3540:          Top Slice
3541:          v_tlf, {e_tf}, v_trf,
3542:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3543:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3544:       */
3545:       {
3546:         const PetscInt oc    = 0;
3547:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3548:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3549:         const PetscInt off   = oft   + PetscSqr(k-1);
3550:         const PetscInt ofk   = off   + PetscSqr(k-1);
3551:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3552:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3553:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3554:         const PetscInt oebb  = oebl  + (k-1);
3555:         const PetscInt oebr  = oebb  + (k-1);
3556:         const PetscInt oebf  = oebr  + (k-1);
3557:         const PetscInt oetf  = oebf  + (k-1);
3558:         const PetscInt oetr  = oetf  + (k-1);
3559:         const PetscInt oetb  = oetr  + (k-1);
3560:         const PetscInt oetl  = oetb  + (k-1);
3561:         const PetscInt oerf  = oetl  + (k-1);
3562:         const PetscInt oelf  = oerf  + (k-1);
3563:         const PetscInt oelb  = oelf  + (k-1);
3564:         const PetscInt oerb  = oelb  + (k-1);
3565:         const PetscInt ovblf = oerb  + (k-1);
3566:         const PetscInt ovblb = ovblf + 1;
3567:         const PetscInt ovbrb = ovblb + 1;
3568:         const PetscInt ovbrf = ovbrb + 1;
3569:         const PetscInt ovtlf = ovbrf + 1;
3570:         const PetscInt ovtrf = ovtlf + 1;
3571:         const PetscInt ovtrb = ovtrf + 1;
3572:         const PetscInt ovtlb = ovtrb + 1;
3573:         PetscInt       o, n;

3575:         /* Bottom Slice */
3576:         /*   bottom */
3577:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3578:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3579:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3580:         /*   middle */
3581:         for (i = 0; i < k-1; ++i) {
3582:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3583:           for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;}
3584:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3585:         }
3586:         /*   top */
3587:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3588:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3589:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3591:         /* Middle Slice */
3592:         for (j = 0; j < k-1; ++j) {
3593:           /*   bottom */
3594:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3595:           for (o = off+j*(k-1); o < off+(j+1)*(k-1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3596:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3597:           /*   middle */
3598:           for (i = 0; i < k-1; ++i) {
3599:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3600:             for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc+(j*(k-1)+i)*(k-1)+n)*Nc + c + foffset;
3601:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3602:           }
3603:           /*   top */
3604:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3605:           for (o = ofk+j*(k-1)+(k-2); o >= ofk+j*(k-1); --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3606:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3607:         }

3609:         /* Top Slice */
3610:         /*   bottom */
3611:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3612:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3613:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3614:         /*   middle */
3615:         for (i = 0; i < k-1; ++i) {
3616:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3617:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3618:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3619:         }
3620:         /*   top */
3621:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3622:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3623:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3625:         foffset = offset;
3626:       }
3627:       break;
3628:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3629:     }
3630:   }
3631:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3632:   /* Check permutation */
3633:   {
3634:     PetscInt *check;

3636:     PetscMalloc1(size, &check);
3637:     for (i = 0; i < size; ++i) {check[i] = -1; if (perm[i] < 0 || perm[i] >= size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%D] = %D", i, perm[i]);}
3638:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3639:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3640:     PetscFree(check);
3641:   }
3642:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3643:   return(0);
3644: }

3646: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3647: {
3648:   PetscDS        prob;
3649:   PetscInt       depth, Nf, h;
3650:   DMLabel        label;

3654:   prob    = dm->prob;
3655:   Nf      = prob->Nf;
3656:   label   = dm->depthLabel;
3657:   *dspace = NULL;
3658:   if (field < Nf) {
3659:     PetscObject disc = prob->disc[field];

3661:     if (disc->classid == PETSCFE_CLASSID) {
3662:       PetscDualSpace dsp;

3664:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3665:       DMLabelGetNumValues(label,&depth);
3666:       DMLabelGetValue(label,point,&h);
3667:       h    = depth - 1 - h;
3668:       if (h) {
3669:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3670:       } else {
3671:         *dspace = dsp;
3672:       }
3673:     }
3674:   }
3675:   return(0);
3676: }


3679: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3680: {
3681:   PetscScalar    *array, *vArray;
3682:   const PetscInt *cone, *coneO;
3683:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3684:   PetscErrorCode  ierr;

3687:   PetscSectionGetChart(section, &pStart, &pEnd);
3688:   DMPlexGetConeSize(dm, point, &numPoints);
3689:   DMPlexGetCone(dm, point, &cone);
3690:   DMPlexGetConeOrientation(dm, point, &coneO);
3691:   if (!values || !*values) {
3692:     if ((point >= pStart) && (point < pEnd)) {
3693:       PetscInt dof;

3695:       PetscSectionGetDof(section, point, &dof);
3696:       size += dof;
3697:     }
3698:     for (p = 0; p < numPoints; ++p) {
3699:       const PetscInt cp = cone[p];
3700:       PetscInt       dof;

3702:       if ((cp < pStart) || (cp >= pEnd)) continue;
3703:       PetscSectionGetDof(section, cp, &dof);
3704:       size += dof;
3705:     }
3706:     if (!values) {
3707:       if (csize) *csize = size;
3708:       return(0);
3709:     }
3710:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
3711:   } else {
3712:     array = *values;
3713:   }
3714:   size = 0;
3715:   VecGetArray(v, &vArray);
3716:   if ((point >= pStart) && (point < pEnd)) {
3717:     PetscInt     dof, off, d;
3718:     PetscScalar *varr;

3720:     PetscSectionGetDof(section, point, &dof);
3721:     PetscSectionGetOffset(section, point, &off);
3722:     varr = &vArray[off];
3723:     for (d = 0; d < dof; ++d, ++offset) {
3724:       array[offset] = varr[d];
3725:     }
3726:     size += dof;
3727:   }
3728:   for (p = 0; p < numPoints; ++p) {
3729:     const PetscInt cp = cone[p];
3730:     PetscInt       o  = coneO[p];
3731:     PetscInt       dof, off, d;
3732:     PetscScalar   *varr;

3734:     if ((cp < pStart) || (cp >= pEnd)) continue;
3735:     PetscSectionGetDof(section, cp, &dof);
3736:     PetscSectionGetOffset(section, cp, &off);
3737:     varr = &vArray[off];
3738:     if (o >= 0) {
3739:       for (d = 0; d < dof; ++d, ++offset) {
3740:         array[offset] = varr[d];
3741:       }
3742:     } else {
3743:       for (d = dof-1; d >= 0; --d, ++offset) {
3744:         array[offset] = varr[d];
3745:       }
3746:     }
3747:     size += dof;
3748:   }
3749:   VecRestoreArray(v, &vArray);
3750:   if (!*values) {
3751:     if (csize) *csize = size;
3752:     *values = array;
3753:   } else {
3754:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3755:     *csize = size;
3756:   }
3757:   return(0);
3758: }

3760: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3761: {
3762:   const PetscInt *cla;
3763:   PetscInt       np, *pts = NULL;

3767:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3768:   if (!*clPoints) {
3769:     PetscInt pStart, pEnd, p, q;

3771:     PetscSectionGetChart(section, &pStart, &pEnd);
3772:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3773:     /* Compress out points not in the section */
3774:     for (p = 0, q = 0; p < np; p++) {
3775:       PetscInt r = pts[2*p];
3776:       if ((r >= pStart) && (r < pEnd)) {
3777:         pts[q*2]   = r;
3778:         pts[q*2+1] = pts[2*p+1];
3779:         ++q;
3780:       }
3781:     }
3782:     np = q;
3783:     cla = NULL;
3784:   } else {
3785:     PetscInt dof, off;

3787:     PetscSectionGetDof(*clSec, point, &dof);
3788:     PetscSectionGetOffset(*clSec, point, &off);
3789:     ISGetIndices(*clPoints, &cla);
3790:     np   = dof/2;
3791:     pts  = (PetscInt *) &cla[off];
3792:   }
3793:   *numPoints = np;
3794:   *points    = pts;
3795:   *clp       = cla;

3797:   return(0);
3798: }

3800: static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3801: {

3805:   if (!*clPoints) {
3806:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3807:   } else {
3808:     ISRestoreIndices(*clPoints, clp);
3809:   }
3810:   *numPoints = 0;
3811:   *points    = NULL;
3812:   *clSec     = NULL;
3813:   *clPoints  = NULL;
3814:   *clp       = NULL;
3815:   return(0);
3816: }

3818: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3819: {
3820:   PetscInt          offset = 0, p;
3821:   const PetscInt    **perms = NULL;
3822:   const PetscScalar **flips = NULL;
3823:   PetscErrorCode    ierr;

3826:   *size = 0;
3827:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3828:   for (p = 0; p < numPoints; p++) {
3829:     const PetscInt    point = points[2*p];
3830:     const PetscInt    *perm = perms ? perms[p] : NULL;
3831:     const PetscScalar *flip = flips ? flips[p] : NULL;
3832:     PetscInt          dof, off, d;
3833:     const PetscScalar *varr;

3835:     PetscSectionGetDof(section, point, &dof);
3836:     PetscSectionGetOffset(section, point, &off);
3837:     varr = &vArray[off];
3838:     if (clperm) {
3839:       if (perm) {
3840:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3841:       } else {
3842:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3843:       }
3844:       if (flip) {
3845:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3846:       }
3847:     } else {
3848:       if (perm) {
3849:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3850:       } else {
3851:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3852:       }
3853:       if (flip) {
3854:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3855:       }
3856:     }
3857:     offset += dof;
3858:   }
3859:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3860:   *size = offset;
3861:   return(0);
3862: }

3864: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3865: {
3866:   PetscInt          offset = 0, f;
3867:   PetscErrorCode    ierr;

3870:   *size = 0;
3871:   for (f = 0; f < numFields; ++f) {
3872:     PetscInt          p;
3873:     const PetscInt    **perms = NULL;
3874:     const PetscScalar **flips = NULL;

3876:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3877:     for (p = 0; p < numPoints; p++) {
3878:       const PetscInt    point = points[2*p];
3879:       PetscInt          fdof, foff, b;
3880:       const PetscScalar *varr;
3881:       const PetscInt    *perm = perms ? perms[p] : NULL;
3882:       const PetscScalar *flip = flips ? flips[p] : NULL;

3884:       PetscSectionGetFieldDof(section, point, f, &fdof);
3885:       PetscSectionGetFieldOffset(section, point, f, &foff);
3886:       varr = &vArray[foff];
3887:       if (clperm) {
3888:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
3889:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
3890:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
3891:       } else {
3892:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
3893:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
3894:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
3895:       }
3896:       offset += fdof;
3897:     }
3898:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3899:   }
3900:   *size = offset;
3901:   return(0);
3902: }

3904: /*@C
3905:   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'

3907:   Not collective

3909:   Input Parameters:
3910: + dm - The DM
3911: . section - The section describing the layout in v, or NULL to use the default section
3912: . v - The local vector
3913: - point - The sieve point in the DM

3915:   Output Parameters:
3916: + csize - The number of values in the closure, or NULL
3917: - values - The array of values, which is a borrowed array and should not be freed

3919:   Fortran Notes:
3920:   Since it returns an array, this routine is only available in Fortran 90, and you must
3921:   include petsc.h90 in your code.

3923:   The csize argument is not present in the Fortran 90 binding since it is internal to the array.

3925:   Level: intermediate

3927: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3928: @*/
3929: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3930: {
3931:   PetscSection       clSection;
3932:   IS                 clPoints;
3933:   PetscScalar       *array;
3934:   const PetscScalar *vArray;
3935:   PetscInt          *points = NULL;
3936:   const PetscInt    *clp, *perm;
3937:   PetscInt           depth, numFields, numPoints, size;
3938:   PetscErrorCode     ierr;

3942:   if (!section) {DMGetDefaultSection(dm, &section);}
3945:   DMPlexGetDepth(dm, &depth);
3946:   PetscSectionGetNumFields(section, &numFields);
3947:   if (depth == 1 && numFields < 2) {
3948:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
3949:     return(0);
3950:   }
3951:   /* Get points */
3952:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3953:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
3954:   /* Get array */
3955:   if (!values || !*values) {
3956:     PetscInt asize = 0, dof, p;

3958:     for (p = 0; p < numPoints*2; p += 2) {
3959:       PetscSectionGetDof(section, points[p], &dof);
3960:       asize += dof;
3961:     }
3962:     if (!values) {
3963:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3964:       if (csize) *csize = asize;
3965:       return(0);
3966:     }
3967:     DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
3968:   } else {
3969:     array = *values;
3970:   }
3971:   VecGetArrayRead(v, &vArray);
3972:   /* Get values */
3973:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
3974:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
3975:   /* Cleanup points */
3976:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3977:   /* Cleanup array */
3978:   VecRestoreArrayRead(v, &vArray);
3979:   if (!*values) {
3980:     if (csize) *csize = size;
3981:     *values = array;
3982:   } else {
3983:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3984:     *csize = size;
3985:   }
3986:   return(0);
3987: }

3989: /*@C
3990:   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'

3992:   Not collective

3994:   Input Parameters:
3995: + dm - The DM
3996: . section - The section describing the layout in v, or NULL to use the default section
3997: . v - The local vector
3998: . point - The sieve point in the DM
3999: . csize - The number of values in the closure, or NULL
4000: - values - The array of values, which is a borrowed array and should not be freed

4002:   Fortran Notes:
4003:   Since it returns an array, this routine is only available in Fortran 90, and you must
4004:   include petsc.h90 in your code.

4006:   The csize argument is not present in the Fortran 90 binding since it is internal to the array.

4008:   Level: intermediate

4010: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4011: @*/
4012: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4013: {
4014:   PetscInt       size = 0;

4018:   /* Should work without recalculating size */
4019:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
4020:   return(0);
4021: }

4023: PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
4024: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}

4026: PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
4027: {
4028:   PetscInt        cdof;   /* The number of constraints on this point */
4029:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4030:   PetscScalar    *a;
4031:   PetscInt        off, cind = 0, k;
4032:   PetscErrorCode  ierr;

4035:   PetscSectionGetConstraintDof(section, point, &cdof);
4036:   PetscSectionGetOffset(section, point, &off);
4037:   a    = &array[off];
4038:   if (!cdof || setBC) {
4039:     if (clperm) {
4040:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4041:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4042:     } else {
4043:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4044:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4045:     }
4046:   } else {
4047:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4048:     if (clperm) {
4049:       if (perm) {for (k = 0; k < dof; ++k) {
4050:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4051:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4052:         }
4053:       } else {
4054:         for (k = 0; k < dof; ++k) {
4055:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4056:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4057:         }
4058:       }
4059:     } else {
4060:       if (perm) {
4061:         for (k = 0; k < dof; ++k) {
4062:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4063:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4064:         }
4065:       } else {
4066:         for (k = 0; k < dof; ++k) {
4067:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4068:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4069:         }
4070:       }
4071:     }
4072:   }
4073:   return(0);
4074: }

4076: PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
4077: {
4078:   PetscInt        cdof;   /* The number of constraints on this point */
4079:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4080:   PetscScalar    *a;
4081:   PetscInt        off, cind = 0, k;
4082:   PetscErrorCode  ierr;

4085:   PetscSectionGetConstraintDof(section, point, &cdof);
4086:   PetscSectionGetOffset(section, point, &off);
4087:   a    = &array[off];
4088:   if (cdof) {
4089:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4090:     if (clperm) {
4091:       if (perm) {
4092:         for (k = 0; k < dof; ++k) {
4093:           if ((cind < cdof) && (k == cdofs[cind])) {
4094:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4095:             cind++;
4096:           }
4097:         }
4098:       } else {
4099:         for (k = 0; k < dof; ++k) {
4100:           if ((cind < cdof) && (k == cdofs[cind])) {
4101:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4102:             cind++;
4103:           }
4104:         }
4105:       }
4106:     } else {
4107:       if (perm) {
4108:         for (k = 0; k < dof; ++k) {
4109:           if ((cind < cdof) && (k == cdofs[cind])) {
4110:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4111:             cind++;
4112:           }
4113:         }
4114:       } else {
4115:         for (k = 0; k < dof; ++k) {
4116:           if ((cind < cdof) && (k == cdofs[cind])) {
4117:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4118:             cind++;
4119:           }
4120:         }
4121:       }
4122:     }
4123:   }
4124:   return(0);
4125: }

4127: PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4128: {
4129:   PetscScalar    *a;
4130:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4131:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4132:   PetscInt        cind = 0, b;
4133:   PetscErrorCode  ierr;

4136:   PetscSectionGetFieldDof(section, point, f, &fdof);
4137:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4138:   PetscSectionGetFieldOffset(section, point, f, &foff);
4139:   a    = &array[foff];
4140:   if (!fcdof || setBC) {
4141:     if (clperm) {
4142:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4143:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4144:     } else {
4145:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4146:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4147:     }
4148:   } else {
4149:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4150:     if (clperm) {
4151:       if (perm) {
4152:         for (b = 0; b < fdof; b++) {
4153:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4154:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4155:         }
4156:       } else {
4157:         for (b = 0; b < fdof; b++) {
4158:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4159:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4160:         }
4161:       }
4162:     } else {
4163:       if (perm) {
4164:         for (b = 0; b < fdof; b++) {
4165:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4166:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4167:         }
4168:       } else {
4169:         for (b = 0; b < fdof; b++) {
4170:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4171:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4172:         }
4173:       }
4174:     }
4175:   }
4176:   *offset += fdof;
4177:   return(0);
4178: }

4180: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4181: {
4182:   PetscScalar    *a;
4183:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4184:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4185:   PetscInt        cind = 0, b;
4186:   PetscErrorCode  ierr;

4189:   PetscSectionGetFieldDof(section, point, f, &fdof);
4190:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4191:   PetscSectionGetFieldOffset(section, point, f, &foff);
4192:   a    = &array[foff];
4193:   if (fcdof) {
4194:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4195:     if (clperm) {
4196:       if (perm) {
4197:         for (b = 0; b < fdof; b++) {
4198:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4199:             fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4200:             ++cind;
4201:           }
4202:         }
4203:       } else {
4204:         for (b = 0; b < fdof; b++) {
4205:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4206:             fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4207:             ++cind;
4208:           }
4209:         }
4210:       }
4211:     } else {
4212:       if (perm) {
4213:         for (b = 0; b < fdof; b++) {
4214:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4215:             fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4216:             ++cind;
4217:           }
4218:         }
4219:       } else {
4220:         for (b = 0; b < fdof; b++) {
4221:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4222:             fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4223:             ++cind;
4224:           }
4225:         }
4226:       }
4227:     }
4228:   }
4229:   *offset += fdof;
4230:   return(0);
4231: }

4233: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4234: {
4235:   PetscScalar    *array;
4236:   const PetscInt *cone, *coneO;
4237:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4238:   PetscErrorCode  ierr;

4241:   PetscSectionGetChart(section, &pStart, &pEnd);
4242:   DMPlexGetConeSize(dm, point, &numPoints);
4243:   DMPlexGetCone(dm, point, &cone);
4244:   DMPlexGetConeOrientation(dm, point, &coneO);
4245:   VecGetArray(v, &array);
4246:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4247:     const PetscInt cp = !p ? point : cone[p-1];
4248:     const PetscInt o  = !p ? 0     : coneO[p-1];

4250:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4251:     PetscSectionGetDof(section, cp, &dof);
4252:     /* ADD_VALUES */
4253:     {
4254:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4255:       PetscScalar    *a;
4256:       PetscInt        cdof, coff, cind = 0, k;

4258:       PetscSectionGetConstraintDof(section, cp, &cdof);
4259:       PetscSectionGetOffset(section, cp, &coff);
4260:       a    = &array[coff];
4261:       if (!cdof) {
4262:         if (o >= 0) {
4263:           for (k = 0; k < dof; ++k) {
4264:             a[k] += values[off+k];
4265:           }
4266:         } else {
4267:           for (k = 0; k < dof; ++k) {
4268:             a[k] += values[off+dof-k-1];
4269:           }
4270:         }
4271:       } else {
4272:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4273:         if (o >= 0) {
4274:           for (k = 0; k < dof; ++k) {
4275:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4276:             a[k] += values[off+k];
4277:           }
4278:         } else {
4279:           for (k = 0; k < dof; ++k) {
4280:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4281:             a[k] += values[off+dof-k-1];
4282:           }
4283:         }
4284:       }
4285:     }
4286:   }
4287:   VecRestoreArray(v, &array);
4288:   return(0);
4289: }

4291: /*@C
4292:   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'

4294:   Not collective

4296:   Input Parameters:
4297: + dm - The DM
4298: . section - The section describing the layout in v, or NULL to use the default section
4299: . v - The local vector
4300: . point - The sieve point in the DM
4301: . values - The array of values
4302: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

4304:   Fortran Notes:
4305:   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.

4307:   Level: intermediate

4309: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4310: @*/
4311: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4312: {
4313:   PetscSection    clSection;
4314:   IS              clPoints;
4315:   PetscScalar    *array;
4316:   PetscInt       *points = NULL;
4317:   const PetscInt *clp, *clperm;
4318:   PetscInt        depth, numFields, numPoints, p;
4319:   PetscErrorCode  ierr;

4323:   if (!section) {DMGetDefaultSection(dm, &section);}
4326:   DMPlexGetDepth(dm, &depth);
4327:   PetscSectionGetNumFields(section, &numFields);
4328:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4329:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4330:     return(0);
4331:   }
4332:   /* Get points */
4333:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4334:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4335:   /* Get array */
4336:   VecGetArray(v, &array);
4337:   /* Get values */
4338:   if (numFields > 0) {
4339:     PetscInt offset = 0, f;
4340:     for (f = 0; f < numFields; ++f) {
4341:       const PetscInt    **perms = NULL;
4342:       const PetscScalar **flips = NULL;

4344:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4345:       switch (mode) {
4346:       case INSERT_VALUES:
4347:         for (p = 0; p < numPoints; p++) {
4348:           const PetscInt    point = points[2*p];
4349:           const PetscInt    *perm = perms ? perms[p] : NULL;
4350:           const PetscScalar *flip = flips ? flips[p] : NULL;
4351:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4352:         } break;
4353:       case INSERT_ALL_VALUES:
4354:         for (p = 0; p < numPoints; p++) {
4355:           const PetscInt    point = points[2*p];
4356:           const PetscInt    *perm = perms ? perms[p] : NULL;
4357:           const PetscScalar *flip = flips ? flips[p] : NULL;
4358:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4359:         } break;
4360:       case INSERT_BC_VALUES:
4361:         for (p = 0; p < numPoints; p++) {
4362:           const PetscInt    point = points[2*p];
4363:           const PetscInt    *perm = perms ? perms[p] : NULL;
4364:           const PetscScalar *flip = flips ? flips[p] : NULL;
4365:           updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4366:         } break;
4367:       case ADD_VALUES:
4368:         for (p = 0; p < numPoints; p++) {
4369:           const PetscInt    point = points[2*p];
4370:           const PetscInt    *perm = perms ? perms[p] : NULL;
4371:           const PetscScalar *flip = flips ? flips[p] : NULL;
4372:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4373:         } break;
4374:       case ADD_ALL_VALUES:
4375:         for (p = 0; p < numPoints; p++) {
4376:           const PetscInt    point = points[2*p];
4377:           const PetscInt    *perm = perms ? perms[p] : NULL;
4378:           const PetscScalar *flip = flips ? flips[p] : NULL;
4379:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4380:         } break;
4381:       case ADD_BC_VALUES:
4382:         for (p = 0; p < numPoints; p++) {
4383:           const PetscInt    point = points[2*p];
4384:           const PetscInt    *perm = perms ? perms[p] : NULL;
4385:           const PetscScalar *flip = flips ? flips[p] : NULL;
4386:           updatePointFieldsBC_private(section, point, perm, flip, f, add, clperm, values, &offset, array);
4387:         } break;
4388:       default:
4389:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4390:       }
4391:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4392:     }
4393:   } else {
4394:     PetscInt dof, off;
4395:     const PetscInt    **perms = NULL;
4396:     const PetscScalar **flips = NULL;

4398:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4399:     switch (mode) {
4400:     case INSERT_VALUES:
4401:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4402:         const PetscInt    point = points[2*p];
4403:         const PetscInt    *perm = perms ? perms[p] : NULL;
4404:         const PetscScalar *flip = flips ? flips[p] : NULL;
4405:         PetscSectionGetDof(section, point, &dof);
4406:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4407:       } break;
4408:     case INSERT_ALL_VALUES:
4409:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4410:         const PetscInt    point = points[2*p];
4411:         const PetscInt    *perm = perms ? perms[p] : NULL;
4412:         const PetscScalar *flip = flips ? flips[p] : NULL;
4413:         PetscSectionGetDof(section, point, &dof);
4414:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4415:       } break;
4416:     case INSERT_BC_VALUES:
4417:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4418:         const PetscInt    point = points[2*p];
4419:         const PetscInt    *perm = perms ? perms[p] : NULL;
4420:         const PetscScalar *flip = flips ? flips[p] : NULL;
4421:         PetscSectionGetDof(section, point, &dof);
4422:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4423:       } break;
4424:     case ADD_VALUES:
4425:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4426:         const PetscInt    point = points[2*p];
4427:         const PetscInt    *perm = perms ? perms[p] : NULL;
4428:         const PetscScalar *flip = flips ? flips[p] : NULL;
4429:         PetscSectionGetDof(section, point, &dof);
4430:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4431:       } break;
4432:     case ADD_ALL_VALUES:
4433:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4434:         const PetscInt    point = points[2*p];
4435:         const PetscInt    *perm = perms ? perms[p] : NULL;
4436:         const PetscScalar *flip = flips ? flips[p] : NULL;
4437:         PetscSectionGetDof(section, point, &dof);
4438:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4439:       } break;
4440:     case ADD_BC_VALUES:
4441:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4442:         const PetscInt    point = points[2*p];
4443:         const PetscInt    *perm = perms ? perms[p] : NULL;
4444:         const PetscScalar *flip = flips ? flips[p] : NULL;
4445:         PetscSectionGetDof(section, point, &dof);
4446:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4447:       } break;
4448:     default:
4449:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4450:     }
4451:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4452:   }
4453:   /* Cleanup points */
4454:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4455:   /* Cleanup array */
4456:   VecRestoreArray(v, &array);
4457:   return(0);
4458: }

4460: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4461: {
4462:   PetscSection      clSection;
4463:   IS                clPoints;
4464:   PetscScalar       *array;
4465:   PetscInt          *points = NULL;
4466:   const PetscInt    *clp, *clperm;
4467:   PetscInt          numFields, numPoints, p;
4468:   PetscInt          offset = 0, f;
4469:   PetscErrorCode    ierr;

4473:   if (!section) {DMGetDefaultSection(dm, &section);}
4476:   PetscSectionGetNumFields(section, &numFields);
4477:   /* Get points */
4478:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4479:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4480:   /* Get array */
4481:   VecGetArray(v, &array);
4482:   /* Get values */
4483:   for (f = 0; f < numFields; ++f) {
4484:     const PetscInt    **perms = NULL;
4485:     const PetscScalar **flips = NULL;

4487:     if (!fieldActive[f]) {
4488:       for (p = 0; p < numPoints*2; p += 2) {
4489:         PetscInt fdof;
4490:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4491:         offset += fdof;
4492:       }
4493:       continue;
4494:     }
4495:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4496:     switch (mode) {
4497:     case INSERT_VALUES:
4498:       for (p = 0; p < numPoints; p++) {
4499:         const PetscInt    point = points[2*p];
4500:         const PetscInt    *perm = perms ? perms[p] : NULL;
4501:         const PetscScalar *flip = flips ? flips[p] : NULL;
4502:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4503:       } break;
4504:     case INSERT_ALL_VALUES:
4505:       for (p = 0; p < numPoints; p++) {
4506:         const PetscInt    point = points[2*p];
4507:         const PetscInt    *perm = perms ? perms[p] : NULL;
4508:         const PetscScalar *flip = flips ? flips[p] : NULL;
4509:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4510:         } break;
4511:     case INSERT_BC_VALUES:
4512:       for (p = 0; p < numPoints; p++) {
4513:         const PetscInt    point = points[2*p];
4514:         const PetscInt    *perm = perms ? perms[p] : NULL;
4515:         const PetscScalar *flip = flips ? flips[p] : NULL;
4516:         updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4517:       } break;
4518:     case ADD_VALUES:
4519:       for (p = 0; p < numPoints; p++) {
4520:         const PetscInt    point = points[2*p];
4521:         const PetscInt    *perm = perms ? perms[p] : NULL;
4522:         const PetscScalar *flip = flips ? flips[p] : NULL;
4523:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4524:       } break;
4525:     case ADD_ALL_VALUES:
4526:       for (p = 0; p < numPoints; p++) {
4527:         const PetscInt    point = points[2*p];
4528:         const PetscInt    *perm = perms ? perms[p] : NULL;
4529:         const PetscScalar *flip = flips ? flips[p] : NULL;
4530:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4531:       } break;
4532:     default:
4533:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4534:     }
4535:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4536:   }
4537:   /* Cleanup points */
4538:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4539:   /* Cleanup array */
4540:   VecRestoreArray(v, &array);
4541:   return(0);
4542: }

4544: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4545: {
4546:   PetscMPIInt    rank;
4547:   PetscInt       i, j;

4551:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4552:   PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);
4553:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4554:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4555:   numCIndices = numCIndices ? numCIndices : numRIndices;
4556:   for (i = 0; i < numRIndices; i++) {
4557:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4558:     for (j = 0; j < numCIndices; j++) {
4559: #if defined(PETSC_USE_COMPLEX)
4560:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4561: #else
4562:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4563: #endif
4564:     }
4565:     PetscViewerASCIIPrintf(viewer, "\n");
4566:   }
4567:   return(0);
4568: }

4570: /* . off - The global offset of this point */
4571: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4572: {
4573:   PetscInt        dof;    /* The number of unknowns on this point */
4574:   PetscInt        cdof;   /* The number of constraints on this point */
4575:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4576:   PetscInt        cind = 0, k;
4577:   PetscErrorCode  ierr;

4580:   PetscSectionGetDof(section, point, &dof);
4581:   PetscSectionGetConstraintDof(section, point, &cdof);
4582:   if (!cdof || setBC) {
4583:     if (perm) {
4584:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4585:     } else {
4586:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4587:     }
4588:   } else {
4589:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4590:     if (perm) {
4591:       for (k = 0; k < dof; ++k) {
4592:         if ((cind < cdof) && (k == cdofs[cind])) {
4593:           /* Insert check for returning constrained indices */
4594:           indices[*loff+perm[k]] = -(off+k+1);
4595:           ++cind;
4596:         } else {
4597:           indices[*loff+perm[k]] = off+k-cind;
4598:         }
4599:       }
4600:     } else {
4601:       for (k = 0; k < dof; ++k) {
4602:         if ((cind < cdof) && (k == cdofs[cind])) {
4603:           /* Insert check for returning constrained indices */
4604:           indices[*loff+k] = -(off+k+1);
4605:           ++cind;
4606:         } else {
4607:           indices[*loff+k] = off+k-cind;
4608:         }
4609:       }
4610:     }
4611:   }
4612:   *loff += dof;
4613:   return(0);
4614: }

4616: /* . off - The global offset of this point */
4617: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4618: {
4619:   PetscInt       numFields, foff, f;

4623:   PetscSectionGetNumFields(section, &numFields);
4624:   for (f = 0, foff = 0; f < numFields; ++f) {
4625:     PetscInt        fdof, cfdof;
4626:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4627:     PetscInt        cind = 0, b;
4628:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4630:     PetscSectionGetFieldDof(section, point, f, &fdof);
4631:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4632:     if (!cfdof || setBC) {
4633:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4634:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4635:     } else {
4636:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4637:       if (perm) {
4638:         for (b = 0; b < fdof; b++) {
4639:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4640:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4641:             ++cind;
4642:           } else {
4643:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4644:           }
4645:         }
4646:       } else {
4647:         for (b = 0; b < fdof; b++) {
4648:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4649:             indices[foffs[f]+b] = -(off+foff+b+1);
4650:             ++cind;
4651:           } else {
4652:             indices[foffs[f]+b] = off+foff+b-cind;
4653:           }
4654:         }
4655:       }
4656:     }
4657:     foff     += (setBC ? fdof : (fdof - cfdof));
4658:     foffs[f] += fdof;
4659:   }
4660:   return(0);
4661: }

4663: PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft)
4664: {
4665:   Mat             cMat;
4666:   PetscSection    aSec, cSec;
4667:   IS              aIS;
4668:   PetscInt        aStart = -1, aEnd = -1;
4669:   const PetscInt  *anchors;
4670:   PetscInt        numFields, f, p, q, newP = 0;
4671:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4672:   PetscInt        *newPoints, *indices, *newIndices;
4673:   PetscInt        maxAnchor, maxDof;
4674:   PetscInt        newOffsets[32];
4675:   PetscInt        *pointMatOffsets[32];
4676:   PetscInt        *newPointOffsets[32];
4677:   PetscScalar     *pointMat[32];
4678:   PetscScalar     *newValues=NULL,*tmpValues;
4679:   PetscBool       anyConstrained = PETSC_FALSE;
4680:   PetscErrorCode  ierr;

4685:   PetscSectionGetNumFields(section, &numFields);

4687:   DMPlexGetAnchors(dm,&aSec,&aIS);
4688:   /* if there are point-to-point constraints */
4689:   if (aSec) {
4690:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4691:     ISGetIndices(aIS,&anchors);
4692:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4693:     /* figure out how many points are going to be in the new element matrix
4694:      * (we allow double counting, because it's all just going to be summed
4695:      * into the global matrix anyway) */
4696:     for (p = 0; p < 2*numPoints; p+=2) {
4697:       PetscInt b    = points[p];
4698:       PetscInt bDof = 0, bSecDof;

4700:       PetscSectionGetDof(section,b,&bSecDof);
4701:       if (!bSecDof) {
4702:         continue;
4703:       }
4704:       if (b >= aStart && b < aEnd) {
4705:         PetscSectionGetDof(aSec,b,&bDof);
4706:       }
4707:       if (bDof) {
4708:         /* this point is constrained */
4709:         /* it is going to be replaced by its anchors */
4710:         PetscInt bOff, q;

4712:         anyConstrained = PETSC_TRUE;
4713:         newNumPoints  += bDof;
4714:         PetscSectionGetOffset(aSec,b,&bOff);
4715:         for (q = 0; q < bDof; q++) {
4716:           PetscInt a = anchors[bOff + q];
4717:           PetscInt aDof;

4719:           PetscSectionGetDof(section,a,&aDof);
4720:           newNumIndices += aDof;
4721:           for (f = 0; f < numFields; ++f) {
4722:             PetscInt fDof;

4724:             PetscSectionGetFieldDof(section, a, f, &fDof);
4725:             newOffsets[f+1] += fDof;
4726:           }
4727:         }
4728:       }
4729:       else {
4730:         /* this point is not constrained */
4731:         newNumPoints++;
4732:         newNumIndices += bSecDof;
4733:         for (f = 0; f < numFields; ++f) {
4734:           PetscInt fDof;

4736:           PetscSectionGetFieldDof(section, b, f, &fDof);
4737:           newOffsets[f+1] += fDof;
4738:         }
4739:       }
4740:     }
4741:   }
4742:   if (!anyConstrained) {
4743:     if (outNumPoints)  *outNumPoints  = 0;
4744:     if (outNumIndices) *outNumIndices = 0;
4745:     if (outPoints)     *outPoints     = NULL;
4746:     if (outValues)     *outValues     = NULL;
4747:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4748:     return(0);
4749:   }

4751:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4752:   if (outNumIndices) *outNumIndices = newNumIndices;

4754:   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];

4756:   if (!outPoints && !outValues) {
4757:     if (offsets) {
4758:       for (f = 0; f <= numFields; f++) {
4759:         offsets[f] = newOffsets[f];
4760:       }
4761:     }
4762:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4763:     return(0);
4764:   }

4766:   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);

4768:   DMGetDefaultConstraints(dm, &cSec, &cMat);

4770:   /* workspaces */
4771:   if (numFields) {
4772:     for (f = 0; f < numFields; f++) {
4773:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4774:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4775:     }
4776:   }
4777:   else {
4778:     DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4779:     DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
4780:   }

4782:   /* get workspaces for the point-to-point matrices */
4783:   if (numFields) {
4784:     PetscInt totalOffset, totalMatOffset;

4786:     for (p = 0; p < numPoints; p++) {
4787:       PetscInt b    = points[2*p];
4788:       PetscInt bDof = 0, bSecDof;

4790:       PetscSectionGetDof(section,b,&bSecDof);
4791:       if (!bSecDof) {
4792:         for (f = 0; f < numFields; f++) {
4793:           newPointOffsets[f][p + 1] = 0;
4794:           pointMatOffsets[f][p + 1] = 0;
4795:         }
4796:         continue;
4797:       }
4798:       if (b >= aStart && b < aEnd) {
4799:         PetscSectionGetDof(aSec, b, &bDof);
4800:       }
4801:       if (bDof) {
4802:         for (f = 0; f < numFields; f++) {
4803:           PetscInt fDof, q, bOff, allFDof = 0;

4805:           PetscSectionGetFieldDof(section, b, f, &fDof);
4806:           PetscSectionGetOffset(aSec, b, &bOff);
4807:           for (q = 0; q < bDof; q++) {
4808:             PetscInt a = anchors[bOff + q];
4809:             PetscInt aFDof;

4811:             PetscSectionGetFieldDof(section, a, f, &aFDof);
4812:             allFDof += aFDof;
4813:           }
4814:           newPointOffsets[f][p+1] = allFDof;
4815:           pointMatOffsets[f][p+1] = fDof * allFDof;
4816:         }
4817:       }
4818:       else {
4819:         for (f = 0; f < numFields; f++) {
4820:           PetscInt fDof;

4822:           PetscSectionGetFieldDof(section, b, f, &fDof);
4823:           newPointOffsets[f][p+1] = fDof;
4824:           pointMatOffsets[f][p+1] = 0;
4825:         }
4826:       }
4827:     }
4828:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4829:       newPointOffsets[f][0] = totalOffset;
4830:       pointMatOffsets[f][0] = totalMatOffset;
4831:       for (p = 0; p < numPoints; p++) {
4832:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4833:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4834:       }
4835:       totalOffset    = newPointOffsets[f][numPoints];
4836:       totalMatOffset = pointMatOffsets[f][numPoints];
4837:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4838:     }
4839:   }
4840:   else {
4841:     for (p = 0; p < numPoints; p++) {
4842:       PetscInt b    = points[2*p];
4843:       PetscInt bDof = 0, bSecDof;

4845:       PetscSectionGetDof(section,b,&bSecDof);
4846:       if (!bSecDof) {
4847:         newPointOffsets[0][p + 1] = 0;
4848:         pointMatOffsets[0][p + 1] = 0;
4849:         continue;
4850:       }
4851:       if (b >= aStart && b < aEnd) {
4852:         PetscSectionGetDof(aSec, b, &bDof);
4853:       }
4854:       if (bDof) {
4855:         PetscInt bOff, q, allDof = 0;

4857:         PetscSectionGetOffset(aSec, b, &bOff);
4858:         for (q = 0; q < bDof; q++) {
4859:           PetscInt a = anchors[bOff + q], aDof;

4861:           PetscSectionGetDof(section, a, &aDof);
4862:           allDof += aDof;
4863:         }
4864:         newPointOffsets[0][p+1] = allDof;
4865:         pointMatOffsets[0][p+1] = bSecDof * allDof;
4866:       }
4867:       else {
4868:         newPointOffsets[0][p+1] = bSecDof;
4869:         pointMatOffsets[0][p+1] = 0;
4870:       }
4871:     }
4872:     newPointOffsets[0][0] = 0;
4873:     pointMatOffsets[0][0] = 0;
4874:     for (p = 0; p < numPoints; p++) {
4875:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4876:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4877:     }
4878:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4879:   }

4881:   /* output arrays */
4882:   DMGetWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);

4884:   /* get the point-to-point matrices; construct newPoints */
4885:   PetscSectionGetMaxDof(aSec, &maxAnchor);
4886:   PetscSectionGetMaxDof(section, &maxDof);
4887:   DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
4888:   DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
4889:   if (numFields) {
4890:     for (p = 0, newP = 0; p < numPoints; p++) {
4891:       PetscInt b    = points[2*p];
4892:       PetscInt o    = points[2*p+1];
4893:       PetscInt bDof = 0, bSecDof;

4895:       PetscSectionGetDof(section, b, &bSecDof);
4896:       if (!bSecDof) {
4897:         continue;
4898:       }
4899:       if (b >= aStart && b < aEnd) {
4900:         PetscSectionGetDof(aSec, b, &bDof);
4901:       }
4902:       if (bDof) {
4903:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

4905:         fStart[0] = 0;
4906:         fEnd[0]   = 0;
4907:         for (f = 0; f < numFields; f++) {
4908:           PetscInt fDof;

4910:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
4911:           fStart[f+1] = fStart[f] + fDof;
4912:           fEnd[f+1]   = fStart[f+1];
4913:         }
4914:         PetscSectionGetOffset(cSec, b, &bOff);
4915:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

4917:         fAnchorStart[0] = 0;
4918:         fAnchorEnd[0]   = 0;
4919:         for (f = 0; f < numFields; f++) {
4920:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

4922:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4923:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4924:         }
4925:         PetscSectionGetOffset(aSec, b, &bOff);
4926:         for (q = 0; q < bDof; q++) {
4927:           PetscInt a = anchors[bOff + q], aOff;

4929:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4930:           newPoints[2*(newP + q)]     = a;
4931:           newPoints[2*(newP + q) + 1] = 0;
4932:           PetscSectionGetOffset(section, a, &aOff);
4933:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
4934:         }
4935:         newP += bDof;

4937:         if (outValues) {
4938:           /* get the point-to-point submatrix */
4939:           for (f = 0; f < numFields; f++) {
4940:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
4941:           }
4942:         }
4943:       }
4944:       else {
4945:         newPoints[2 * newP]     = b;
4946:         newPoints[2 * newP + 1] = o;
4947:         newP++;
4948:       }
4949:     }
4950:   } else {
4951:     for (p = 0; p < numPoints; p++) {
4952:       PetscInt b    = points[2*p];
4953:       PetscInt o    = points[2*p+1];
4954:       PetscInt bDof = 0, bSecDof;

4956:       PetscSectionGetDof(section, b, &bSecDof);
4957:       if (!bSecDof) {
4958:         continue;
4959:       }
4960:       if (b >= aStart && b < aEnd) {
4961:         PetscSectionGetDof(aSec, b, &bDof);
4962:       }
4963:       if (bDof) {
4964:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

4966:         PetscSectionGetOffset(cSec, b, &bOff);
4967:         DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);

4969:         PetscSectionGetOffset (aSec, b, &bOff);
4970:         for (q = 0; q < bDof; q++) {
4971:           PetscInt a = anchors[bOff + q], aOff;

4973:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */

4975:           newPoints[2*(newP + q)]     = a;
4976:           newPoints[2*(newP + q) + 1] = 0;
4977:           PetscSectionGetOffset(section, a, &aOff);
4978:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
4979:         }
4980:         newP += bDof;

4982:         /* get the point-to-point submatrix */
4983:         if (outValues) {
4984:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
4985:         }
4986:       }
4987:       else {
4988:         newPoints[2 * newP]     = b;
4989:         newPoints[2 * newP + 1] = o;
4990:         newP++;
4991:       }
4992:     }
4993:   }

4995:   if (outValues) {
4996:     DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
4997:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
4998:     /* multiply constraints on the right */
4999:     if (numFields) {
5000:       for (f = 0; f < numFields; f++) {
5001:         PetscInt oldOff = offsets[f];

5003:         for (p = 0; p < numPoints; p++) {
5004:           PetscInt cStart = newPointOffsets[f][p];
5005:           PetscInt b      = points[2 * p];
5006:           PetscInt c, r, k;
5007:           PetscInt dof;

5009:           PetscSectionGetFieldDof(section,b,f,&dof);
5010:           if (!dof) {
5011:             continue;
5012:           }
5013:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5014:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5015:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5017:             for (r = 0; r < numIndices; r++) {
5018:               for (c = 0; c < nCols; c++) {
5019:                 for (k = 0; k < dof; k++) {
5020:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5021:                 }
5022:               }
5023:             }
5024:           }
5025:           else {
5026:             /* copy this column as is */
5027:             for (r = 0; r < numIndices; r++) {
5028:               for (c = 0; c < dof; c++) {
5029:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5030:               }
5031:             }
5032:           }
5033:           oldOff += dof;
5034:         }
5035:       }
5036:     }
5037:     else {
5038:       PetscInt oldOff = 0;
5039:       for (p = 0; p < numPoints; p++) {
5040:         PetscInt cStart = newPointOffsets[0][p];
5041:         PetscInt b      = points[2 * p];
5042:         PetscInt c, r, k;
5043:         PetscInt dof;

5045:         PetscSectionGetDof(section,b,&dof);
5046:         if (!dof) {
5047:           continue;
5048:         }
5049:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5050:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5051:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5053:           for (r = 0; r < numIndices; r++) {
5054:             for (c = 0; c < nCols; c++) {
5055:               for (k = 0; k < dof; k++) {
5056:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5057:               }
5058:             }
5059:           }
5060:         }
5061:         else {
5062:           /* copy this column as is */
5063:           for (r = 0; r < numIndices; r++) {
5064:             for (c = 0; c < dof; c++) {
5065:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5066:             }
5067:           }
5068:         }
5069:         oldOff += dof;
5070:       }
5071:     }

5073:     if (multiplyLeft) {
5074:       DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5075:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5076:       /* multiply constraints transpose on the left */
5077:       if (numFields) {
5078:         for (f = 0; f < numFields; f++) {
5079:           PetscInt oldOff = offsets[f];

5081:           for (p = 0; p < numPoints; p++) {
5082:             PetscInt rStart = newPointOffsets[f][p];
5083:             PetscInt b      = points[2 * p];
5084:             PetscInt c, r, k;
5085:             PetscInt dof;

5087:             PetscSectionGetFieldDof(section,b,f,&dof);
5088:             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5089:               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
5090:               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];

5092:               for (r = 0; r < nRows; r++) {
5093:                 for (c = 0; c < newNumIndices; c++) {
5094:                   for (k = 0; k < dof; k++) {
5095:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5096:                   }
5097:                 }
5098:               }
5099:             }
5100:             else {
5101:               /* copy this row as is */
5102:               for (r = 0; r < dof; r++) {
5103:                 for (c = 0; c < newNumIndices; c++) {
5104:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5105:                 }
5106:               }
5107:             }
5108:             oldOff += dof;
5109:           }
5110:         }
5111:       }
5112:       else {
5113:         PetscInt oldOff = 0;

5115:         for (p = 0; p < numPoints; p++) {
5116:           PetscInt rStart = newPointOffsets[0][p];
5117:           PetscInt b      = points[2 * p];
5118:           PetscInt c, r, k;
5119:           PetscInt dof;

5121:           PetscSectionGetDof(section,b,&dof);
5122:           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5123:             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
5124:             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];

5126:             for (r = 0; r < nRows; r++) {
5127:               for (c = 0; c < newNumIndices; c++) {
5128:                 for (k = 0; k < dof; k++) {
5129:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5130:                 }
5131:               }
5132:             }
5133:           }
5134:           else {
5135:             /* copy this row as is */
5136:             for (r = 0; r < dof; r++) {
5137:               for (c = 0; c < newNumIndices; c++) {
5138:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5139:               }
5140:             }
5141:           }
5142:           oldOff += dof;
5143:         }
5144:       }

5146:       DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5147:     }
5148:     else {
5149:       newValues = tmpValues;
5150:     }
5151:   }

5153:   /* clean up */
5154:   DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
5155:   DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);

5157:   if (numFields) {
5158:     for (f = 0; f < numFields; f++) {
5159:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
5160:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
5161:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
5162:     }
5163:   }
5164:   else {
5165:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
5166:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
5167:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
5168:   }
5169:   ISRestoreIndices(aIS,&anchors);

5171:   /* output */
5172:   if (outPoints) {
5173:     *outPoints = newPoints;
5174:   }
5175:   else {
5176:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5177:   }
5178:   if (outValues) {
5179:     *outValues = newValues;
5180:   }
5181:   for (f = 0; f <= numFields; f++) {
5182:     offsets[f] = newOffsets[f];
5183:   }
5184:   return(0);
5185: }

5187: /*@C
5188:   DMPlexGetClosureIndices - Get the indices in a vector v for all points in the closure of the given point

5190:   Not collective

5192:   Input Parameters:
5193: + dm - The DM
5194: . section - The section describing the layout in v, or NULL to use the default section
5195: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5196: - point - The mesh point

5198:   Output parameters:
5199: + numIndices - The number of indices
5200: . indices - The indices
5201: - outOffsets - Field offset if not NULL

5203:   Note: Must call DMPlexRestoreClosureIndices() to free allocated memory

5205:   Level: advanced

5207: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5208: @*/
5209: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5210: {
5211:   PetscSection    clSection;
5212:   IS              clPoints;
5213:   const PetscInt *clp;
5214:   const PetscInt  **perms[32] = {NULL};
5215:   PetscInt       *points = NULL, *pointsNew;
5216:   PetscInt        numPoints, numPointsNew;
5217:   PetscInt        offsets[32];
5218:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5219:   PetscErrorCode  ierr;

5227:   PetscSectionGetNumFields(section, &Nf);
5228:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5229:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5230:   /* Get points in closure */
5231:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5232:   /* Get number of indices and indices per field */
5233:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5234:     PetscInt dof, fdof;

5236:     PetscSectionGetDof(section, points[p], &dof);
5237:     for (f = 0; f < Nf; ++f) {
5238:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5239:       offsets[f+1] += fdof;
5240:     }
5241:     Nind += dof;
5242:   }
5243:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5244:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5245:   if (!Nf) offsets[1] = Nind;
5246:   /* Get dual space symmetries */
5247:   for (f = 0; f < PetscMax(1,Nf); f++) {
5248:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5249:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5250:   }
5251:   /* Correct for hanging node constraints */
5252:   {
5253:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5254:     if (numPointsNew) {
5255:       for (f = 0; f < PetscMax(1,Nf); f++) {
5256:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5257:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5258:       }
5259:       for (f = 0; f < PetscMax(1,Nf); f++) {
5260:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5261:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5262:       }
5263:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5264:       numPoints = numPointsNew;
5265:       Nind      = NindNew;
5266:       points    = pointsNew;
5267:     }
5268:   }
5269:   /* Calculate indices */
5270:   DMGetWorkArray(dm, Nind, PETSC_INT, indices);
5271:   if (Nf) {
5272:     if (outOffsets) {
5273:       PetscInt f;

5275:       for (f = 0; f <= Nf; f++) {
5276:         outOffsets[f] = offsets[f];
5277:       }
5278:     }
5279:     for (p = 0; p < numPoints; p++) {
5280:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5281:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5282:     }
5283:   } else {
5284:     for (p = 0, off = 0; p < numPoints; p++) {
5285:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5287:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5288:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5289:     }
5290:   }
5291:   /* Cleanup points */
5292:   for (f = 0; f < PetscMax(1,Nf); f++) {
5293:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5294:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5295:   }
5296:   if (numPointsNew) {
5297:     DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);
5298:   } else {
5299:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5300:   }
5301:   if (numIndices) *numIndices = Nind;
5302:   return(0);
5303: }

5305: /*@C
5306:   DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point

5308:   Not collective

5310:   Input Parameters:
5311: + dm - The DM
5312: . section - The section describing the layout in v, or NULL to use the default section
5313: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5314: . point - The mesh point
5315: . numIndices - The number of indices
5316: . indices - The indices
5317: - outOffsets - Field offset if not NULL

5319:   Level: advanced

5321: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5322: @*/
5323: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5324: {

5330:   DMRestoreWorkArray(dm, 0, PETSC_INT, indices);
5331:   return(0);
5332: }

5334: /*@C
5335:   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'

5337:   Not collective

5339:   Input Parameters:
5340: + dm - The DM
5341: . section - The section describing the layout in v, or NULL to use the default section
5342: . globalSection - The section describing the layout in v, or NULL to use the default global section
5343: . A - The matrix
5344: . point - The sieve point in the DM
5345: . values - The array of values
5346: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

5348:   Fortran Notes:
5349:   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.

5351:   Level: intermediate

5353: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5354: @*/
5355: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5356: {
5357:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5358:   PetscSection        clSection;
5359:   IS                  clPoints;
5360:   PetscInt           *points = NULL, *newPoints;
5361:   const PetscInt     *clp;
5362:   PetscInt           *indices;
5363:   PetscInt            offsets[32];
5364:   const PetscInt    **perms[32] = {NULL};
5365:   const PetscScalar **flips[32] = {NULL};
5366:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5367:   PetscScalar        *valCopy = NULL;
5368:   PetscScalar        *newValues;
5369:   PetscErrorCode      ierr;

5373:   if (!section) {DMGetDefaultSection(dm, &section);}
5375:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5378:   PetscSectionGetNumFields(section, &numFields);
5379:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5380:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5381:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5382:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5383:     PetscInt fdof;

5385:     PetscSectionGetDof(section, points[p], &dof);
5386:     for (f = 0; f < numFields; ++f) {
5387:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5388:       offsets[f+1] += fdof;
5389:     }
5390:     numIndices += dof;
5391:   }
5392:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

5394:   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5395:   /* Get symmetries */
5396:   for (f = 0; f < PetscMax(1,numFields); f++) {
5397:     if (numFields) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5398:     else           {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5399:     if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5400:       PetscInt foffset = offsets[f];

5402:       for (p = 0; p < numPoints; p++) {
5403:         PetscInt point          = points[2*p], fdof;
5404:         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;

5406:         if (!numFields) {
5407:           PetscSectionGetDof(section,point,&fdof);
5408:         } else {
5409:           PetscSectionGetFieldDof(section,point,f,&fdof);
5410:         }
5411:         if (flip) {
5412:           PetscInt i, j, k;

5414:           if (!valCopy) {
5415:             DMGetWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5416:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5417:             values = valCopy;
5418:           }
5419:           for (i = 0; i < fdof; i++) {
5420:             PetscScalar fval = flip[i];

5422:             for (k = 0; k < numIndices; k++) {
5423:               valCopy[numIndices * (foffset + i) + k] *= fval;
5424:               valCopy[numIndices * k + (foffset + i)] *= fval;
5425:             }
5426:           }
5427:         }
5428:         foffset += fdof;
5429:       }
5430:     }
5431:   }
5432:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5433:   if (newNumPoints) {
5434:     if (valCopy) {
5435:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5436:     }
5437:     for (f = 0; f < PetscMax(1,numFields); f++) {
5438:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5439:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5440:     }
5441:     for (f = 0; f < PetscMax(1,numFields); f++) {
5442:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5443:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5444:     }
5445:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5446:     numPoints  = newNumPoints;
5447:     numIndices = newNumIndices;
5448:     points     = newPoints;
5449:     values     = newValues;
5450:   }
5451:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5452:   if (numFields) {
5453:     for (p = 0; p < numPoints; p++) {
5454:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5455:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5456:     }
5457:   } else {
5458:     for (p = 0, off = 0; p < numPoints; p++) {
5459:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5460:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5461:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5462:     }
5463:   }
5464:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5465:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5466:   if (mesh->printFEM > 1) {
5467:     PetscInt i;
5468:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5469:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5470:     PetscPrintf(PETSC_COMM_SELF, "\n");
5471:   }
5472:   if (ierr) {
5473:     PetscMPIInt    rank;
5474:     PetscErrorCode ierr2;

5476:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5477:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5478:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5479:     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5480: 
5481:   }
5482:   for (f = 0; f < PetscMax(1,numFields); f++) {
5483:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5484:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5485:   }
5486:   if (newNumPoints) {
5487:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5488:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5489:   }
5490:   else {
5491:     if (valCopy) {
5492:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5493:     }
5494:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5495:   }
5496:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5497:   return(0);
5498: }

5500: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5501: {
5502:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5503:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5504:   PetscInt       *cpoints = NULL;
5505:   PetscInt       *findices, *cindices;
5506:   PetscInt        foffsets[32], coffsets[32];
5507:   CellRefiner     cellRefiner;
5508:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5509:   PetscErrorCode  ierr;

5514:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5516:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5518:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5520:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5523:   PetscSectionGetNumFields(fsection, &numFields);
5524:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5525:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5526:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5527:   /* Column indices */
5528:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5529:   maxFPoints = numCPoints;
5530:   /* Compress out points not in the section */
5531:   /*   TODO: Squeeze out points with 0 dof as well */
5532:   PetscSectionGetChart(csection, &pStart, &pEnd);
5533:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5534:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5535:       cpoints[q*2]   = cpoints[p];
5536:       cpoints[q*2+1] = cpoints[p+1];
5537:       ++q;
5538:     }
5539:   }
5540:   numCPoints = q;
5541:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5542:     PetscInt fdof;

5544:     PetscSectionGetDof(csection, cpoints[p], &dof);
5545:     if (!dof) continue;
5546:     for (f = 0; f < numFields; ++f) {
5547:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5548:       coffsets[f+1] += fdof;
5549:     }
5550:     numCIndices += dof;
5551:   }
5552:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5553:   /* Row indices */
5554:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5555:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5556:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5557:   for (r = 0, q = 0; r < numSubcells; ++r) {
5558:     /* TODO Map from coarse to fine cells */
5559:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5560:     /* Compress out points not in the section */
5561:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5562:     for (p = 0; p < numFPoints*2; p += 2) {
5563:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5564:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5565:         if (!dof) continue;
5566:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5567:         if (s < q) continue;
5568:         ftotpoints[q*2]   = fpoints[p];
5569:         ftotpoints[q*2+1] = fpoints[p+1];
5570:         ++q;
5571:       }
5572:     }
5573:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5574:   }
5575:   numFPoints = q;
5576:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5577:     PetscInt fdof;

5579:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5580:     if (!dof) continue;
5581:     for (f = 0; f < numFields; ++f) {
5582:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5583:       foffsets[f+1] += fdof;
5584:     }
5585:     numFIndices += dof;
5586:   }
5587:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5589:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5590:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5591:   DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5592:   DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5593:   if (numFields) {
5594:     const PetscInt **permsF[32] = {NULL};
5595:     const PetscInt **permsC[32] = {NULL};

5597:     for (f = 0; f < numFields; f++) {
5598:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5599:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5600:     }
5601:     for (p = 0; p < numFPoints; p++) {
5602:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5603:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5604:     }
5605:     for (p = 0; p < numCPoints; p++) {
5606:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5607:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5608:     }
5609:     for (f = 0; f < numFields; f++) {
5610:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5611:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5612:     }
5613:   } else {
5614:     const PetscInt **permsF = NULL;
5615:     const PetscInt **permsC = NULL;

5617:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5618:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5619:     for (p = 0, off = 0; p < numFPoints; p++) {
5620:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5622:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5623:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5624:     }
5625:     for (p = 0, off = 0; p < numCPoints; p++) {
5626:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5628:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5629:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5630:     }
5631:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5632:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5633:   }
5634:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5635:   /* TODO: flips */
5636:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5637:   if (ierr) {
5638:     PetscMPIInt    rank;
5639:     PetscErrorCode ierr2;

5641:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5642:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5643:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5644:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5645:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5646: 
5647:   }
5648:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5649:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5650:   DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5651:   DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5652:   return(0);
5653: }

5655: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5656: {
5657:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5658:   PetscInt      *cpoints = NULL;
5659:   PetscInt       foffsets[32], coffsets[32];
5660:   CellRefiner    cellRefiner;
5661:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

5667:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5669:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5671:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5673:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5675:   PetscSectionGetNumFields(fsection, &numFields);
5676:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5677:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5678:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5679:   /* Column indices */
5680:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5681:   maxFPoints = numCPoints;
5682:   /* Compress out points not in the section */
5683:   /*   TODO: Squeeze out points with 0 dof as well */
5684:   PetscSectionGetChart(csection, &pStart, &pEnd);
5685:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5686:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5687:       cpoints[q*2]   = cpoints[p];
5688:       cpoints[q*2+1] = cpoints[p+1];
5689:       ++q;
5690:     }
5691:   }
5692:   numCPoints = q;
5693:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5694:     PetscInt fdof;

5696:     PetscSectionGetDof(csection, cpoints[p], &dof);
5697:     if (!dof) continue;
5698:     for (f = 0; f < numFields; ++f) {
5699:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5700:       coffsets[f+1] += fdof;
5701:     }
5702:     numCIndices += dof;
5703:   }
5704:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5705:   /* Row indices */
5706:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5707:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5708:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5709:   for (r = 0, q = 0; r < numSubcells; ++r) {
5710:     /* TODO Map from coarse to fine cells */
5711:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5712:     /* Compress out points not in the section */
5713:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5714:     for (p = 0; p < numFPoints*2; p += 2) {
5715:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5716:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5717:         if (!dof) continue;
5718:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5719:         if (s < q) continue;
5720:         ftotpoints[q*2]   = fpoints[p];
5721:         ftotpoints[q*2+1] = fpoints[p+1];
5722:         ++q;
5723:       }
5724:     }
5725:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5726:   }
5727:   numFPoints = q;
5728:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5729:     PetscInt fdof;

5731:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5732:     if (!dof) continue;
5733:     for (f = 0; f < numFields; ++f) {
5734:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5735:       foffsets[f+1] += fdof;
5736:     }
5737:     numFIndices += dof;
5738:   }
5739:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5741:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5742:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5743:   if (numFields) {
5744:     const PetscInt **permsF[32] = {NULL};
5745:     const PetscInt **permsC[32] = {NULL};

5747:     for (f = 0; f < numFields; f++) {
5748:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5749:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5750:     }
5751:     for (p = 0; p < numFPoints; p++) {
5752:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5753:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5754:     }
5755:     for (p = 0; p < numCPoints; p++) {
5756:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5757:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5758:     }
5759:     for (f = 0; f < numFields; f++) {
5760:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5761:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5762:     }
5763:   } else {
5764:     const PetscInt **permsF = NULL;
5765:     const PetscInt **permsC = NULL;

5767:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5768:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5769:     for (p = 0, off = 0; p < numFPoints; p++) {
5770:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5772:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5773:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5774:     }
5775:     for (p = 0, off = 0; p < numCPoints; p++) {
5776:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5778:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5779:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5780:     }
5781:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5782:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5783:   }
5784:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5785:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5786:   return(0);
5787: }

5789: /*@
5790:   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid

5792:   Input Parameter:
5793: . dm - The DMPlex object

5795:   Output Parameters:
5796: + cMax - The first hybrid cell
5797: . fMax - The first hybrid face
5798: . eMax - The first hybrid edge
5799: - vMax - The first hybrid vertex

5801:   Level: developer

5803: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5804: @*/
5805: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5806: {
5807:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5808:   PetscInt       dim;

5813:   DMGetDimension(dm, &dim);
5814:   if (cMax) *cMax = mesh->hybridPointMax[dim];
5815:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5816:   if (eMax) *eMax = mesh->hybridPointMax[1];
5817:   if (vMax) *vMax = mesh->hybridPointMax[0];
5818:   return(0);
5819: }

5821: /*@
5822:   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid

5824:   Input Parameters:
5825: . dm   - The DMPlex object
5826: . cMax - The first hybrid cell
5827: . fMax - The first hybrid face
5828: . eMax - The first hybrid edge
5829: - vMax - The first hybrid vertex

5831:   Level: developer

5833: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5834: @*/
5835: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5836: {
5837:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5838:   PetscInt       dim;

5843:   DMGetDimension(dm, &dim);
5844:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5845:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5846:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5847:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5848:   return(0);
5849: }

5851: /*@C
5852:   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)

5854:   Input Parameter:
5855: . dm   - The DMPlex object

5857:   Output Parameter:
5858: . cellHeight - The height of a cell

5860:   Level: developer

5862: .seealso DMPlexSetVTKCellHeight()
5863: @*/
5864: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5865: {
5866:   DM_Plex *mesh = (DM_Plex*) dm->data;

5871:   *cellHeight = mesh->vtkCellHeight;
5872:   return(0);
5873: }

5875: /*@C
5876:   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)

5878:   Input Parameters:
5879: + dm   - The DMPlex object
5880: - cellHeight - The height of a cell

5882:   Level: developer

5884: .seealso DMPlexGetVTKCellHeight()
5885: @*/
5886: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5887: {
5888:   DM_Plex *mesh = (DM_Plex*) dm->data;

5892:   mesh->vtkCellHeight = cellHeight;
5893:   return(0);
5894: }

5896: /* We can easily have a form that takes an IS instead */
5897: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5898: {
5899:   PetscSection   section, globalSection;
5900:   PetscInt      *numbers, p;

5904:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
5905:   PetscSectionSetChart(section, pStart, pEnd);
5906:   for (p = pStart; p < pEnd; ++p) {
5907:     PetscSectionSetDof(section, p, 1);
5908:   }
5909:   PetscSectionSetUp(section);
5910:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
5911:   PetscMalloc1(pEnd - pStart, &numbers);
5912:   for (p = pStart; p < pEnd; ++p) {
5913:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5914:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5915:     else                       numbers[p-pStart] += shift;
5916:   }
5917:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5918:   if (globalSize) {
5919:     PetscLayout layout;
5920:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
5921:     PetscLayoutGetSize(layout, globalSize);
5922:     PetscLayoutDestroy(&layout);
5923:   }
5924:   PetscSectionDestroy(&section);
5925:   PetscSectionDestroy(&globalSection);
5926:   return(0);
5927: }

5929: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5930: {
5931:   PetscInt       cellHeight, cStart, cEnd, cMax;

5935:   DMPlexGetVTKCellHeight(dm, &cellHeight);
5936:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5937:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5938:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5939:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
5940:   return(0);
5941: }

5943: /*@C
5944:   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process

5946:   Input Parameter:
5947: . dm   - The DMPlex object

5949:   Output Parameter:
5950: . globalCellNumbers - Global cell numbers for all cells on this process

5952:   Level: developer

5954: .seealso DMPlexGetVertexNumbering()
5955: @*/
5956: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5957: {
5958:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5963:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
5964:   *globalCellNumbers = mesh->globalCellNumbers;
5965:   return(0);
5966: }

5968: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
5969: {
5970:   PetscInt       vStart, vEnd, vMax;

5975:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5976:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
5977:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
5978:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
5979:   return(0);
5980: }

5982: /*@C
5983:   DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process

5985:   Input Parameter:
5986: . dm   - The DMPlex object

5988:   Output Parameter:
5989: . globalVertexNumbers - Global vertex numbers for all vertices on this process

5991:   Level: developer

5993: .seealso DMPlexGetCellNumbering()
5994: @*/
5995: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5996: {
5997:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6002:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6003:   *globalVertexNumbers = mesh->globalVertexNumbers;
6004:   return(0);
6005: }

6007: /*@C
6008:   DMPlexCreatePointNumbering - Create a global numbering for all points on this process

6010:   Input Parameter:
6011: . dm   - The DMPlex object

6013:   Output Parameter:
6014: . globalPointNumbers - Global numbers for all points on this process

6016:   Level: developer

6018: .seealso DMPlexGetCellNumbering()
6019: @*/
6020: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6021: {
6022:   IS             nums[4];
6023:   PetscInt       depths[4];
6024:   PetscInt       depth, d, shift = 0;

6029:   DMPlexGetDepth(dm, &depth);
6030:   /* For unstratified meshes use dim instead of depth */
6031:   if (depth < 0) {DMGetDimension(dm, &depth);}
6032:   depths[0] = depth; depths[1] = 0;
6033:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6034:   for (d = 0; d <= depth; ++d) {
6035:     PetscInt pStart, pEnd, gsize;

6037:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6038:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6039:     shift += gsize;
6040:   }
6041:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6042:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6043:   return(0);
6044: }

6046: /*@
6047:   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.

6049:   Input Parameters:
6050:   + dm - The DMPlex object

6052:   Note: This is a useful diagnostic when creating meshes programmatically.

6054:   Level: developer

6056: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6057: @*/
6058: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6059: {
6060:   PetscSection    coneSection, supportSection;
6061:   const PetscInt *cone, *support;
6062:   PetscInt        coneSize, c, supportSize, s;
6063:   PetscInt        pStart, pEnd, p, csize, ssize;
6064:   PetscErrorCode  ierr;

6068:   DMPlexGetConeSection(dm, &coneSection);
6069:   DMPlexGetSupportSection(dm, &supportSection);
6070:   /* Check that point p is found in the support of its cone points, and vice versa */
6071:   DMPlexGetChart(dm, &pStart, &pEnd);
6072:   for (p = pStart; p < pEnd; ++p) {
6073:     DMPlexGetConeSize(dm, p, &coneSize);
6074:     DMPlexGetCone(dm, p, &cone);
6075:     for (c = 0; c < coneSize; ++c) {
6076:       PetscBool dup = PETSC_FALSE;
6077:       PetscInt  d;
6078:       for (d = c-1; d >= 0; --d) {
6079:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6080:       }
6081:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6082:       DMPlexGetSupport(dm, cone[c], &support);
6083:       for (s = 0; s < supportSize; ++s) {
6084:         if (support[s] == p) break;
6085:       }
6086:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6087:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6088:         for (s = 0; s < coneSize; ++s) {
6089:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6090:         }
6091:         PetscPrintf(PETSC_COMM_SELF, "\n");
6092:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6093:         for (s = 0; s < supportSize; ++s) {
6094:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6095:         }
6096:         PetscPrintf(PETSC_COMM_SELF, "\n");
6097:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6098:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6099:       }
6100:     }
6101:     DMPlexGetSupportSize(dm, p, &supportSize);
6102:     DMPlexGetSupport(dm, p, &support);
6103:     for (s = 0; s < supportSize; ++s) {
6104:       DMPlexGetConeSize(dm, support[s], &coneSize);
6105:       DMPlexGetCone(dm, support[s], &cone);
6106:       for (c = 0; c < coneSize; ++c) {
6107:         if (cone[c] == p) break;
6108:       }
6109:       if (c >= coneSize) {
6110:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6111:         for (c = 0; c < supportSize; ++c) {
6112:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6113:         }
6114:         PetscPrintf(PETSC_COMM_SELF, "\n");
6115:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6116:         for (c = 0; c < coneSize; ++c) {
6117:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6118:         }
6119:         PetscPrintf(PETSC_COMM_SELF, "\n");
6120:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6121:       }
6122:     }
6123:   }
6124:   PetscSectionGetStorageSize(coneSection, &csize);
6125:   PetscSectionGetStorageSize(supportSection, &ssize);
6126:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6127:   return(0);
6128: }

6130: /*@
6131:   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices

6133:   Input Parameters:
6134: + dm - The DMPlex object
6135: . isSimplex - Are the cells simplices or tensor products
6136: - cellHeight - Normally 0

6138:   Note: This is a useful diagnostic when creating meshes programmatically.

6140:   Level: developer

6142: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6143: @*/
6144: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6145: {
6146:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6151:   DMGetDimension(dm, &dim);
6152:   switch (dim) {
6153:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6154:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6155:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6156:   default:
6157:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6158:   }
6159:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6160:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6161:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6162:   cMax = cMax >= 0 ? cMax : cEnd;
6163:   for (c = cStart; c < cMax; ++c) {
6164:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6166:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6167:     for (cl = 0; cl < closureSize*2; cl += 2) {
6168:       const PetscInt p = closure[cl];
6169:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6170:     }
6171:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6172:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6173:   }
6174:   for (c = cMax; c < cEnd; ++c) {
6175:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6177:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6178:     for (cl = 0; cl < closureSize*2; cl += 2) {
6179:       const PetscInt p = closure[cl];
6180:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6181:     }
6182:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6183:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6184:   }
6185:   return(0);
6186: }

6188: /*@
6189:   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type

6191:   Input Parameters:
6192: + dm - The DMPlex object
6193: . isSimplex - Are the cells simplices or tensor products
6194: - cellHeight - Normally 0

6196:   Note: This is a useful diagnostic when creating meshes programmatically.

6198:   Level: developer

6200: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6201: @*/
6202: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6203: {
6204:   PetscInt       pMax[4];
6205:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6210:   DMGetDimension(dm, &dim);
6211:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6212:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6213:   for (h = cellHeight; h < dim; ++h) {
6214:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6215:     for (c = cStart; c < cEnd; ++c) {
6216:       const PetscInt *cone, *ornt, *faces;
6217:       PetscInt        numFaces, faceSize, coneSize,f;
6218:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6220:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6221:       DMPlexGetConeSize(dm, c, &coneSize);
6222:       DMPlexGetCone(dm, c, &cone);
6223:       DMPlexGetConeOrientation(dm, c, &ornt);
6224:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6225:       for (cl = 0; cl < closureSize*2; cl += 2) {
6226:         const PetscInt p = closure[cl];
6227:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6228:       }
6229:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6230:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6231:       for (f = 0; f < numFaces; ++f) {
6232:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6234:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6235:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6236:           const PetscInt p = fclosure[cl];
6237:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6238:         }
6239:         if (fnumCorners != faceSize) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D (%D) of cell %D has %D vertices but should have %D", cone[f], f, c, fnumCorners, faceSize);
6240:         for (v = 0; v < fnumCorners; ++v) {
6241:           if (fclosure[v] != faces[f*faceSize+v]) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D (%d) of cell %D vertex %D, %D != %D", cone[f], f, c, v, fclosure[v], faces[f*faceSize+v]);
6242:         }
6243:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6244:       }
6245:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6246:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6247:     }
6248:   }
6249:   return(0);
6250: }

6252: /* Pointwise interpolation
6253:      Just code FEM for now
6254:      u^f = I u^c
6255:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6256:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6257:      I_{ij} = psi^f_i phi^c_j
6258: */
6259: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6260: {
6261:   PetscSection   gsc, gsf;
6262:   PetscInt       m, n;
6263:   void          *ctx;
6264:   DM             cdm;
6265:   PetscBool      regular;

6269:   DMGetDefaultGlobalSection(dmFine, &gsf);
6270:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6271:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6272:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6274:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6275:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6276:   MatSetType(*interpolation, dmCoarse->mattype);
6277:   DMGetApplicationContext(dmFine, &ctx);

6279:   DMGetCoarseDM(dmFine, &cdm);
6280:   DMPlexGetRegularRefinement(dmFine, &regular);
6281:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6282:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6283:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6284:   /* Use naive scaling */
6285:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6286:   return(0);
6287: }

6289: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6290: {
6292:   VecScatter     ctx;

6295:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6296:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6297:   VecScatterDestroy(&ctx);
6298:   return(0);
6299: }

6301: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6302: {
6303:   PetscSection   section;
6304:   IS            *bcPoints, *bcComps;
6305:   PetscBool     *isFE;
6306:   PetscInt      *bcFields, *numComp, *numDof;
6307:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6308:   PetscInt       cStart, cEnd, cEndInterior;

6312:   DMGetNumFields(dm, &numFields);
6313:   if (!numFields) return(0);
6314:   /* FE and FV boundary conditions are handled slightly differently */
6315:   PetscMalloc1(numFields, &isFE);
6316:   for (f = 0; f < numFields; ++f) {
6317:     PetscObject  obj;
6318:     PetscClassId id;

6320:     DMGetField(dm, f, &obj);
6321:     PetscObjectGetClassId(obj, &id);
6322:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6323:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6324:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6325:   }
6326:   /* Allocate boundary point storage for FEM boundaries */
6327:   DMPlexGetDepth(dm, &depth);
6328:   DMGetDimension(dm, &dim);
6329:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6330:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6331:   PetscDSGetNumBoundary(dm->prob, &numBd);
6332:   for (bd = 0; bd < numBd; ++bd) {
6333:     PetscInt                field;
6334:     DMBoundaryConditionType type;
6335:     const char             *labelName;
6336:     DMLabel                 label;

6338:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6339:     DMGetLabel(dm,labelName,&label);
6340:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6341:   }
6342:   /* Add ghost cell boundaries for FVM */
6343:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6344:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6345:   /* Constrain ghost cells for FV */
6346:   for (f = 0; f < numFields; ++f) {
6347:     PetscInt *newidx, c;

6349:     if (isFE[f] || cEndInterior < 0) continue;
6350:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6351:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6352:     bcFields[bc] = f;
6353:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6354:   }
6355:   /* Handle FEM Dirichlet boundaries */
6356:   for (bd = 0; bd < numBd; ++bd) {
6357:     const char             *bdLabel;
6358:     DMLabel                 label;
6359:     const PetscInt         *comps;
6360:     const PetscInt         *values;
6361:     PetscInt                bd2, field, numComps, numValues;
6362:     DMBoundaryConditionType type;
6363:     PetscBool               duplicate = PETSC_FALSE;

6365:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6366:     DMGetLabel(dm, bdLabel, &label);
6367:     if (!isFE[field] || !label) continue;
6368:     /* Only want to modify label once */
6369:     for (bd2 = 0; bd2 < bd; ++bd2) {
6370:       const char *bdname;
6371:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6372:       PetscStrcmp(bdname, bdLabel, &duplicate);
6373:       if (duplicate) break;
6374:     }
6375:     if (!duplicate && (isFE[field])) {
6376:       /* don't complete cells, which are just present to give orientation to the boundary */
6377:       DMPlexLabelComplete(dm, label);
6378:     }
6379:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6380:     if (type & DM_BC_ESSENTIAL) {
6381:       PetscInt       *newidx;
6382:       PetscInt        n, newn = 0, p, v;

6384:       bcFields[bc] = field;
6385:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6386:       for (v = 0; v < numValues; ++v) {
6387:         IS              tmp;
6388:         const PetscInt *idx;

6390:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6391:         if (!tmp) continue;
6392:         ISGetLocalSize(tmp, &n);
6393:         ISGetIndices(tmp, &idx);
6394:         if (isFE[field]) {
6395:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6396:         } else {
6397:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6398:         }
6399:         ISRestoreIndices(tmp, &idx);
6400:         ISDestroy(&tmp);
6401:       }
6402:       PetscMalloc1(newn,&newidx);
6403:       newn = 0;
6404:       for (v = 0; v < numValues; ++v) {
6405:         IS              tmp;
6406:         const PetscInt *idx;

6408:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6409:         if (!tmp) continue;
6410:         ISGetLocalSize(tmp, &n);
6411:         ISGetIndices(tmp, &idx);
6412:         if (isFE[field]) {
6413:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6414:         } else {
6415:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6416:         }
6417:         ISRestoreIndices(tmp, &idx);
6418:         ISDestroy(&tmp);
6419:       }
6420:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6421:     }
6422:   }
6423:   /* Handle discretization */
6424:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6425:   for (f = 0; f < numFields; ++f) {
6426:     PetscObject obj;

6428:     DMGetField(dm, f, &obj);
6429:     if (isFE[f]) {
6430:       PetscFE         fe = (PetscFE) obj;
6431:       const PetscInt *numFieldDof;
6432:       PetscInt        d;

6434:       PetscFEGetNumComponents(fe, &numComp[f]);
6435:       PetscFEGetNumDof(fe, &numFieldDof);
6436:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6437:     } else {
6438:       PetscFV fv = (PetscFV) obj;

6440:       PetscFVGetNumComponents(fv, &numComp[f]);
6441:       numDof[f*(dim+1)+dim] = numComp[f];
6442:     }
6443:   }
6444:   for (f = 0; f < numFields; ++f) {
6445:     PetscInt d;
6446:     for (d = 1; d < dim; ++d) {
6447:       if ((numDof[f*(dim+1)+d] > 0) && (depth < dim)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces.");
6448:     }
6449:   }
6450:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6451:   for (f = 0; f < numFields; ++f) {
6452:     PetscFE     fe;
6453:     const char *name;

6455:     DMGetField(dm, f, (PetscObject *) &fe);
6456:     PetscObjectGetName((PetscObject) fe, &name);
6457:     PetscSectionSetFieldName(section, f, name);
6458:   }
6459:   DMSetDefaultSection(dm, section);
6460:   PetscSectionDestroy(&section);
6461:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6462:   PetscFree3(bcFields,bcPoints,bcComps);
6463:   PetscFree2(numComp,numDof);
6464:   PetscFree(isFE);
6465:   return(0);
6466: }

6468: /*@
6469:   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh

6471:   Input Parameter:
6472: . dm - The DMPlex object

6474:   Output Parameter:
6475: . regular - The flag

6477:   Level: intermediate

6479: .seealso: DMPlexSetRegularRefinement()
6480: @*/
6481: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6482: {
6486:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6487:   return(0);
6488: }

6490: /*@
6491:   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh

6493:   Input Parameters:
6494: + dm - The DMPlex object
6495: - regular - The flag

6497:   Level: intermediate

6499: .seealso: DMPlexGetRegularRefinement()
6500: @*/
6501: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6502: {
6505:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6506:   return(0);
6507: }

6509: /* anchors */
6510: /*@
6511:   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
6512:   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().

6514:   not collective

6516:   Input Parameters:
6517: . dm - The DMPlex object

6519:   Output Parameters:
6520: + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
6521: - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection


6524:   Level: intermediate

6526: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6527: @*/
6528: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6529: {
6530:   DM_Plex *plex = (DM_Plex *)dm->data;

6535:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6536:   if (anchorSection) *anchorSection = plex->anchorSection;
6537:   if (anchorIS) *anchorIS = plex->anchorIS;
6538:   return(0);
6539: }

6541: /*@
6542:   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
6543:   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
6544:   point's degrees of freedom to be a linear combination of other points' degrees of freedom.

6546:   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
6547:   DMGetConstraints() and filling in the entries in the constraint matrix.

6549:   collective on dm

6551:   Input Parameters:
6552: + dm - The DMPlex object
6553: . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.  Must have a local communicator (PETSC_COMM_SELF or derivative).
6554: - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).

6556:   The reference counts of anchorSection and anchorIS are incremented.

6558:   Level: intermediate

6560: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6561: @*/
6562: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6563: {
6564:   DM_Plex        *plex = (DM_Plex *)dm->data;
6565:   PetscMPIInt    result;

6570:   if (anchorSection) {
6572:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6573:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6574:   }
6575:   if (anchorIS) {
6577:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6578:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6579:   }

6581:   PetscObjectReference((PetscObject)anchorSection);
6582:   PetscSectionDestroy(&plex->anchorSection);
6583:   plex->anchorSection = anchorSection;

6585:   PetscObjectReference((PetscObject)anchorIS);
6586:   ISDestroy(&plex->anchorIS);
6587:   plex->anchorIS = anchorIS;

6589: #if defined(PETSC_USE_DEBUG)
6590:   if (anchorIS && anchorSection) {
6591:     PetscInt size, a, pStart, pEnd;
6592:     const PetscInt *anchors;

6594:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6595:     ISGetLocalSize(anchorIS,&size);
6596:     ISGetIndices(anchorIS,&anchors);
6597:     for (a = 0; a < size; a++) {
6598:       PetscInt p;

6600:       p = anchors[a];
6601:       if (p >= pStart && p < pEnd) {
6602:         PetscInt dof;

6604:         PetscSectionGetDof(anchorSection,p,&dof);
6605:         if (dof) {
6606:           PetscErrorCode ierr2;

6608:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6609:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6610:         }
6611:       }
6612:     }
6613:     ISRestoreIndices(anchorIS,&anchors);
6614:   }
6615: #endif
6616:   /* reset the generic constraints */
6617:   DMSetDefaultConstraints(dm,NULL,NULL);
6618:   return(0);
6619: }

6621: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6622: {
6623:   PetscSection anchorSection;
6624:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6629:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6630:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6631:   PetscSectionGetNumFields(section,&numFields);
6632:   if (numFields) {
6633:     PetscInt f;
6634:     PetscSectionSetNumFields(*cSec,numFields);

6636:     for (f = 0; f < numFields; f++) {
6637:       PetscInt numComp;

6639:       PetscSectionGetFieldComponents(section,f,&numComp);
6640:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6641:     }
6642:   }
6643:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6644:   PetscSectionGetChart(section,&sStart,&sEnd);
6645:   pStart = PetscMax(pStart,sStart);
6646:   pEnd   = PetscMin(pEnd,sEnd);
6647:   pEnd   = PetscMax(pStart,pEnd);
6648:   PetscSectionSetChart(*cSec,pStart,pEnd);
6649:   for (p = pStart; p < pEnd; p++) {
6650:     PetscSectionGetDof(anchorSection,p,&dof);
6651:     if (dof) {
6652:       PetscSectionGetDof(section,p,&dof);
6653:       PetscSectionSetDof(*cSec,p,dof);
6654:       for (f = 0; f < numFields; f++) {
6655:         PetscSectionGetFieldDof(section,p,f,&dof);
6656:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6657:       }
6658:     }
6659:   }
6660:   PetscSectionSetUp(*cSec);
6661:   return(0);
6662: }

6664: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6665: {
6666:   PetscSection aSec;
6667:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6668:   const PetscInt *anchors;
6669:   PetscInt numFields, f;
6670:   IS aIS;

6675:   PetscSectionGetStorageSize(cSec, &m);
6676:   PetscSectionGetStorageSize(section, &n);
6677:   MatCreate(PETSC_COMM_SELF,cMat);
6678:   MatSetSizes(*cMat,m,n,m,n);
6679:   MatSetType(*cMat,MATSEQAIJ);
6680:   DMPlexGetAnchors(dm,&aSec,&aIS);
6681:   ISGetIndices(aIS,&anchors);
6682:   /* cSec will be a subset of aSec and section */
6683:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6684:   PetscMalloc1(m+1,&i);
6685:   i[0] = 0;
6686:   PetscSectionGetNumFields(section,&numFields);
6687:   for (p = pStart; p < pEnd; p++) {
6688:     PetscInt rDof, rOff, r;

6690:     PetscSectionGetDof(aSec,p,&rDof);
6691:     if (!rDof) continue;
6692:     PetscSectionGetOffset(aSec,p,&rOff);
6693:     if (numFields) {
6694:       for (f = 0; f < numFields; f++) {
6695:         annz = 0;
6696:         for (r = 0; r < rDof; r++) {
6697:           a = anchors[rOff + r];
6698:           PetscSectionGetFieldDof(section,a,f,&aDof);
6699:           annz += aDof;
6700:         }
6701:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6702:         PetscSectionGetFieldOffset(cSec,p,f,&off);
6703:         for (q = 0; q < dof; q++) {
6704:           i[off + q + 1] = i[off + q] + annz;
6705:         }
6706:       }
6707:     }
6708:     else {
6709:       annz = 0;
6710:       for (q = 0; q < dof; q++) {
6711:         a = anchors[off + q];
6712:         PetscSectionGetDof(section,a,&aDof);
6713:         annz += aDof;
6714:       }
6715:       PetscSectionGetDof(cSec,p,&dof);
6716:       PetscSectionGetOffset(cSec,p,&off);
6717:       for (q = 0; q < dof; q++) {
6718:         i[off + q + 1] = i[off + q] + annz;
6719:       }
6720:     }
6721:   }
6722:   nnz = i[m];
6723:   PetscMalloc1(nnz,&j);
6724:   offset = 0;
6725:   for (p = pStart; p < pEnd; p++) {
6726:     if (numFields) {
6727:       for (f = 0; f < numFields; f++) {
6728:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6729:         for (q = 0; q < dof; q++) {
6730:           PetscInt rDof, rOff, r;
6731:           PetscSectionGetDof(aSec,p,&rDof);
6732:           PetscSectionGetOffset(aSec,p,&rOff);
6733:           for (r = 0; r < rDof; r++) {
6734:             PetscInt s;

6736:             a = anchors[rOff + r];
6737:             PetscSectionGetFieldDof(section,a,f,&aDof);
6738:             PetscSectionGetFieldOffset(section,a,f,&aOff);
6739:             for (s = 0; s < aDof; s++) {
6740:               j[offset++] = aOff + s;
6741:             }
6742:           }
6743:         }
6744:       }
6745:     }
6746:     else {
6747:       PetscSectionGetDof(cSec,p,&dof);
6748:       for (q = 0; q < dof; q++) {
6749:         PetscInt rDof, rOff, r;
6750:         PetscSectionGetDof(aSec,p,&rDof);
6751:         PetscSectionGetOffset(aSec,p,&rOff);
6752:         for (r = 0; r < rDof; r++) {
6753:           PetscInt s;

6755:           a = anchors[rOff + r];
6756:           PetscSectionGetDof(section,a,&aDof);
6757:           PetscSectionGetOffset(section,a,&aOff);
6758:           for (s = 0; s < aDof; s++) {
6759:             j[offset++] = aOff + s;
6760:           }
6761:         }
6762:       }
6763:     }
6764:   }
6765:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
6766:   PetscFree(i);
6767:   PetscFree(j);
6768:   ISRestoreIndices(aIS,&anchors);
6769:   return(0);
6770: }

6772: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6773: {
6774:   DM_Plex        *plex = (DM_Plex *)dm->data;
6775:   PetscSection   anchorSection, section, cSec;
6776:   Mat            cMat;

6781:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6782:   if (anchorSection) {
6783:     PetscDS  ds;
6784:     PetscInt nf;

6786:     DMGetDefaultSection(dm,&section);
6787:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
6788:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
6789:     DMGetDS(dm,&ds);
6790:     PetscDSGetNumFields(ds,&nf);
6791:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
6792:     DMSetDefaultConstraints(dm,cSec,cMat);
6793:     PetscSectionDestroy(&cSec);
6794:     MatDestroy(&cMat);
6795:   }
6796:   return(0);
6797: }