Actual source code: plex.c

petsc-master 2016-12-09
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);

 16: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
 17: {
 18:   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior, vdof = 0, cdof = 0;

 22:   *ft  = PETSC_VTK_POINT_FIELD;
 23:   DMGetDimension(dm, &dim);
 24:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
 25:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
 26:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
 27:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
 28:   PetscSectionGetChart(section, &pStart, &pEnd);
 29:   if (field >= 0) {
 30:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vdof);}
 31:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &cdof);}
 32:   } else {
 33:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vdof);}
 34:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &cdof);}
 35:   }
 36:   if (vdof) {
 37:     *sStart = vStart;
 38:     *sEnd   = vEnd;
 39:     if (vdof == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
 40:     else             *ft = PETSC_VTK_POINT_FIELD;
 41:   } else if (cdof) {
 42:     *sStart = cStart;
 43:     *sEnd   = cEnd;
 44:     if (cdof == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
 45:     else             *ft = PETSC_VTK_CELL_FIELD;
 46:   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
 47:   return(0);
 48: }

 52: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
 53: {
 54:   DM             dm;
 55:   PetscBool      isvtk, ishdf5, isseq;

 59:   VecGetDM(v, &dm);
 60:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
 61:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
 62:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
 63:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
 64:   if (isvtk || ishdf5) {
 65:     PetscInt  numFields;
 66:     PetscBool fem = PETSC_FALSE;

 68:     DMGetNumFields(dm, &numFields);
 69:     if (numFields) {
 70:       PetscObject fe;

 72:       DMGetField(dm, 0, &fe);
 73:       if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE;
 74:     }
 75:     if (fem) {DMPlexInsertBoundaryValues(dm, PETSC_TRUE, v, 0.0, NULL, NULL, NULL);}
 76:   }
 77:   if (isvtk) {
 78:     PetscSection            section;
 79:     PetscViewerVTKFieldType ft;
 80:     PetscInt                pStart, pEnd;

 82:     DMGetDefaultSection(dm, &section);
 83:     DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
 84:     PetscObjectReference((PetscObject) v);  /* viewer drops reference */
 85:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
 86:   } else if (ishdf5) {
 87: #if defined(PETSC_HAVE_HDF5)
 88:     VecView_Plex_Local_HDF5(v, viewer);
 89: #else
 90:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
 91: #endif
 92:   } else {
 93:     if (isseq) {VecView_Seq(v, viewer);}
 94:     else       {VecView_MPI(v, viewer);}
 95:   }
 96:   return(0);
 97: }

101: PetscErrorCode VecView_Plex_Draw(Vec v, PetscViewer viewer)
102: {
103:   DM                 dm;
104:   PetscDraw          draw, popup;
105:   DM                 cdm;
106:   PetscSection       coordSection;
107:   Vec                coordinates;
108:   const PetscScalar *coords, *array;
109:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
110:   PetscReal          min, max;
111:   PetscBool          isnull;
112:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, level;
113:   const char        *name;
114:   PetscErrorCode     ierr;

117:   VecGetDM(v, &dm);
118:   DMGetCoordinateDim(dm, &dim);
119:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
120:   DMGetCoarsenLevel(dm, &level);
121:   DMGetCoordinateDM(dm, &cdm);
122:   DMGetDefaultSection(cdm, &coordSection);
123:   DMGetCoordinatesLocal(dm, &coordinates);
124:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
125:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

127:   PetscViewerDrawGetDraw(viewer, 0, &draw);
128:   PetscDrawIsNull(draw, &isnull);
129:   if (isnull) return(0);
130:   PetscObjectGetName((PetscObject) v, &name);
131:   PetscDrawSetTitle(draw, name);

133:   VecGetLocalSize(coordinates, &N);
134:   VecGetArrayRead(coordinates, &coords);
135:   for (c = 0; c < N; c += dim) {
136:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
137:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
138:   }
139:   VecRestoreArrayRead(coordinates, &coords);
140:   PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
141:   PetscDrawClear(draw);

143:   VecMin(v, NULL, &min);
144:   VecMax(v, NULL, &max);
145:   PetscDrawGetPopup(draw, &popup);
146:   PetscDrawScalePopup(popup, min, max);

148:   VecGetArrayRead(v, &array);
149:   for (c = cStart; c < cEnd; ++c) {
150:     PetscScalar *coords = NULL, *a = NULL;
151:     PetscInt     numCoords, color;

153:     DMPlexPointGlobalRead(dm, c, array, &a);
154:     color = PetscDrawRealToColor(PetscRealPart(a[0]), min, max);
155:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
156:     switch (numCoords) {
157:     case 6:
158:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color, color, color);
159:       break;
160:     case 8:
161:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color, color, color);
162:       PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color, color, color);
163:       break;
164:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
165:     }
166:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
167:   }
168:   VecRestoreArrayRead(v, &array);
169:   PetscDrawFlush(draw);
170:   PetscDrawPause(draw);
171:   PetscDrawSave(draw);
172:   return(0);
173: }

177: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
178: {
179:   DM             dm;
180:   PetscBool      isvtk, ishdf5, isdraw, isseq;

184:   VecGetDM(v, &dm);
185:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
186:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
187:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
188:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
189:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
190:   if (isvtk) {
191:     Vec         locv;
192:     const char *name;

194:     DMGetLocalVector(dm, &locv);
195:     PetscObjectGetName((PetscObject) v, &name);
196:     PetscObjectSetName((PetscObject) locv, name);
197:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
198:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
199:     VecView_Plex_Local(locv, viewer);
200:     DMRestoreLocalVector(dm, &locv);
201:   } else if (ishdf5) {
202: #if defined(PETSC_HAVE_HDF5)
203:     VecView_Plex_HDF5(v, viewer);
204: #else
205:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
206: #endif
207:   } else if (isdraw) {
208:     VecView_Plex_Draw(v, viewer);
209:   } else {
210:     if (isseq) {VecView_Seq(v, viewer);}
211:     else       {VecView_MPI(v, viewer);}
212:   }
213:   return(0);
214: }

218: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
219: {
220:   DM                dm;
221:   MPI_Comm          comm;
222:   PetscViewerFormat format;
223:   Vec               v;
224:   PetscBool         isvtk, ishdf5;
225:   PetscErrorCode    ierr;

228:   VecGetDM(originalv, &dm);
229:   PetscObjectGetComm((PetscObject) originalv, &comm);
230:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
231:   PetscViewerGetFormat(viewer, &format);
232:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
233:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
234:   if (format == PETSC_VIEWER_NATIVE) {
235:     const char *vecname;
236:     PetscInt    n, nroots;

238:     if (dm->sfNatural) {
239:       VecGetLocalSize(originalv, &n);
240:       PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
241:       if (n == nroots) {
242:         DMGetGlobalVector(dm, &v);
243:         DMPlexGlobalToNaturalBegin(dm, originalv, v);
244:         DMPlexGlobalToNaturalEnd(dm, originalv, v);
245:         PetscObjectGetName((PetscObject) originalv, &vecname);
246:         PetscObjectSetName((PetscObject) v, vecname);
247:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
248:     } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
249:   } else {
250:     /* we are viewing a natural DMPlex vec. */
251:     v = originalv;
252:   }
253:   if (ishdf5) {
254: #if defined(PETSC_HAVE_HDF5)
255:     VecView_Plex_HDF5_Native(v, viewer);
256: #else
257:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
258: #endif
259:   } else if (isvtk) {
260:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
261:   } else {
262:     PetscBool isseq;

264:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
265:     if (isseq) {VecView_Seq(v, viewer);}
266:     else       {VecView_MPI(v, viewer);}
267:   }
268:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
269:   return(0);
270: }

274: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
275: {
276:   DM             dm;
277:   PetscBool      ishdf5;

281:   VecGetDM(v, &dm);
282:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
283:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
284:   if (ishdf5) {
285:     DM          dmBC;
286:     Vec         gv;
287:     const char *name;

289:     DMGetOutputDM(dm, &dmBC);
290:     DMGetGlobalVector(dmBC, &gv);
291:     PetscObjectGetName((PetscObject) v, &name);
292:     PetscObjectSetName((PetscObject) gv, name);
293:     VecLoad_Default(gv, viewer);
294:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
295:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
296:     DMRestoreGlobalVector(dmBC, &gv);
297:   } else {
298:     VecLoad_Default(v, viewer);
299:   }
300:   return(0);
301: }

305: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
306: {
307:   DM             dm;
308:   PetscBool      ishdf5;

312:   VecGetDM(v, &dm);
313:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
314:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
315:   if (ishdf5) {
316: #if defined(PETSC_HAVE_HDF5)
317:     VecLoad_Plex_HDF5(v, viewer);
318: #else
319:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
320: #endif
321:   } else {
322:     VecLoad_Default(v, viewer);
323:   }
324:   return(0);
325: }

329: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
330: {
331:   DM                dm;
332:   PetscViewerFormat format;
333:   PetscBool         ishdf5;
334:   PetscErrorCode    ierr;

337:   VecGetDM(originalv, &dm);
338:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
339:   PetscViewerGetFormat(viewer, &format);
340:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
341:   if (format == PETSC_VIEWER_NATIVE) {
342:     if (dm->sfNatural) {
343:       if (ishdf5) {
344: #if defined(PETSC_HAVE_HDF5)
345:         Vec         v;
346:         const char *vecname;

348:         DMGetGlobalVector(dm, &v);
349:         PetscObjectGetName((PetscObject) originalv, &vecname);
350:         PetscObjectSetName((PetscObject) v, vecname);
351:         VecLoad_Plex_HDF5_Native(v, viewer);
352:         DMPlexNaturalToGlobalBegin(dm, v, originalv);
353:         DMPlexNaturalToGlobalEnd(dm, v, originalv);
354:         DMRestoreGlobalVector(dm, &v);
355: #else
356:         SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
357: #endif
358:       } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
359:     }
360:   }
361:   return(0);
362: }

366: PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
367: {
368:   PetscSection       coordSection;
369:   Vec                coordinates;
370:   DMLabel            depthLabel;
371:   const char        *name[4];
372:   const PetscScalar *a;
373:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
374:   PetscErrorCode     ierr;

377:   DMGetDimension(dm, &dim);
378:   DMGetCoordinatesLocal(dm, &coordinates);
379:   DMGetCoordinateSection(dm, &coordSection);
380:   DMPlexGetDepthLabel(dm, &depthLabel);
381:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
382:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
383:   VecGetArrayRead(coordinates, &a);
384:   name[0]     = "vertex";
385:   name[1]     = "edge";
386:   name[dim-1] = "face";
387:   name[dim]   = "cell";
388:   for (c = cStart; c < cEnd; ++c) {
389:     PetscInt *closure = NULL;
390:     PetscInt  closureSize, cl;

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

398:       if ((point < pStart) || (point >= pEnd)) continue;
399:       PetscSectionGetDof(coordSection, point, &dof);
400:       if (!dof) continue;
401:       DMLabelGetValue(depthLabel, point, &depth);
402:       PetscSectionGetOffset(coordSection, point, &off);
403:       PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
404:       for (p = 0; p < dof/dim; ++p) {
405:         PetscViewerASCIIPrintf(viewer, " (");
406:         for (d = 0; d < dim; ++d) {
407:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
408:           PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
409:         }
410:         PetscViewerASCIIPrintf(viewer, ")");
411:       }
412:       PetscViewerASCIIPrintf(viewer, "\n");
413:     }
414:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
415:     PetscViewerASCIIPopTab(viewer);
416:   }
417:   VecRestoreArrayRead(coordinates, &a);
418:   return(0);
419: }

423: PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
424: {
425:   DM_Plex          *mesh = (DM_Plex*) dm->data;
426:   DM                cdm;
427:   DMLabel           markers;
428:   PetscSection      coordSection;
429:   Vec               coordinates;
430:   PetscViewerFormat format;
431:   PetscErrorCode    ierr;

434:   DMGetCoordinateDM(dm, &cdm);
435:   DMGetDefaultSection(cdm, &coordSection);
436:   DMGetCoordinatesLocal(dm, &coordinates);
437:   PetscViewerGetFormat(viewer, &format);
438:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
439:     const char *name;
440:     PetscInt    maxConeSize, maxSupportSize;
441:     PetscInt    pStart, pEnd, p;
442:     PetscMPIInt rank, size;

444:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
445:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
446:     PetscObjectGetName((PetscObject) dm, &name);
447:     DMPlexGetChart(dm, &pStart, &pEnd);
448:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
449:     PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);
450:     PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
451:     PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
452:     PetscViewerASCIIPushSynchronized(viewer);
453:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);
454:     for (p = pStart; p < pEnd; ++p) {
455:       PetscInt dof, off, s;

457:       PetscSectionGetDof(mesh->supportSection, p, &dof);
458:       PetscSectionGetOffset(mesh->supportSection, p, &off);
459:       for (s = off; s < off+dof; ++s) {
460:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
461:       }
462:     }
463:     PetscViewerFlush(viewer);
464:     PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
465:     for (p = pStart; p < pEnd; ++p) {
466:       PetscInt dof, off, c;

468:       PetscSectionGetDof(mesh->coneSection, p, &dof);
469:       PetscSectionGetOffset(mesh->coneSection, p, &off);
470:       for (c = off; c < off+dof; ++c) {
471:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
472:       }
473:     }
474:     PetscViewerFlush(viewer);
475:     PetscViewerASCIIPopSynchronized(viewer);
476:     PetscSectionGetChart(coordSection, &pStart, NULL);
477:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
478:     DMGetLabel(dm, "marker", &markers);
479:     DMLabelView(markers,viewer);
480:     if (size > 1) {
481:       PetscSF sf;

483:       DMGetPointSF(dm, &sf);
484:       PetscSFView(sf, viewer);
485:     }
486:     PetscViewerFlush(viewer);
487:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
488:     const char  *name, *color;
489:     const char  *defcolors[3]  = {"gray", "orange", "green"};
490:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
491:     PetscReal    scale         = 2.0;
492:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
493:     double       tcoords[3];
494:     PetscScalar *coords;
495:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
496:     PetscMPIInt  rank, size;
497:     char         **names, **colors, **lcolors;

499:     DMGetDimension(dm, &dim);
500:     DMPlexGetDepth(dm, &depth);
501:     DMGetNumLabels(dm, &numLabels);
502:     numLabels  = PetscMax(numLabels, 10);
503:     numColors  = 10;
504:     numLColors = 10;
505:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
506:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
507:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
508:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
509:     if (!useLabels) numLabels = 0;
510:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
511:     if (!useColors) {
512:       numColors = 3;
513:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
514:     }
515:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
516:     if (!useColors) {
517:       numLColors = 4;
518:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
519:     }
520:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
521:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
522:     PetscObjectGetName((PetscObject) dm, &name);
523:     PetscViewerASCIIPrintf(viewer, "\
524: \\documentclass[tikz]{standalone}\n\n\
525: \\usepackage{pgflibraryshapes}\n\
526: \\usetikzlibrary{backgrounds}\n\
527: \\usetikzlibrary{arrows}\n\
528: \\begin{document}\n");
529:     if (size > 1) {
530:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
531:       for (p = 0; p < size; ++p) {
532:         if (p > 0 && p == size-1) {
533:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
534:         } else if (p > 0) {
535:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
536:         }
537:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
538:       }
539:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
540:     }
541:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);
542:     /* Plot vertices */
543:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
544:     VecGetArray(coordinates, &coords);
545:     PetscViewerASCIIPushSynchronized(viewer);
546:     for (v = vStart; v < vEnd; ++v) {
547:       PetscInt  off, dof, d;
548:       PetscBool isLabeled = PETSC_FALSE;

550:       PetscSectionGetDof(coordSection, v, &dof);
551:       PetscSectionGetOffset(coordSection, v, &off);
552:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
553:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
554:       for (d = 0; d < dof; ++d) {
555:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
556:         tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
557:       }
558:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
559:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
560:       for (d = 0; d < dof; ++d) {
561:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
562:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
563:       }
564:       color = colors[rank%numColors];
565:       for (l = 0; l < numLabels; ++l) {
566:         PetscInt val;
567:         DMGetLabelValue(dm, names[l], v, &val);
568:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
569:       }
570:       if (useNumbers) {
571:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
572:       } else {
573:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
574:       }
575:     }
576:     VecRestoreArray(coordinates, &coords);
577:     PetscViewerFlush(viewer);
578:     /* Plot edges */
579:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
580:     if (dim < 3 && useNumbers) {
581:       VecGetArray(coordinates, &coords);
582:       PetscViewerASCIIPrintf(viewer, "\\path\n");
583:       for (e = eStart; e < eEnd; ++e) {
584:         const PetscInt *cone;
585:         PetscInt        coneSize, offA, offB, dof, d;

587:         DMPlexGetConeSize(dm, e, &coneSize);
588:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
589:         DMPlexGetCone(dm, e, &cone);
590:         PetscSectionGetDof(coordSection, cone[0], &dof);
591:         PetscSectionGetOffset(coordSection, cone[0], &offA);
592:         PetscSectionGetOffset(coordSection, cone[1], &offB);
593:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
594:         for (d = 0; d < dof; ++d) {
595:           tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
596:           tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
597:         }
598:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
599:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
600:         for (d = 0; d < dof; ++d) {
601:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
602:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
603:         }
604:         color = colors[rank%numColors];
605:         for (l = 0; l < numLabels; ++l) {
606:           PetscInt val;
607:           DMGetLabelValue(dm, names[l], v, &val);
608:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
609:         }
610:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
611:       }
612:       VecRestoreArray(coordinates, &coords);
613:       PetscViewerFlush(viewer);
614:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
615:     }
616:     /* Plot cells */
617:     if (dim == 3 || !useNumbers) {
618:       for (e = eStart; e < eEnd; ++e) {
619:         const PetscInt *cone;

621:         color = colors[rank%numColors];
622:         for (l = 0; l < numLabels; ++l) {
623:           PetscInt val;
624:           DMGetLabelValue(dm, names[l], e, &val);
625:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
626:         }
627:         DMPlexGetCone(dm, e, &cone);
628:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
629:       }
630:     } else {
631:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
632:       for (c = cStart; c < cEnd; ++c) {
633:         PetscInt *closure = NULL;
634:         PetscInt  closureSize, firstPoint = -1;

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

641:           if ((point < vStart) || (point >= vEnd)) continue;
642:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
643:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
644:           if (firstPoint < 0) firstPoint = point;
645:         }
646:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
647:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
648:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
649:       }
650:     }
651:     PetscViewerFlush(viewer);
652:     PetscViewerASCIIPopSynchronized(viewer);
653:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
654:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
655:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
656:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
657:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
658:     PetscFree3(names, colors, lcolors);
659:   } else {
660:     MPI_Comm    comm;
661:     PetscInt   *sizes, *hybsizes;
662:     PetscInt    locDepth, depth, dim, d, pMax[4];
663:     PetscInt    pStart, pEnd, p;
664:     PetscInt    numLabels, l;
665:     const char *name;
666:     PetscMPIInt size;

668:     PetscObjectGetComm((PetscObject)dm,&comm);
669:     MPI_Comm_size(comm, &size);
670:     DMGetDimension(dm, &dim);
671:     PetscObjectGetName((PetscObject) dm, &name);
672:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);}
673:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);}
674:     DMPlexGetDepth(dm, &locDepth);
675:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
676:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
677:     PetscMalloc2(size,&sizes,size,&hybsizes);
678:     if (depth == 1) {
679:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
680:       pEnd = pEnd - pStart;
681:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
682:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
683:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
684:       PetscViewerASCIIPrintf(viewer, "\n");
685:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
686:       pEnd = pEnd - pStart;
687:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
688:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
689:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
690:       PetscViewerASCIIPrintf(viewer, "\n");
691:     } else {
692:       PetscMPIInt rank;
693:       MPI_Comm_rank(comm, &rank);
694:       for (d = 0; d <= dim; d++) {
695:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
696:         pEnd    -= pStart;
697:         pMax[d] -= pStart;
698:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
699:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
700:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
701:         for (p = 0; p < size; ++p) {
702:           if (!rank) {
703:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
704:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
705:           }
706:         }
707:         PetscViewerASCIIPrintf(viewer, "\n");
708:       }
709:     }
710:     PetscFree2(sizes,hybsizes);
711:     DMGetNumLabels(dm, &numLabels);
712:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
713:     for (l = 0; l < numLabels; ++l) {
714:       DMLabel         label;
715:       const char     *name;
716:       IS              valueIS;
717:       const PetscInt *values;
718:       PetscInt        numValues, v;

720:       DMGetLabelName(dm, l, &name);
721:       DMGetLabel(dm, name, &label);
722:       DMLabelGetNumValues(label, &numValues);
723:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata of sizes (", name, numValues);
724:       DMLabelGetValueIS(label, &valueIS);
725:       ISGetIndices(valueIS, &values);
726:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
727:       for (v = 0; v < numValues; ++v) {
728:         PetscInt size;

730:         DMLabelGetStratumSize(label, values[v], &size);
731:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
732:         PetscViewerASCIIPrintf(viewer, "%D", size);
733:       }
734:       PetscViewerASCIIPrintf(viewer, ")\n");
735:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
736:       ISRestoreIndices(valueIS, &values);
737:       ISDestroy(&valueIS);
738:     }
739:     DMGetCoarseDM(dm, &cdm);
740:     if (cdm) {
741:       PetscViewerASCIIPushTab(viewer);
742:       DMPlexView_Ascii(cdm, viewer);
743:       PetscViewerASCIIPopTab(viewer);
744:     }
745:   }
746:   return(0);
747: }

751: PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
752: {
753:   PetscDraw          draw;
754:   DM                 cdm;
755:   PetscSection       coordSection;
756:   Vec                coordinates;
757:   const PetscScalar *coords;
758:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
759:   PetscBool          isnull;
760:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
761:   PetscErrorCode     ierr;

764:   DMGetCoordinateDim(dm, &dim);
765:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
766:   DMGetCoordinateDM(dm, &cdm);
767:   DMGetDefaultSection(cdm, &coordSection);
768:   DMGetCoordinatesLocal(dm, &coordinates);
769:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
770:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

772:   PetscViewerDrawGetDraw(viewer, 0, &draw);
773:   PetscDrawIsNull(draw, &isnull);
774:   if (isnull) return(0);
775:   PetscDrawSetTitle(draw, "Mesh");

777:   VecGetLocalSize(coordinates, &N);
778:   VecGetArrayRead(coordinates, &coords);
779:   for (c = 0; c < N; c += dim) {
780:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
781:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
782:   }
783:   VecRestoreArrayRead(coordinates, &coords);
784:   PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
785:   PetscDrawClear(draw);

787:   for (c = cStart; c < cEnd; ++c) {
788:     PetscScalar *coords = NULL;
789:     PetscInt     numCoords;

791:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
792:     switch (numCoords) {
793:     case 6:
794:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
795:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
796:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
797:       break;
798:     case 8:
799:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
800:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
801:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
802:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
803:       break;
804:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
805:     }
806:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
807:   }
808:   PetscDrawFlush(draw);
809:   PetscDrawPause(draw);
810:   PetscDrawSave(draw);
811:   return(0);
812: }

816: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
817: {
818:   PetscBool      iascii, ishdf5, isvtk, isdraw;

824:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
825:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
826:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
827:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
828:   if (iascii) {
829:     DMPlexView_Ascii(dm, viewer);
830:   } else if (ishdf5) {
831: #if defined(PETSC_HAVE_HDF5)
832:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
833:     DMPlexView_HDF5(dm, viewer);
834:     PetscViewerPopFormat(viewer);
835: #else
836:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
837: #endif
838:   } else if (isvtk) {
839:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
840:   } else if (isdraw) {
841:     DMPlexView_Draw(dm, viewer);
842:   }
843:   return(0);
844: }

848: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
849: {
850:   PetscBool      isbinary, ishdf5;

856:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
857:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
858:   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
859:   else if (ishdf5) {
860: #if defined(PETSC_HAVE_HDF5)
861:     DMPlexLoad_HDF5(dm, viewer);
862: #else
863:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
864: #endif
865:   }
866:   return(0);
867: }


872: PetscErrorCode DMDestroy_Plex(DM dm)
873: {
874:   DM_Plex       *mesh = (DM_Plex*) dm->data;

878:   if (--mesh->refct > 0) return(0);
879:   PetscSectionDestroy(&mesh->coneSection);
880:   PetscFree(mesh->cones);
881:   PetscFree(mesh->coneOrientations);
882:   PetscSectionDestroy(&mesh->supportSection);
883:   PetscSectionDestroy(&mesh->subdomainSection);
884:   PetscFree(mesh->supports);
885:   PetscFree(mesh->facesTmp);
886:   PetscFree(mesh->tetgenOpts);
887:   PetscFree(mesh->triangleOpts);
888:   PetscPartitionerDestroy(&mesh->partitioner);
889:   DMLabelDestroy(&mesh->subpointMap);
890:   ISDestroy(&mesh->globalVertexNumbers);
891:   ISDestroy(&mesh->globalCellNumbers);
892:   PetscSectionDestroy(&mesh->anchorSection);
893:   ISDestroy(&mesh->anchorIS);
894:   PetscSectionDestroy(&mesh->parentSection);
895:   PetscFree(mesh->parents);
896:   PetscFree(mesh->childIDs);
897:   PetscSectionDestroy(&mesh->childSection);
898:   PetscFree(mesh->children);
899:   DMDestroy(&mesh->referenceTree);
900:   PetscGridHashDestroy(&mesh->lbox);
901:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
902:   PetscFree(mesh);
903:   PetscObjectComposeFunction((PetscObject)dm,"DMAdaptLabel_C",NULL);
904:   return(0);
905: }

909: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
910: {
911:   PetscSection           sectionGlobal;
912:   PetscInt               bs = -1, mbs;
913:   PetscInt               localSize;
914:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
915:   PetscErrorCode         ierr;
916:   MatType                mtype;
917:   ISLocalToGlobalMapping ltog;

920:   MatInitializePackage();
921:   mtype = dm->mattype;
922:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
923:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
924:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
925:   MatCreate(PetscObjectComm((PetscObject)dm), J);
926:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
927:   MatSetType(*J, mtype);
928:   MatSetFromOptions(*J);
929:   MatGetBlockSize(*J, &mbs);
930:   if (mbs > 1) bs = mbs;
931:   PetscStrcmp(mtype, MATSHELL, &isShell);
932:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
933:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
934:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
935:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
936:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
937:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
938:   PetscStrcmp(mtype, MATIS, &isMatIS);
939:   if (!isShell) {
940:     PetscSection subSection;
941:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
942:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin, *ltogidx, lsize;
943:     PetscInt     pStart, pEnd, p, dof, cdof;

945:     /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
946:     if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
947:       PetscSection section;
948:       PetscInt     size;

950:       DMGetDefaultSection(dm, &section);
951:       PetscSectionGetStorageSize(section, &size);
952:       PetscMalloc1(size,&ltogidx);
953:       DMPlexGetSubdomainSection(dm, &subSection);
954:     } else {
955:       DMGetLocalToGlobalMapping(dm,&ltog);
956:     }
957:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
958:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
959:       PetscInt bdof;

961:       PetscSectionGetDof(sectionGlobal, p, &dof);
962:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
963:       dof  = dof < 0 ? -(dof+1) : dof;
964:       bdof = cdof && (dof-cdof) ? 1 : dof;
965:       if (dof) {
966:         if (bs < 0)          {bs = bdof;}
967:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
968:       }
969:       if (isMatIS) {
970:         PetscInt loff,c,off;
971:         PetscSectionGetOffset(subSection, p, &loff);
972:         PetscSectionGetOffset(sectionGlobal, p, &off);
973:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
974:       }
975:     }
976:     /* Must have same blocksize on all procs (some might have no points) */
977:     bsLocal = bs;
978:     MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
979:     bsLocal = bs < 0 ? bsMax : bs;
980:     MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
981:     if (bsMin != bsMax) {bs = 1;}
982:     else                {bs = bsMax;}
983:     bs   = bs < 0 ? 1 : bs;
984:     if (isMatIS) {
985:       PetscInt l;
986:       /* Must reduce indices by blocksize */
987:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
988:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
989:     }
990:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
991:     if (isMatIS) {
992:       ISLocalToGlobalMappingDestroy(&ltog);
993:     }
994:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
995:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
996:     PetscFree4(dnz, onz, dnzu, onzu);
997:   }
998:   MatSetDM(*J, dm);
999:   return(0);
1000: }

1004: /*
1005:   DMPlexGetSubdomainGlobalSection - Returns the section associated with the subdomain

1007:   Not collective

1009:   Input Parameter:
1010: . mesh - The DMPlex

1012:   Output Parameters:
1013: . subsection - The subdomain section

1015:   Level: developer

1017: .seealso:
1018: */
1019: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1020: {
1021:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1026:   if (!mesh->subdomainSection) {
1027:     PetscSection section;
1028:     PetscSF      sf;

1030:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1031:     DMGetDefaultSection(dm,&section);
1032:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1033:     PetscSFDestroy(&sf);
1034:   }
1035:   *subsection = mesh->subdomainSection;
1036:   return(0);
1037: }

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

1044:   Not collective

1046:   Input Parameter:
1047: . mesh - The DMPlex

1049:   Output Parameters:
1050: + pStart - The first mesh point
1051: - pEnd   - The upper bound for mesh points

1053:   Level: beginner

1055: .seealso: DMPlexCreate(), DMPlexSetChart()
1056: @*/
1057: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1058: {
1059:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1064:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1065:   return(0);
1066: }

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

1073:   Not collective

1075:   Input Parameters:
1076: + mesh - The DMPlex
1077: . pStart - The first mesh point
1078: - pEnd   - The upper bound for mesh points

1080:   Output Parameters:

1082:   Level: beginner

1084: .seealso: DMPlexCreate(), DMPlexGetChart()
1085: @*/
1086: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1087: {
1088:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1093:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1094:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1095:   return(0);
1096: }

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

1103:   Not collective

1105:   Input Parameters:
1106: + mesh - The DMPlex
1107: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1109:   Output Parameter:
1110: . size - The cone size for point p

1112:   Level: beginner

1114: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1115: @*/
1116: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1117: {
1118:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1124:   PetscSectionGetDof(mesh->coneSection, p, size);
1125:   return(0);
1126: }

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

1133:   Not collective

1135:   Input Parameters:
1136: + mesh - The DMPlex
1137: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1138: - size - The cone size for point p

1140:   Output Parameter:

1142:   Note:
1143:   This should be called after DMPlexSetChart().

1145:   Level: beginner

1147: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1148: @*/
1149: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1150: {
1151:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1158:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1159:   return(0);
1160: }

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

1167:   Not collective

1169:   Input Parameters:
1170: + mesh - The DMPlex
1171: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1172: - size - The additional cone size for point p

1174:   Output Parameter:

1176:   Note:
1177:   This should be called after DMPlexSetChart().

1179:   Level: beginner

1181: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1182: @*/
1183: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1184: {
1185:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1186:   PetscInt       csize;

1191:   PetscSectionAddDof(mesh->coneSection, p, size);
1192:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1194:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1195:   return(0);
1196: }

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

1203:   Not collective

1205:   Input Parameters:
1206: + mesh - The DMPlex
1207: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1212:   Level: beginner

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

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

1220: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1221: @*/
1222: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1223: {
1224:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1225:   PetscInt       off;

1231:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1232:   *cone = &mesh->cones[off];
1233:   return(0);
1234: }

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

1241:   Not collective

1243:   Input Parameters:
1244: + mesh - The DMPlex
1245: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1246: - cone - An array of points which are on the in-edges for point p

1248:   Output Parameter:

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

1253:   Level: beginner

1255: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1256: @*/
1257: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1258: {
1259:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1260:   PetscInt       pStart, pEnd;
1261:   PetscInt       dof, off, c;

1266:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1267:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1269:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1270:   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);
1271:   for (c = 0; c < dof; ++c) {
1272:     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);
1273:     mesh->cones[off+c] = cone[c];
1274:   }
1275:   return(0);
1276: }

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

1283:   Not collective

1285:   Input Parameters:
1286: + mesh - The DMPlex
1287: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1289:   Output Parameter:
1290: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1291:                     integer giving the prescription for cone traversal. If it is negative, the cone is
1292:                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1293:                     the index of the cone point on which to start.

1295:   Level: beginner

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

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

1303: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1304: @*/
1305: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1306: {
1307:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1308:   PetscInt       off;

1313: #if defined(PETSC_USE_DEBUG)
1314:   {
1315:     PetscInt dof;
1316:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1318:   }
1319: #endif
1320:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1322:   *coneOrientation = &mesh->coneOrientations[off];
1323:   return(0);
1324: }

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

1331:   Not collective

1333:   Input Parameters:
1334: + mesh - The DMPlex
1335: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1336: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1337:                     integer giving the prescription for cone traversal. If it is negative, the cone is
1338:                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1339:                     the index of the cone point on which to start.

1341:   Output Parameter:

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

1346:   Level: beginner

1348: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1349: @*/
1350: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1351: {
1352:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1353:   PetscInt       pStart, pEnd;
1354:   PetscInt       dof, off, c;

1359:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1360:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1362:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1363:   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);
1364:   for (c = 0; c < dof; ++c) {
1365:     PetscInt cdof, o = coneOrientation[c];

1367:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1368:     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);
1369:     mesh->coneOrientations[off+c] = o;
1370:   }
1371:   return(0);
1372: }

1376: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1377: {
1378:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1379:   PetscInt       pStart, pEnd;
1380:   PetscInt       dof, off;

1385:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1386:   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);
1387:   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);
1388:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1389:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1390:   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);
1391:   mesh->cones[off+conePos] = conePoint;
1392:   return(0);
1393: }

1397: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1398: {
1399:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1400:   PetscInt       pStart, pEnd;
1401:   PetscInt       dof, off;

1406:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1407:   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);
1408:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1409:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1410:   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);
1411:   mesh->coneOrientations[off+conePos] = coneOrientation;
1412:   return(0);
1413: }

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

1420:   Not collective

1422:   Input Parameters:
1423: + mesh - The DMPlex
1424: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1426:   Output Parameter:
1427: . size - The support size for point p

1429:   Level: beginner

1431: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1432: @*/
1433: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1434: {
1435:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1441:   PetscSectionGetDof(mesh->supportSection, p, size);
1442:   return(0);
1443: }

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

1450:   Not collective

1452:   Input Parameters:
1453: + mesh - The DMPlex
1454: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1455: - size - The support size for point p

1457:   Output Parameter:

1459:   Note:
1460:   This should be called after DMPlexSetChart().

1462:   Level: beginner

1464: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1465: @*/
1466: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1467: {
1468:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1475:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1476:   return(0);
1477: }

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

1484:   Not collective

1486:   Input Parameters:
1487: + mesh - The DMPlex
1488: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1493:   Level: beginner

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

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

1501: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1502: @*/
1503: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1504: {
1505:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1506:   PetscInt       off;

1512:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1513:   *support = &mesh->supports[off];
1514:   return(0);
1515: }

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

1522:   Not collective

1524:   Input Parameters:
1525: + mesh - The DMPlex
1526: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1527: - support - An array of points which are on the in-edges for point p

1529:   Output Parameter:

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

1534:   Level: beginner

1536: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1537: @*/
1538: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1539: {
1540:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1541:   PetscInt       pStart, pEnd;
1542:   PetscInt       dof, off, c;

1547:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1548:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1550:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1551:   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);
1552:   for (c = 0; c < dof; ++c) {
1553:     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);
1554:     mesh->supports[off+c] = support[c];
1555:   }
1556:   return(0);
1557: }

1561: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1562: {
1563:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1564:   PetscInt       pStart, pEnd;
1565:   PetscInt       dof, off;

1570:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1571:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1572:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1573:   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);
1574:   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);
1575:   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);
1576:   mesh->supports[off+supportPos] = supportPoint;
1577:   return(0);
1578: }

1582: /*@C
1583:   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG

1585:   Not collective

1587:   Input Parameters:
1588: + mesh - The DMPlex
1589: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1590: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1591: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

1593:   Output Parameters:
1594: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1595: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]

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

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

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

1606:   Level: beginner

1608: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1609: @*/
1610: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1611: {
1612:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1613:   PetscInt       *closure, *fifo;
1614:   const PetscInt *tmp = NULL, *tmpO = NULL;
1615:   PetscInt        tmpSize, t;
1616:   PetscInt        depth       = 0, maxSize;
1617:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1618:   PetscErrorCode  ierr;

1622:   DMPlexGetDepth(dm, &depth);
1623:   /* This is only 1-level */
1624:   if (useCone) {
1625:     DMPlexGetConeSize(dm, p, &tmpSize);
1626:     DMPlexGetCone(dm, p, &tmp);
1627:     DMPlexGetConeOrientation(dm, p, &tmpO);
1628:   } else {
1629:     DMPlexGetSupportSize(dm, p, &tmpSize);
1630:     DMPlexGetSupport(dm, p, &tmp);
1631:   }
1632:   if (depth == 1) {
1633:     if (*points) {
1634:       closure = *points;
1635:     } else {
1636:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1637:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1638:     }
1639:     closure[0] = p; closure[1] = 0;
1640:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1641:       closure[closureSize]   = tmp[t];
1642:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1643:     }
1644:     if (numPoints) *numPoints = closureSize/2;
1645:     if (points)    *points    = closure;
1646:     return(0);
1647:   }
1648:   {
1649:     PetscInt c, coneSeries, s,supportSeries;

1651:     c = mesh->maxConeSize;
1652:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1653:     s = mesh->maxSupportSize;
1654:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1655:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1656:   }
1657:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1658:   if (*points) {
1659:     closure = *points;
1660:   } else {
1661:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1662:   }
1663:   closure[0] = p; closure[1] = 0;
1664:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1665:     const PetscInt cp = tmp[t];
1666:     const PetscInt co = tmpO ? tmpO[t] : 0;

1668:     closure[closureSize]   = cp;
1669:     closure[closureSize+1] = co;
1670:     fifo[fifoSize]         = cp;
1671:     fifo[fifoSize+1]       = co;
1672:   }
1673:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1674:   while (fifoSize - fifoStart) {
1675:     const PetscInt q   = fifo[fifoStart];
1676:     const PetscInt o   = fifo[fifoStart+1];
1677:     const PetscInt rev = o >= 0 ? 0 : 1;
1678:     const PetscInt off = rev ? -(o+1) : o;

1680:     if (useCone) {
1681:       DMPlexGetConeSize(dm, q, &tmpSize);
1682:       DMPlexGetCone(dm, q, &tmp);
1683:       DMPlexGetConeOrientation(dm, q, &tmpO);
1684:     } else {
1685:       DMPlexGetSupportSize(dm, q, &tmpSize);
1686:       DMPlexGetSupport(dm, q, &tmp);
1687:       tmpO = NULL;
1688:     }
1689:     for (t = 0; t < tmpSize; ++t) {
1690:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1691:       const PetscInt cp = tmp[i];
1692:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1693:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1694:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1695:       PetscInt       co = tmpO ? tmpO[i] : 0;
1696:       PetscInt       c;

1698:       if (rev) {
1699:         PetscInt childSize, coff;
1700:         DMPlexGetConeSize(dm, cp, &childSize);
1701:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1702:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1703:       }
1704:       /* Check for duplicate */
1705:       for (c = 0; c < closureSize; c += 2) {
1706:         if (closure[c] == cp) break;
1707:       }
1708:       if (c == closureSize) {
1709:         closure[closureSize]   = cp;
1710:         closure[closureSize+1] = co;
1711:         fifo[fifoSize]         = cp;
1712:         fifo[fifoSize+1]       = co;
1713:         closureSize           += 2;
1714:         fifoSize              += 2;
1715:       }
1716:     }
1717:     fifoStart += 2;
1718:   }
1719:   if (numPoints) *numPoints = closureSize/2;
1720:   if (points)    *points    = closure;
1721:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1722:   return(0);
1723: }

1727: /*@C
1728:   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

1730:   Not collective

1732:   Input Parameters:
1733: + mesh - The DMPlex
1734: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1735: . orientation - The orientation of the point
1736: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1737: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

1739:   Output Parameters:
1740: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1741: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]

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

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

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

1752:   Level: beginner

1754: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1755: @*/
1756: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1757: {
1758:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1759:   PetscInt       *closure, *fifo;
1760:   const PetscInt *tmp = NULL, *tmpO = NULL;
1761:   PetscInt        tmpSize, t;
1762:   PetscInt        depth       = 0, maxSize;
1763:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1764:   PetscErrorCode  ierr;

1768:   DMPlexGetDepth(dm, &depth);
1769:   /* This is only 1-level */
1770:   if (useCone) {
1771:     DMPlexGetConeSize(dm, p, &tmpSize);
1772:     DMPlexGetCone(dm, p, &tmp);
1773:     DMPlexGetConeOrientation(dm, p, &tmpO);
1774:   } else {
1775:     DMPlexGetSupportSize(dm, p, &tmpSize);
1776:     DMPlexGetSupport(dm, p, &tmp);
1777:   }
1778:   if (depth == 1) {
1779:     if (*points) {
1780:       closure = *points;
1781:     } else {
1782:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1783:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1784:     }
1785:     closure[0] = p; closure[1] = ornt;
1786:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1787:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1788:       closure[closureSize]   = tmp[i];
1789:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1790:     }
1791:     if (numPoints) *numPoints = closureSize/2;
1792:     if (points)    *points    = closure;
1793:     return(0);
1794:   }
1795:   {
1796:     PetscInt c, coneSeries, s,supportSeries;

1798:     c = mesh->maxConeSize;
1799:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1800:     s = mesh->maxSupportSize;
1801:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1802:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1803:   }
1804:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1805:   if (*points) {
1806:     closure = *points;
1807:   } else {
1808:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1809:   }
1810:   closure[0] = p; closure[1] = ornt;
1811:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1812:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1813:     const PetscInt cp = tmp[i];
1814:     PetscInt       co = tmpO ? tmpO[i] : 0;

1816:     if (ornt < 0) {
1817:       PetscInt childSize, coff;
1818:       DMPlexGetConeSize(dm, cp, &childSize);
1819:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
1820:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1821:     }
1822:     closure[closureSize]   = cp;
1823:     closure[closureSize+1] = co;
1824:     fifo[fifoSize]         = cp;
1825:     fifo[fifoSize+1]       = co;
1826:   }
1827:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1828:   while (fifoSize - fifoStart) {
1829:     const PetscInt q   = fifo[fifoStart];
1830:     const PetscInt o   = fifo[fifoStart+1];
1831:     const PetscInt rev = o >= 0 ? 0 : 1;
1832:     const PetscInt off = rev ? -(o+1) : o;

1834:     if (useCone) {
1835:       DMPlexGetConeSize(dm, q, &tmpSize);
1836:       DMPlexGetCone(dm, q, &tmp);
1837:       DMPlexGetConeOrientation(dm, q, &tmpO);
1838:     } else {
1839:       DMPlexGetSupportSize(dm, q, &tmpSize);
1840:       DMPlexGetSupport(dm, q, &tmp);
1841:       tmpO = NULL;
1842:     }
1843:     for (t = 0; t < tmpSize; ++t) {
1844:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1845:       const PetscInt cp = tmp[i];
1846:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1847:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1848:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1849:       PetscInt       co = tmpO ? tmpO[i] : 0;
1850:       PetscInt       c;

1852:       if (rev) {
1853:         PetscInt childSize, coff;
1854:         DMPlexGetConeSize(dm, cp, &childSize);
1855:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1856:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1857:       }
1858:       /* Check for duplicate */
1859:       for (c = 0; c < closureSize; c += 2) {
1860:         if (closure[c] == cp) break;
1861:       }
1862:       if (c == closureSize) {
1863:         closure[closureSize]   = cp;
1864:         closure[closureSize+1] = co;
1865:         fifo[fifoSize]         = cp;
1866:         fifo[fifoSize+1]       = co;
1867:         closureSize           += 2;
1868:         fifoSize              += 2;
1869:       }
1870:     }
1871:     fifoStart += 2;
1872:   }
1873:   if (numPoints) *numPoints = closureSize/2;
1874:   if (points)    *points    = closure;
1875:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1876:   return(0);
1877: }

1881: /*@C
1882:   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG

1884:   Not collective

1886:   Input Parameters:
1887: + mesh - The DMPlex
1888: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1889: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1890: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
1891: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit

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

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

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

1902:   Level: beginner

1904: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1905: @*/
1906: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1907: {

1914:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
1915:   if (numPoints) *numPoints = 0;
1916:   return(0);
1917: }

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

1924:   Not collective

1926:   Input Parameter:
1927: . mesh - The DMPlex

1929:   Output Parameters:
1930: + maxConeSize - The maximum number of in-edges
1931: - maxSupportSize - The maximum number of out-edges

1933:   Level: beginner

1935: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1936: @*/
1937: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1938: {
1939:   DM_Plex *mesh = (DM_Plex*) dm->data;

1943:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1944:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1945:   return(0);
1946: }

1950: PetscErrorCode DMSetUp_Plex(DM dm)
1951: {
1952:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1953:   PetscInt       size;

1958:   PetscSectionSetUp(mesh->coneSection);
1959:   PetscSectionGetStorageSize(mesh->coneSection, &size);
1960:   PetscMalloc1(size, &mesh->cones);
1961:   PetscCalloc1(size, &mesh->coneOrientations);
1962:   if (mesh->maxSupportSize) {
1963:     PetscSectionSetUp(mesh->supportSection);
1964:     PetscSectionGetStorageSize(mesh->supportSection, &size);
1965:     PetscMalloc1(size, &mesh->supports);
1966:   }
1967:   return(0);
1968: }

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

1977:   if (subdm) {DMClone(dm, subdm);}
1978:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
1979:   return(0);
1980: }

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

1987:   Not collective

1989:   Input Parameter:
1990: . mesh - The DMPlex

1992:   Output Parameter:

1994:   Note:
1995:   This should be called after all calls to DMPlexSetCone()

1997:   Level: beginner

1999: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2000: @*/
2001: PetscErrorCode DMPlexSymmetrize(DM dm)
2002: {
2003:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2004:   PetscInt      *offsets;
2005:   PetscInt       supportSize;
2006:   PetscInt       pStart, pEnd, p;

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

2017:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2018:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2019:     for (c = off; c < off+dof; ++c) {
2020:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2021:     }
2022:   }
2023:   for (p = pStart; p < pEnd; ++p) {
2024:     PetscInt dof;

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

2028:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2029:   }
2030:   PetscSectionSetUp(mesh->supportSection);
2031:   /* Calculate supports */
2032:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2033:   PetscMalloc1(supportSize, &mesh->supports);
2034:   PetscCalloc1(pEnd - pStart, &offsets);
2035:   for (p = pStart; p < pEnd; ++p) {
2036:     PetscInt dof, off, c;

2038:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2039:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2040:     for (c = off; c < off+dof; ++c) {
2041:       const PetscInt q = mesh->cones[c];
2042:       PetscInt       offS;

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

2046:       mesh->supports[offS+offsets[q]] = p;
2047:       ++offsets[q];
2048:     }
2049:   }
2050:   PetscFree(offsets);
2051:   return(0);
2052: }

2056: /*@
2057:   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2058:   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2059:   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2060:   the DAG.

2062:   Collective on dm

2064:   Input Parameter:
2065: . mesh - The DMPlex

2067:   Output Parameter:

2069:   Notes:
2070:   Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2071:   1 for edges, and so on.  The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2072:   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
2073:   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.

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

2077:   Level: beginner

2079: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2080: @*/
2081: PetscErrorCode DMPlexStratify(DM dm)
2082: {
2083:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2084:   DMLabel        label;
2085:   PetscInt       pStart, pEnd, p;
2086:   PetscInt       numRoots = 0, numLeaves = 0;

2091:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2092:   /* Calculate depth */
2093:   DMPlexGetChart(dm, &pStart, &pEnd);
2094:   DMCreateLabel(dm, "depth");
2095:   DMPlexGetDepthLabel(dm, &label);
2096:   /* Initialize roots and count leaves */
2097:   for (p = pStart; p < pEnd; ++p) {
2098:     PetscInt coneSize, supportSize;

2100:     DMPlexGetConeSize(dm, p, &coneSize);
2101:     DMPlexGetSupportSize(dm, p, &supportSize);
2102:     if (!coneSize && supportSize) {
2103:       ++numRoots;
2104:       DMLabelSetValue(label, p, 0);
2105:     } else if (!supportSize && coneSize) {
2106:       ++numLeaves;
2107:     } else if (!supportSize && !coneSize) {
2108:       /* Isolated points */
2109:       DMLabelSetValue(label, p, 0);
2110:     }
2111:   }
2112:   if (numRoots + numLeaves == (pEnd - pStart)) {
2113:     for (p = pStart; p < pEnd; ++p) {
2114:       PetscInt coneSize, supportSize;

2116:       DMPlexGetConeSize(dm, p, &coneSize);
2117:       DMPlexGetSupportSize(dm, p, &supportSize);
2118:       if (!supportSize && coneSize) {
2119:         DMLabelSetValue(label, p, 1);
2120:       }
2121:     }
2122:   } else {
2123:     IS       pointIS;
2124:     PetscInt numPoints = 0, level = 0;

2126:     DMLabelGetStratumIS(label, level, &pointIS);
2127:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2128:     while (numPoints) {
2129:       const PetscInt *points;
2130:       const PetscInt  newLevel = level+1;

2132:       ISGetIndices(pointIS, &points);
2133:       for (p = 0; p < numPoints; ++p) {
2134:         const PetscInt  point = points[p];
2135:         const PetscInt *support;
2136:         PetscInt        supportSize, s;

2138:         DMPlexGetSupportSize(dm, point, &supportSize);
2139:         DMPlexGetSupport(dm, point, &support);
2140:         for (s = 0; s < supportSize; ++s) {
2141:           DMLabelSetValue(label, support[s], newLevel);
2142:         }
2143:       }
2144:       ISRestoreIndices(pointIS, &points);
2145:       ++level;
2146:       ISDestroy(&pointIS);
2147:       DMLabelGetStratumIS(label, level, &pointIS);
2148:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2149:       else         {numPoints = 0;}
2150:     }
2151:     ISDestroy(&pointIS);
2152:   }
2153:   { /* just in case there is an empty process */
2154:     PetscInt numValues, maxValues = 0, v;

2156:     DMLabelGetNumValues(label,&numValues);
2157:     for (v = 0; v < numValues; v++) {
2158:       IS pointIS;

2160:       DMLabelGetStratumIS(label, v, &pointIS);
2161:       if (pointIS) {
2162:         PetscInt  min, max, numPoints;
2163:         PetscInt  start;
2164:         PetscBool contig;

2166:         ISGetLocalSize(pointIS, &numPoints);
2167:         ISGetMinMax(pointIS, &min, &max);
2168:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2169:         if (start == 0 && contig) {
2170:           ISDestroy(&pointIS);
2171:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2172:           DMLabelSetStratumIS(label, v, pointIS);
2173:         }
2174:       }
2175:       ISDestroy(&pointIS);
2176:     }
2177:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2178:     for (v = numValues; v < maxValues; v++) {
2179:       DMLabelAddStratum(label,v);
2180:     }
2181:   }

2183:   DMLabelGetState(label, &mesh->depthState);
2184:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2185:   return(0);
2186: }

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

2193:   Not Collective

2195:   Input Parameters:
2196: + dm - The DMPlex object
2197: . numPoints - The number of input points for the join
2198: - points - The input points

2200:   Output Parameters:
2201: + numCoveredPoints - The number of points in the join
2202: - coveredPoints - The points in the join

2204:   Level: intermediate

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

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

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

2214: .keywords: mesh
2215: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2216: @*/
2217: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2218: {
2219:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2220:   PetscInt      *join[2];
2221:   PetscInt       joinSize, i = 0;
2222:   PetscInt       dof, off, p, c, m;

2230:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
2231:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
2232:   /* Copy in support of first point */
2233:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2234:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2235:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2236:     join[i][joinSize] = mesh->supports[off+joinSize];
2237:   }
2238:   /* Check each successive support */
2239:   for (p = 1; p < numPoints; ++p) {
2240:     PetscInt newJoinSize = 0;

2242:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2243:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2244:     for (c = 0; c < dof; ++c) {
2245:       const PetscInt point = mesh->supports[off+c];

2247:       for (m = 0; m < joinSize; ++m) {
2248:         if (point == join[i][m]) {
2249:           join[1-i][newJoinSize++] = point;
2250:           break;
2251:         }
2252:       }
2253:     }
2254:     joinSize = newJoinSize;
2255:     i        = 1-i;
2256:   }
2257:   *numCoveredPoints = joinSize;
2258:   *coveredPoints    = join[i];
2259:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2260:   return(0);
2261: }

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

2268:   Not Collective

2270:   Input Parameters:
2271: + dm - The DMPlex object
2272: . numPoints - The number of input points for the join
2273: - points - The input points

2275:   Output Parameters:
2276: + numCoveredPoints - The number of points in the join
2277: - coveredPoints - The points in the join

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

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

2285:   Level: intermediate

2287: .keywords: mesh
2288: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2289: @*/
2290: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2291: {

2299:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2300:   if (numCoveredPoints) *numCoveredPoints = 0;
2301:   return(0);
2302: }

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

2309:   Not Collective

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

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

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

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

2326:   Level: intermediate

2328: .keywords: mesh
2329: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2330: @*/
2331: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2332: {
2333:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2334:   PetscInt      *offsets, **closures;
2335:   PetscInt      *join[2];
2336:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2337:   PetscInt       p, d, c, m, ms;


2346:   DMPlexGetDepth(dm, &depth);
2347:   PetscCalloc1(numPoints, &closures);
2348:   DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2349:   ms      = mesh->maxSupportSize;
2350:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2351:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
2352:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);

2354:   for (p = 0; p < numPoints; ++p) {
2355:     PetscInt closureSize;

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

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

2363:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2364:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2365:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2366:           offsets[p*(depth+2)+d+1] = i;
2367:           break;
2368:         }
2369:       }
2370:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2371:     }
2372:     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);
2373:   }
2374:   for (d = 0; d < depth+1; ++d) {
2375:     PetscInt dof;

2377:     /* Copy in support of first point */
2378:     dof = offsets[d+1] - offsets[d];
2379:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2380:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2381:     }
2382:     /* Check each successive cone */
2383:     for (p = 1; p < numPoints && joinSize; ++p) {
2384:       PetscInt newJoinSize = 0;

2386:       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2387:       for (c = 0; c < dof; ++c) {
2388:         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];

2390:         for (m = 0; m < joinSize; ++m) {
2391:           if (point == join[i][m]) {
2392:             join[1-i][newJoinSize++] = point;
2393:             break;
2394:           }
2395:         }
2396:       }
2397:       joinSize = newJoinSize;
2398:       i        = 1-i;
2399:     }
2400:     if (joinSize) break;
2401:   }
2402:   *numCoveredPoints = joinSize;
2403:   *coveredPoints    = join[i];
2404:   for (p = 0; p < numPoints; ++p) {
2405:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2406:   }
2407:   PetscFree(closures);
2408:   DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2409:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2410:   return(0);
2411: }

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

2418:   Not Collective

2420:   Input Parameters:
2421: + dm - The DMPlex object
2422: . numPoints - The number of input points for the meet
2423: - points - The input points

2425:   Output Parameters:
2426: + numCoveredPoints - The number of points in the meet
2427: - coveredPoints - The points in the meet

2429:   Level: intermediate

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

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

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

2439: .keywords: mesh
2440: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2441: @*/
2442: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2443: {
2444:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2445:   PetscInt      *meet[2];
2446:   PetscInt       meetSize, i = 0;
2447:   PetscInt       dof, off, p, c, m;

2455:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
2456:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
2457:   /* Copy in cone of first point */
2458:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2459:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2460:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2461:     meet[i][meetSize] = mesh->cones[off+meetSize];
2462:   }
2463:   /* Check each successive cone */
2464:   for (p = 1; p < numPoints; ++p) {
2465:     PetscInt newMeetSize = 0;

2467:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2468:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2469:     for (c = 0; c < dof; ++c) {
2470:       const PetscInt point = mesh->cones[off+c];

2472:       for (m = 0; m < meetSize; ++m) {
2473:         if (point == meet[i][m]) {
2474:           meet[1-i][newMeetSize++] = point;
2475:           break;
2476:         }
2477:       }
2478:     }
2479:     meetSize = newMeetSize;
2480:     i        = 1-i;
2481:   }
2482:   *numCoveringPoints = meetSize;
2483:   *coveringPoints    = meet[i];
2484:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2485:   return(0);
2486: }

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

2493:   Not Collective

2495:   Input Parameters:
2496: + dm - The DMPlex object
2497: . numPoints - The number of input points for the meet
2498: - points - The input points

2500:   Output Parameters:
2501: + numCoveredPoints - The number of points in the meet
2502: - coveredPoints - The points in the meet

2504:   Level: intermediate

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

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

2512: .keywords: mesh
2513: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2514: @*/
2515: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2516: {

2524:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2525:   if (numCoveredPoints) *numCoveredPoints = 0;
2526:   return(0);
2527: }

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

2534:   Not Collective

2536:   Input Parameters:
2537: + dm - The DMPlex object
2538: . numPoints - The number of input points for the meet
2539: - points - The input points

2541:   Output Parameters:
2542: + numCoveredPoints - The number of points in the meet
2543: - coveredPoints - The points in the meet

2545:   Level: intermediate

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

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

2553: .keywords: mesh
2554: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2555: @*/
2556: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2557: {
2558:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2559:   PetscInt      *offsets, **closures;
2560:   PetscInt      *meet[2];
2561:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2562:   PetscInt       p, h, c, m, mc;


2571:   DMPlexGetDepth(dm, &height);
2572:   PetscMalloc1(numPoints, &closures);
2573:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2574:   mc      = mesh->maxConeSize;
2575:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2576:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
2577:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

2579:   for (p = 0; p < numPoints; ++p) {
2580:     PetscInt closureSize;

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

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

2588:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2589:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2590:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2591:           offsets[p*(height+2)+h+1] = i;
2592:           break;
2593:         }
2594:       }
2595:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2596:     }
2597:     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);
2598:   }
2599:   for (h = 0; h < height+1; ++h) {
2600:     PetscInt dof;

2602:     /* Copy in cone of first point */
2603:     dof = offsets[h+1] - offsets[h];
2604:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2605:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2606:     }
2607:     /* Check each successive cone */
2608:     for (p = 1; p < numPoints && meetSize; ++p) {
2609:       PetscInt newMeetSize = 0;

2611:       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2612:       for (c = 0; c < dof; ++c) {
2613:         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];

2615:         for (m = 0; m < meetSize; ++m) {
2616:           if (point == meet[i][m]) {
2617:             meet[1-i][newMeetSize++] = point;
2618:             break;
2619:           }
2620:         }
2621:       }
2622:       meetSize = newMeetSize;
2623:       i        = 1-i;
2624:     }
2625:     if (meetSize) break;
2626:   }
2627:   *numCoveredPoints = meetSize;
2628:   *coveredPoints    = meet[i];
2629:   for (p = 0; p < numPoints; ++p) {
2630:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2631:   }
2632:   PetscFree(closures);
2633:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2634:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2635:   return(0);
2636: }

2640: /*@C
2641:   DMPlexEqual - Determine if two DMs have the same topology

2643:   Not Collective

2645:   Input Parameters:
2646: + dmA - A DMPlex object
2647: - dmB - A DMPlex object

2649:   Output Parameters:
2650: . equal - PETSC_TRUE if the topologies are identical

2652:   Level: intermediate

2654:   Notes:
2655:   We are not solving graph isomorphism, so we do not permutation.

2657: .keywords: mesh
2658: .seealso: DMPlexGetCone()
2659: @*/
2660: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2661: {
2662:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2670:   *equal = PETSC_FALSE;
2671:   DMPlexGetDepth(dmA, &depth);
2672:   DMPlexGetDepth(dmB, &depthB);
2673:   if (depth != depthB) return(0);
2674:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2675:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2676:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2677:   for (p = pStart; p < pEnd; ++p) {
2678:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2679:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

2681:     DMPlexGetConeSize(dmA, p, &coneSize);
2682:     DMPlexGetCone(dmA, p, &cone);
2683:     DMPlexGetConeOrientation(dmA, p, &ornt);
2684:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2685:     DMPlexGetCone(dmB, p, &coneB);
2686:     DMPlexGetConeOrientation(dmB, p, &orntB);
2687:     if (coneSize != coneSizeB) return(0);
2688:     for (c = 0; c < coneSize; ++c) {
2689:       if (cone[c] != coneB[c]) return(0);
2690:       if (ornt[c] != orntB[c]) return(0);
2691:     }
2692:     DMPlexGetSupportSize(dmA, p, &supportSize);
2693:     DMPlexGetSupport(dmA, p, &support);
2694:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2695:     DMPlexGetSupport(dmB, p, &supportB);
2696:     if (supportSize != supportSizeB) return(0);
2697:     for (s = 0; s < supportSize; ++s) {
2698:       if (support[s] != supportB[s]) return(0);
2699:     }
2700:   }
2701:   *equal = PETSC_TRUE;
2702:   return(0);
2703: }

2707: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2708: {
2709:   MPI_Comm       comm;

2713:   PetscObjectGetComm((PetscObject)dm,&comm);
2715:   switch (cellDim) {
2716:   case 0:
2717:     *numFaceVertices = 0;
2718:     break;
2719:   case 1:
2720:     *numFaceVertices = 1;
2721:     break;
2722:   case 2:
2723:     switch (numCorners) {
2724:     case 3: /* triangle */
2725:       *numFaceVertices = 2; /* Edge has 2 vertices */
2726:       break;
2727:     case 4: /* quadrilateral */
2728:       *numFaceVertices = 2; /* Edge has 2 vertices */
2729:       break;
2730:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2731:       *numFaceVertices = 3; /* Edge has 3 vertices */
2732:       break;
2733:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2734:       *numFaceVertices = 3; /* Edge has 3 vertices */
2735:       break;
2736:     default:
2737:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2738:     }
2739:     break;
2740:   case 3:
2741:     switch (numCorners) {
2742:     case 4: /* tetradehdron */
2743:       *numFaceVertices = 3; /* Face has 3 vertices */
2744:       break;
2745:     case 6: /* tet cohesive cells */
2746:       *numFaceVertices = 4; /* Face has 4 vertices */
2747:       break;
2748:     case 8: /* hexahedron */
2749:       *numFaceVertices = 4; /* Face has 4 vertices */
2750:       break;
2751:     case 9: /* tet cohesive Lagrange cells */
2752:       *numFaceVertices = 6; /* Face has 6 vertices */
2753:       break;
2754:     case 10: /* quadratic tetrahedron */
2755:       *numFaceVertices = 6; /* Face has 6 vertices */
2756:       break;
2757:     case 12: /* hex cohesive Lagrange cells */
2758:       *numFaceVertices = 6; /* Face has 6 vertices */
2759:       break;
2760:     case 18: /* quadratic tet cohesive Lagrange cells */
2761:       *numFaceVertices = 6; /* Face has 6 vertices */
2762:       break;
2763:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2764:       *numFaceVertices = 9; /* Face has 9 vertices */
2765:       break;
2766:     default:
2767:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2768:     }
2769:     break;
2770:   default:
2771:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
2772:   }
2773:   return(0);
2774: }

2778: /*@
2779:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

2781:   Not Collective

2783:   Input Parameter:
2784: . dm    - The DMPlex object

2786:   Output Parameter:
2787: . depthLabel - The DMLabel recording point depth

2789:   Level: developer

2791: .keywords: mesh, points
2792: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2793: @*/
2794: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2795: {

2801:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
2802:   *depthLabel = dm->depthLabel;
2803:   return(0);
2804: }

2808: /*@
2809:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

2811:   Not Collective

2813:   Input Parameter:
2814: . dm    - The DMPlex object

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

2819:   Level: developer

2821: .keywords: mesh, points
2822: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2823: @*/
2824: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
2825: {
2826:   DMLabel        label;
2827:   PetscInt       d = 0;

2833:   DMPlexGetDepthLabel(dm, &label);
2834:   if (label) {DMLabelGetNumValues(label, &d);}
2835:   *depth = d-1;
2836:   return(0);
2837: }

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

2844:   Not Collective

2846:   Input Parameters:
2847: + dm           - The DMPlex object
2848: - stratumValue - The requested depth

2850:   Output Parameters:
2851: + start - The first point at this depth
2852: - end   - One beyond the last point at this depth

2854:   Level: developer

2856: .keywords: mesh, points
2857: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
2858: @*/
2859: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2860: {
2861:   DMLabel        label;
2862:   PetscInt       pStart, pEnd;

2869:   DMPlexGetChart(dm, &pStart, &pEnd);
2870:   if (pStart == pEnd) return(0);
2871:   if (stratumValue < 0) {
2872:     if (start) *start = pStart;
2873:     if (end)   *end   = pEnd;
2874:     return(0);
2875:   }
2876:   DMPlexGetDepthLabel(dm, &label);
2877:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2878:   DMLabelGetStratumBounds(label, stratumValue, start, end);
2879:   return(0);
2880: }

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

2887:   Not Collective

2889:   Input Parameters:
2890: + dm           - The DMPlex object
2891: - stratumValue - The requested height

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

2897:   Level: developer

2899: .keywords: mesh, points
2900: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
2901: @*/
2902: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2903: {
2904:   DMLabel        label;
2905:   PetscInt       depth, pStart, pEnd;

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

2928: /* Set the number of dof on each point and separate by fields */
2929: PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
2930: {
2931:   PetscInt      *pMax;
2932:   PetscInt       depth, pStart = 0, pEnd = 0;
2933:   PetscInt       Nf, p, d, dep, f;
2934:   PetscBool     *isFE;

2938:   PetscMalloc1(numFields, &isFE);
2939:   DMGetNumFields(dm, &Nf);
2940:   for (f = 0; f < numFields; ++f) {
2941:     PetscObject  obj;
2942:     PetscClassId id;

2944:     isFE[f] = PETSC_FALSE;
2945:     if (f >= Nf) continue;
2946:     DMGetField(dm, f, &obj);
2947:     PetscObjectGetClassId(obj, &id);
2948:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2949:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2950:   }
2951:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
2952:   if (numFields > 0) {
2953:     PetscSectionSetNumFields(*section, numFields);
2954:     if (numComp) {
2955:       for (f = 0; f < numFields; ++f) {
2956:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
2957:         if (isFE[f]) {
2958:           PetscFE           fe;
2959:           PetscDualSpace    dspace;
2960:           const PetscInt    ***perms;
2961:           const PetscScalar ***flips;
2962:           const PetscInt    *numDof;

2964:           DMGetField(dm,f,(PetscObject *) &fe);
2965:           PetscFEGetDualSpace(fe,&dspace);
2966:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
2967:           PetscDualSpaceGetNumDof(dspace,&numDof);
2968:           if (perms || flips) {
2969:             DM               K;
2970:             DMLabel          depthLabel;
2971:             PetscInt         depth, h;
2972:             PetscSectionSym  sym;

2974:             PetscDualSpaceGetDM(dspace,&K);
2975:             DMPlexGetDepthLabel(dm,&depthLabel);
2976:             DMPlexGetDepth(dm,&depth);
2977:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
2978:             for (h = 0; h <= depth; h++) {
2979:               PetscDualSpace    hspace;
2980:               PetscInt          kStart, kEnd;
2981:               PetscInt          kConeSize;
2982:               const PetscInt    **perms0 = NULL;
2983:               const PetscScalar **flips0 = NULL;

2985:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
2986:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
2987:               if (!hspace) continue;
2988:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
2989:               if (perms) perms0 = perms[0];
2990:               if (flips) flips0 = flips[0];
2991:               if (!(perms0 || flips0)) continue;
2992:               DMPlexGetConeSize(K,kStart,&kConeSize);
2993:               if (numComp[f] == 1) {
2994:                 PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
2995:               } else {
2996:                 PetscInt    **fieldPerms = NULL, o;
2997:                 PetscScalar **fieldFlips = NULL;

2999:                 PetscCalloc1(2 * kConeSize,&fieldPerms);
3000:                 PetscCalloc1(2 * kConeSize,&fieldFlips);
3001:                 for (o = -kConeSize; o < kConeSize; o++) {
3002:                   if (perms0 && perms0[o]) {
3003:                     PetscInt r, s;

3005:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldPerms[o+kConeSize]);
3006:                     for (r = 0; r < numDof[depth - h]; r++) {
3007:                       for (s = 0; s < numComp[f]; s++) {
3008:                         fieldPerms[o+kConeSize][r * numComp[f] + s] = numComp[f] * perms0[o][r] + s;
3009:                       }
3010:                     }
3011:                   }
3012:                   if (flips0 && flips0[o]) {
3013:                     PetscInt r, s;

3015:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldFlips[o+kConeSize]);
3016:                     for (r = 0; r < numDof[depth - h]; r++) {
3017:                       for (s = 0; s < numComp[f]; s++) {
3018:                         fieldFlips[o+kConeSize][r * numComp[f] + s] = flips0[o][r];
3019:                       }
3020:                     }
3021:                   }
3022:                 }
3023:                 PetscSectionSymLabelSetStratum(sym,depth - h,numComp[f] * numDof[depth - h],-kConeSize,kConeSize,PETSC_OWN_POINTER,(const PetscInt **) fieldPerms,(const PetscScalar **)fieldFlips);
3024:               }
3025:             }
3026:             PetscSectionSetFieldSym(*section,f,sym);
3027:             PetscSectionSymDestroy(&sym);
3028:           }
3029:         }
3030:       }
3031:     }
3032:   }
3033:   DMPlexGetChart(dm, &pStart, &pEnd);
3034:   PetscSectionSetChart(*section, pStart, pEnd);
3035:   DMPlexGetDepth(dm, &depth);
3036:   PetscMalloc1(depth+1,&pMax);
3037:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3038:   for (dep = 0; dep <= depth; ++dep) {
3039:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3040:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3041:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3042:     for (p = pStart; p < pEnd; ++p) {
3043:       PetscInt tot = 0;

3045:       for (f = 0; f < numFields; ++f) {
3046:         if (isFE[f] && p >= pMax[dep]) continue;
3047:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3048:         tot += numDof[f*(dim+1)+d];
3049:       }
3050:       PetscSectionSetDof(*section, p, tot);
3051:     }
3052:   }
3053:   PetscFree(pMax);
3054:   PetscFree(isFE);
3055:   return(0);
3056: }

3060: /* Set the number of dof on each point and separate by fields
3061:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3062: */
3063: PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3064: {
3065:   PetscInt       numFields;
3066:   PetscInt       bc;
3067:   PetscSection   aSec;

3071:   PetscSectionGetNumFields(section, &numFields);
3072:   for (bc = 0; bc < numBC; ++bc) {
3073:     PetscInt        field = 0;
3074:     const PetscInt *comp;
3075:     const PetscInt *idx;
3076:     PetscInt        Nc = -1, n, i;

3078:     if (numFields) field = bcField[bc];
3079:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3080:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3081:     ISGetLocalSize(bcPoints[bc], &n);
3082:     ISGetIndices(bcPoints[bc], &idx);
3083:     for (i = 0; i < n; ++i) {
3084:       const PetscInt p = idx[i];
3085:       PetscInt       numConst;

3087:       if (numFields) {
3088:         PetscSectionGetFieldDof(section, p, field, &numConst);
3089:       } else {
3090:         PetscSectionGetDof(section, p, &numConst);
3091:       }
3092:       /* If Nc < 0, constrain every dof on the point */
3093:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3094:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3095:       PetscSectionAddConstraintDof(section, p, numConst);
3096:     }
3097:     ISRestoreIndices(bcPoints[bc], &idx);
3098:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3099:   }
3100:   DMPlexGetAnchors(dm, &aSec, NULL);
3101:   if (aSec) {
3102:     PetscInt aStart, aEnd, a;

3104:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3105:     for (a = aStart; a < aEnd; a++) {
3106:       PetscInt dof, f;

3108:       PetscSectionGetDof(aSec, a, &dof);
3109:       if (dof) {
3110:         /* if there are point-to-point constraints, then all dofs are constrained */
3111:         PetscSectionGetDof(section, a, &dof);
3112:         PetscSectionSetConstraintDof(section, a, dof);
3113:         for (f = 0; f < numFields; f++) {
3114:           PetscSectionGetFieldDof(section, a, f, &dof);
3115:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3116:         }
3117:       }
3118:     }
3119:   }
3120:   return(0);
3121: }

3125: /* Set the constrained field indices on each point
3126:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3127: */
3128: PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3129: {
3130:   PetscSection   aSec;
3131:   PetscInt      *indices;
3132:   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;

3136:   PetscSectionGetNumFields(section, &numFields);
3137:   if (!numFields) return(0);
3138:   /* Initialize all field indices to -1 */
3139:   PetscSectionGetChart(section, &pStart, &pEnd);
3140:   PetscSectionGetMaxDof(section, &maxDof);
3141:   PetscMalloc1(maxDof, &indices);
3142:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3143:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3144:   /* Handle BC constraints */
3145:   for (bc = 0; bc < numBC; ++bc) {
3146:     const PetscInt  field = bcField[bc];
3147:     const PetscInt *comp, *idx;
3148:     PetscInt        Nc = -1, n, i;

3150:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3151:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3152:     ISGetLocalSize(bcPoints[bc], &n);
3153:     ISGetIndices(bcPoints[bc], &idx);
3154:     for (i = 0; i < n; ++i) {
3155:       const PetscInt  p = idx[i];
3156:       const PetscInt *find;
3157:       PetscInt        fcdof, c;

3159:       PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3160:       if (Nc < 0) {
3161:         for (d = 0; d < fcdof; ++d) indices[d] = d;
3162:       } else {
3163:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3164:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3165:         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
3166:         PetscSortInt(d+Nc, indices);
3167:         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3168:       }
3169:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3170:     }
3171:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3172:     ISRestoreIndices(bcPoints[bc], &idx);
3173:   }
3174:   /* Handle anchors */
3175:   DMPlexGetAnchors(dm, &aSec, NULL);
3176:   if (aSec) {
3177:     PetscInt aStart, aEnd, a;

3179:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3180:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3181:     for (a = aStart; a < aEnd; a++) {
3182:       PetscInt dof, fdof, f;

3184:       PetscSectionGetDof(aSec, a, &dof);
3185:       if (dof) {
3186:         /* if there are point-to-point constraints, then all dofs are constrained */
3187:         for (f = 0; f < numFields; f++) {
3188:           PetscSectionGetFieldDof(section, a, f, &fdof);
3189:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3190:         }
3191:       }
3192:     }
3193:   }
3194:   PetscFree(indices);
3195:   return(0);
3196: }

3200: /* Set the constrained indices on each point */
3201: PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3202: {
3203:   PetscInt      *indices;
3204:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3208:   PetscSectionGetNumFields(section, &numFields);
3209:   PetscSectionGetMaxDof(section, &maxDof);
3210:   PetscSectionGetChart(section, &pStart, &pEnd);
3211:   PetscMalloc1(maxDof, &indices);
3212:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3213:   for (p = pStart; p < pEnd; ++p) {
3214:     PetscInt cdof, d;

3216:     PetscSectionGetConstraintDof(section, p, &cdof);
3217:     if (cdof) {
3218:       if (numFields) {
3219:         PetscInt numConst = 0, foff = 0;

3221:         for (f = 0; f < numFields; ++f) {
3222:           const PetscInt *find;
3223:           PetscInt        fcdof, fdof;

3225:           PetscSectionGetFieldDof(section, p, f, &fdof);
3226:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3227:           /* Change constraint numbering from field component to local dof number */
3228:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3229:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3230:           numConst += fcdof;
3231:           foff     += fdof;
3232:         }
3233:         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
3234:       } else {
3235:         for (d = 0; d < cdof; ++d) indices[d] = d;
3236:       }
3237:       PetscSectionSetConstraintIndices(section, p, indices);
3238:     }
3239:   }
3240:   PetscFree(indices);
3241:   return(0);
3242: }

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

3249:   Not Collective

3251:   Input Parameters:
3252: + dm        - The DMPlex object
3253: . dim       - The spatial dimension of the problem
3254: . numFields - The number of fields in the problem
3255: . numComp   - An array of size numFields that holds the number of components for each field
3256: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3257: . numBC     - The number of boundary conditions
3258: . bcField   - An array of size numBC giving the field number for each boundry condition
3259: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3260: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3261: - perm      - Optional permutation of the chart, or NULL

3263:   Output Parameter:
3264: . section - The PetscSection object

3266:   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
3267:   number of dof for field 0 on each edge.

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

3271:   Level: developer

3273:   Fortran Notes:
3274:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3276: .keywords: mesh, elements
3277: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3278: @*/
3279: 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)
3280: {
3281:   PetscSection   aSec;

3285:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3286:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3287:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3288:   PetscSectionSetUp(*section);
3289:   DMPlexGetAnchors(dm,&aSec,NULL);
3290:   if (numBC || aSec) {
3291:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3292:     DMPlexCreateSectionBCIndices(dm, *section);
3293:   }
3294:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3295:   return(0);
3296: }

3300: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3301: {
3302:   PetscSection   section, s;
3303:   Mat            m;
3304:   PetscInt       maxHeight;

3308:   DMClone(dm, cdm);
3309:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3310:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3311:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3312:   DMSetDefaultSection(*cdm, section);
3313:   PetscSectionDestroy(&section);
3314:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3315:   MatCreate(PETSC_COMM_SELF, &m);
3316:   DMSetDefaultConstraints(*cdm, s, m);
3317:   PetscSectionDestroy(&s);
3318:   MatDestroy(&m);
3319:   return(0);
3320: }

3324: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3325: {
3326:   DM_Plex *mesh = (DM_Plex*) dm->data;

3330:   if (section) *section = mesh->coneSection;
3331:   return(0);
3332: }

3336: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3337: {
3338:   DM_Plex *mesh = (DM_Plex*) dm->data;

3342:   if (section) *section = mesh->supportSection;
3343:   return(0);
3344: }

3348: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3349: {
3350:   DM_Plex *mesh = (DM_Plex*) dm->data;

3354:   if (cones) *cones = mesh->cones;
3355:   return(0);
3356: }

3360: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3361: {
3362:   DM_Plex *mesh = (DM_Plex*) dm->data;

3366:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3367:   return(0);
3368: }

3370: /******************************** FEM Support **********************************/

3374: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3375: {
3376:   PetscInt      *perm;
3377:   PetscInt       dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3381:   if (!section) {DMGetDefaultSection(dm, &section);}
3382:   DMGetDimension(dm, &dim);
3383:   PetscSectionGetNumFields(section, &Nf);
3384:   if (dim <= 1) return(0);
3385:   for (f = 0; f < Nf; ++f) {
3386:     /* An order k SEM disc has k-1 dofs on an edge */
3387:     DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3388:     PetscSectionGetFieldDof(section, eStart, f, &k);
3389:     PetscSectionGetFieldComponents(section, f, &Nc);
3390:     k = k/Nc + 1;
3391:     size += PetscPowInt(k+1, dim)*Nc;
3392:   }
3393:   PetscMalloc1(size, &perm);
3394:   for (f = 0; f < Nf; ++f) {
3395:     switch (dim) {
3396:     case 2:
3397:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3398:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3399:       PetscSectionGetFieldDof(section, eStart, f, &k);
3400:       PetscSectionGetFieldComponents(section, f, &Nc);
3401:       k = k/Nc + 1;
3402:       /* The SEM order is

3404:          v_lb, {e_b}, v_rb,
3405:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3406:          v_lt, reverse {e_t}, v_rt
3407:       */
3408:       {
3409:         const PetscInt of   = 0;
3410:         const PetscInt oeb  = of   + PetscSqr(k-1);
3411:         const PetscInt oer  = oeb  + (k-1);
3412:         const PetscInt oet  = oer  + (k-1);
3413:         const PetscInt oel  = oet  + (k-1);
3414:         const PetscInt ovlb = oel  + (k-1);
3415:         const PetscInt ovrb = ovlb + 1;
3416:         const PetscInt ovrt = ovrb + 1;
3417:         const PetscInt ovlt = ovrt + 1;
3418:         PetscInt       o;

3420:         /* bottom */
3421:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3422:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3423:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3424:         /* middle */
3425:         for (i = 0; i < k-1; ++i) {
3426:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3427:           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;
3428:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3429:         }
3430:         /* top */
3431:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3432:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3433:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3434:         foffset = offset;
3435:       }
3436:       break;
3437:     case 3:
3438:       /* The original hex closure is

3440:          {c,
3441:           f_b, f_t, f_f, f_b, f_r, f_l,
3442:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3443:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3444:       */
3445:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3446:       PetscSectionGetFieldDof(section, eStart, f, &k);
3447:       PetscSectionGetFieldComponents(section, f, &Nc);
3448:       k = k/Nc + 1;
3449:       /* The SEM order is
3450:          Bottom Slice
3451:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3452:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3453:          v_blb, {e_bb}, v_brb,

3455:          Middle Slice (j)
3456:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3457:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3458:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3460:          Top Slice
3461:          v_tlf, {e_tf}, v_trf,
3462:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3463:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3464:       */
3465:       {
3466:         const PetscInt oc    = 0;
3467:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3468:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3469:         const PetscInt off   = oft   + PetscSqr(k-1);
3470:         const PetscInt ofk   = off   + PetscSqr(k-1);
3471:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3472:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3473:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3474:         const PetscInt oebb  = oebl  + (k-1);
3475:         const PetscInt oebr  = oebb  + (k-1);
3476:         const PetscInt oebf  = oebr  + (k-1);
3477:         const PetscInt oetf  = oebf  + (k-1);
3478:         const PetscInt oetr  = oetf  + (k-1);
3479:         const PetscInt oetb  = oetr  + (k-1);
3480:         const PetscInt oetl  = oetb  + (k-1);
3481:         const PetscInt oerf  = oetl  + (k-1);
3482:         const PetscInt oelf  = oerf  + (k-1);
3483:         const PetscInt oelb  = oelf  + (k-1);
3484:         const PetscInt oerb  = oelb  + (k-1);
3485:         const PetscInt ovblf = oerb  + (k-1);
3486:         const PetscInt ovblb = ovblf + 1;
3487:         const PetscInt ovbrb = ovblb + 1;
3488:         const PetscInt ovbrf = ovbrb + 1;
3489:         const PetscInt ovtlf = ovbrf + 1;
3490:         const PetscInt ovtrf = ovtlf + 1;
3491:         const PetscInt ovtrb = ovtrf + 1;
3492:         const PetscInt ovtlb = ovtrb + 1;
3493:         PetscInt       o, n;

3495:         /* Bottom Slice */
3496:         /*   bottom */
3497:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3498:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3499:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3500:         /*   middle */
3501:         for (i = 0; i < k-1; ++i) {
3502:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3503:           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;}
3504:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3505:         }
3506:         /*   top */
3507:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3508:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3509:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3511:         /* Middle Slice */
3512:         for (j = 0; j < k-1; ++j) {
3513:           /*   bottom */
3514:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3515:           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;
3516:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3517:           /*   middle */
3518:           for (i = 0; i < k-1; ++i) {
3519:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3520:             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;
3521:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3522:           }
3523:           /*   top */
3524:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3525:           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;
3526:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3527:         }

3529:         /* Top Slice */
3530:         /*   bottom */
3531:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3532:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3533:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3534:         /*   middle */
3535:         for (i = 0; i < k-1; ++i) {
3536:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3537:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3538:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3539:         }
3540:         /*   top */
3541:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3542:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3543:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3545:         foffset = offset;
3546:       }
3547:       break;
3548:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3549:     }
3550:   }
3551:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3552:   /* Check permutation */
3553:   {
3554:     PetscInt *check;

3556:     PetscMalloc1(size, &check);
3557:     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]);}
3558:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3559:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3560:     PetscFree(check);
3561:   }
3562:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3563:   return(0);
3564: }

3568: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3569: {
3570:   PetscDS        prob;
3571:   PetscInt       depth, Nf, h;
3572:   DMLabel        label;

3576:   prob    = dm->prob;
3577:   Nf      = prob->Nf;
3578:   label   = dm->depthLabel;
3579:   *dspace = NULL;
3580:   if (field < Nf) {
3581:     PetscObject disc = prob->disc[field];

3583:     if (disc->classid == PETSCFE_CLASSID) {
3584:       PetscDualSpace dsp;

3586:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3587:       DMLabelGetNumValues(label,&depth);
3588:       DMLabelGetValue(label,point,&h);
3589:       h    = depth - 1 - h;
3590:       if (h) {
3591:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3592:       } else {
3593:         *dspace = dsp;
3594:       }
3595:     }
3596:   }
3597:   return(0);
3598: }


3603: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3604: {
3605:   PetscScalar    *array, *vArray;
3606:   const PetscInt *cone, *coneO;
3607:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3608:   PetscErrorCode  ierr;

3611:   PetscSectionGetChart(section, &pStart, &pEnd);
3612:   DMPlexGetConeSize(dm, point, &numPoints);
3613:   DMPlexGetCone(dm, point, &cone);
3614:   DMPlexGetConeOrientation(dm, point, &coneO);
3615:   if (!values || !*values) {
3616:     if ((point >= pStart) && (point < pEnd)) {
3617:       PetscInt dof;

3619:       PetscSectionGetDof(section, point, &dof);
3620:       size += dof;
3621:     }
3622:     for (p = 0; p < numPoints; ++p) {
3623:       const PetscInt cp = cone[p];
3624:       PetscInt       dof;

3626:       if ((cp < pStart) || (cp >= pEnd)) continue;
3627:       PetscSectionGetDof(section, cp, &dof);
3628:       size += dof;
3629:     }
3630:     if (!values) {
3631:       if (csize) *csize = size;
3632:       return(0);
3633:     }
3634:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
3635:   } else {
3636:     array = *values;
3637:   }
3638:   size = 0;
3639:   VecGetArray(v, &vArray);
3640:   if ((point >= pStart) && (point < pEnd)) {
3641:     PetscInt     dof, off, d;
3642:     PetscScalar *varr;

3644:     PetscSectionGetDof(section, point, &dof);
3645:     PetscSectionGetOffset(section, point, &off);
3646:     varr = &vArray[off];
3647:     for (d = 0; d < dof; ++d, ++offset) {
3648:       array[offset] = varr[d];
3649:     }
3650:     size += dof;
3651:   }
3652:   for (p = 0; p < numPoints; ++p) {
3653:     const PetscInt cp = cone[p];
3654:     PetscInt       o  = coneO[p];
3655:     PetscInt       dof, off, d;
3656:     PetscScalar   *varr;

3658:     if ((cp < pStart) || (cp >= pEnd)) continue;
3659:     PetscSectionGetDof(section, cp, &dof);
3660:     PetscSectionGetOffset(section, cp, &off);
3661:     varr = &vArray[off];
3662:     if (o >= 0) {
3663:       for (d = 0; d < dof; ++d, ++offset) {
3664:         array[offset] = varr[d];
3665:       }
3666:     } else {
3667:       for (d = dof-1; d >= 0; --d, ++offset) {
3668:         array[offset] = varr[d];
3669:       }
3670:     }
3671:     size += dof;
3672:   }
3673:   VecRestoreArray(v, &vArray);
3674:   if (!*values) {
3675:     if (csize) *csize = size;
3676:     *values = array;
3677:   } else {
3678:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3679:     *csize = size;
3680:   }
3681:   return(0);
3682: }

3686: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3687: {
3688:   const PetscInt *cla;
3689:   PetscInt       np, *pts = NULL;

3693:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3694:   if (!*clPoints) {
3695:     PetscInt pStart, pEnd, p, q;

3697:     PetscSectionGetChart(section, &pStart, &pEnd);
3698:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3699:     /* Compress out points not in the section */
3700:     for (p = 0, q = 0; p < np; p++) {
3701:       PetscInt r = pts[2*p];
3702:       if ((r >= pStart) && (r < pEnd)) {
3703:         pts[q*2]   = r;
3704:         pts[q*2+1] = pts[2*p+1];
3705:         ++q;
3706:       }
3707:     }
3708:     np = q;
3709:     cla = NULL;
3710:   } else {
3711:     PetscInt dof, off;

3713:     PetscSectionGetDof(*clSec, point, &dof);
3714:     PetscSectionGetOffset(*clSec, point, &off);
3715:     ISGetIndices(*clPoints, &cla);
3716:     np   = dof/2;
3717:     pts  = (PetscInt *) &cla[off];
3718:   }
3719:   *numPoints = np;
3720:   *points    = pts;
3721:   *clp       = cla;

3723:   return(0);
3724: }

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

3733:   if (!*clPoints) {
3734:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3735:   } else {
3736:     ISRestoreIndices(*clPoints, clp);
3737:   }
3738:   *numPoints = 0;
3739:   *points    = NULL;
3740:   *clSec     = NULL;
3741:   *clPoints  = NULL;
3742:   *clp       = NULL;
3743:   return(0);
3744: }

3748: 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[])
3749: {
3750:   PetscInt          offset = 0, p;
3751:   const PetscInt    **perms = NULL;
3752:   const PetscScalar **flips = NULL;
3753:   PetscErrorCode    ierr;

3756:   *size = 0;
3757:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3758:   for (p = 0; p < numPoints; p++) {
3759:     const PetscInt    point = points[2*p];
3760:     const PetscInt    *perm = perms ? perms[p] : NULL;
3761:     const PetscScalar *flip = flips ? flips[p] : NULL;
3762:     PetscInt          dof, off, d;
3763:     const PetscScalar *varr;

3765:     PetscSectionGetDof(section, point, &dof);
3766:     PetscSectionGetOffset(section, point, &off);
3767:     varr = &vArray[off];
3768:     if (clperm) {
3769:       if (perm) {
3770:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3771:       } else {
3772:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3773:       }
3774:       if (flip) {
3775:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3776:       }
3777:     } else {
3778:       if (perm) {
3779:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3780:       } else {
3781:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3782:       }
3783:       if (flip) {
3784:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3785:       }
3786:     }
3787:     offset += dof;
3788:   }
3789:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3790:   *size = offset;
3791:   return(0);
3792: }

3796: 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[])
3797: {
3798:   PetscInt          offset = 0, f;
3799:   PetscErrorCode    ierr;

3802:   *size = 0;
3803:   for (f = 0; f < numFields; ++f) {
3804:     PetscInt          p;
3805:     const PetscInt    **perms = NULL;
3806:     const PetscScalar **flips = NULL;

3808:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3809:     for (p = 0; p < numPoints; p++) {
3810:       const PetscInt    point = points[2*p];
3811:       PetscInt          fdof, foff, b;
3812:       const PetscScalar *varr;
3813:       const PetscInt    *perm = perms ? perms[p] : NULL;
3814:       const PetscScalar *flip = flips ? flips[p] : NULL;

3816:       PetscSectionGetFieldDof(section, point, f, &fdof);
3817:       PetscSectionGetFieldOffset(section, point, f, &foff);
3818:       varr = &vArray[foff];
3819:       if (clperm) {
3820:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
3821:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
3822:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
3823:       } else {
3824:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
3825:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
3826:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
3827:       }
3828:       offset += fdof;
3829:     }
3830:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3831:   }
3832:   *size = offset;
3833:   return(0);
3834: }

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

3841:   Not collective

3843:   Input Parameters:
3844: + dm - The DM
3845: . section - The section describing the layout in v, or NULL to use the default section
3846: . v - The local vector
3847: - point - The sieve point in the DM

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

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

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

3859:   Level: intermediate

3861: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3862: @*/
3863: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3864: {
3865:   PetscSection    clSection;
3866:   IS              clPoints;
3867:   PetscScalar    *array, *vArray;
3868:   PetscInt       *points = NULL;
3869:   const PetscInt *clp, *perm;
3870:   PetscInt        depth, numFields, numPoints, size;
3871:   PetscErrorCode  ierr;

3875:   if (!section) {DMGetDefaultSection(dm, &section);}
3878:   DMPlexGetDepth(dm, &depth);
3879:   PetscSectionGetNumFields(section, &numFields);
3880:   if (depth == 1 && numFields < 2) {
3881:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
3882:     return(0);
3883:   }
3884:   /* Get points */
3885:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3886:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
3887:   /* Get array */
3888:   if (!values || !*values) {
3889:     PetscInt asize = 0, dof, p;

3891:     for (p = 0; p < numPoints*2; p += 2) {
3892:       PetscSectionGetDof(section, points[p], &dof);
3893:       asize += dof;
3894:     }
3895:     if (!values) {
3896:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3897:       if (csize) *csize = asize;
3898:       return(0);
3899:     }
3900:     DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
3901:   } else {
3902:     array = *values;
3903:   }
3904:   VecGetArray(v, &vArray);
3905:   /* Get values */
3906:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
3907:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
3908:   /* Cleanup points */
3909:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3910:   /* Cleanup array */
3911:   VecRestoreArray(v, &vArray);
3912:   if (!*values) {
3913:     if (csize) *csize = size;
3914:     *values = array;
3915:   } else {
3916:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3917:     *csize = size;
3918:   }
3919:   return(0);
3920: }

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

3927:   Not collective

3929:   Input Parameters:
3930: + dm - The DM
3931: . section - The section describing the layout in v, or NULL to use the default section
3932: . v - The local vector
3933: . point - The sieve point in the DM
3934: . csize - The number of values in the closure, or NULL
3935: - values - The array of values, which is a borrowed array and should not be freed

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

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

3943:   Level: intermediate

3945: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3946: @*/
3947: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3948: {
3949:   PetscInt       size = 0;

3953:   /* Should work without recalculating size */
3954:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
3955:   return(0);
3956: }

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

3963: 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[])
3964: {
3965:   PetscInt        cdof;   /* The number of constraints on this point */
3966:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3967:   PetscScalar    *a;
3968:   PetscInt        off, cind = 0, k;
3969:   PetscErrorCode  ierr;

3972:   PetscSectionGetConstraintDof(section, point, &cdof);
3973:   PetscSectionGetOffset(section, point, &off);
3974:   a    = &array[off];
3975:   if (!cdof || setBC) {
3976:     if (clperm) {
3977:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
3978:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
3979:     } else {
3980:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
3981:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
3982:     }
3983:   } else {
3984:     PetscSectionGetConstraintIndices(section, point, &cdofs);
3985:     if (clperm) {
3986:       if (perm) {for (k = 0; k < dof; ++k) {
3987:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3988:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
3989:         }
3990:       } else {
3991:         for (k = 0; k < dof; ++k) {
3992:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3993:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
3994:         }
3995:       }
3996:     } else {
3997:       if (perm) {
3998:         for (k = 0; k < dof; ++k) {
3999:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4000:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4001:         }
4002:       } else {
4003:         for (k = 0; k < dof; ++k) {
4004:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4005:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4006:         }
4007:       }
4008:     }
4009:   }
4010:   return(0);
4011: }

4015: 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[])
4016: {
4017:   PetscInt        cdof;   /* The number of constraints on this point */
4018:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4019:   PetscScalar    *a;
4020:   PetscInt        off, cind = 0, k;
4021:   PetscErrorCode  ierr;

4024:   PetscSectionGetConstraintDof(section, point, &cdof);
4025:   PetscSectionGetOffset(section, point, &off);
4026:   a    = &array[off];
4027:   if (cdof) {
4028:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4029:     if (clperm) {
4030:       if (perm) {
4031:         for (k = 0; k < dof; ++k) {
4032:           if ((cind < cdof) && (k == cdofs[cind])) {
4033:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4034:             cind++;
4035:           }
4036:         }
4037:       } else {
4038:         for (k = 0; k < dof; ++k) {
4039:           if ((cind < cdof) && (k == cdofs[cind])) {
4040:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4041:             cind++;
4042:           }
4043:         }
4044:       }
4045:     } else {
4046:       if (perm) {
4047:         for (k = 0; k < dof; ++k) {
4048:           if ((cind < cdof) && (k == cdofs[cind])) {
4049:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4050:             cind++;
4051:           }
4052:         }
4053:       } else {
4054:         for (k = 0; k < dof; ++k) {
4055:           if ((cind < cdof) && (k == cdofs[cind])) {
4056:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4057:             cind++;
4058:           }
4059:         }
4060:       }
4061:     }
4062:   }
4063:   return(0);
4064: }

4068: 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[])
4069: {
4070:   PetscScalar    *a;
4071:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4072:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4073:   PetscInt        cind = 0, b;
4074:   PetscErrorCode  ierr;

4077:   PetscSectionGetFieldDof(section, point, f, &fdof);
4078:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4079:   PetscSectionGetFieldOffset(section, point, f, &foff);
4080:   a    = &array[foff];
4081:   if (!fcdof || setBC) {
4082:     if (clperm) {
4083:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4084:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4085:     } else {
4086:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4087:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4088:     }
4089:   } else {
4090:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4091:     if (clperm) {
4092:       if (perm) {
4093:         for (b = 0; b < fdof; b++) {
4094:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4095:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4096:         }
4097:       } else {
4098:         for (b = 0; b < fdof; b++) {
4099:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4100:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4101:         }
4102:       }
4103:     } else {
4104:       if (perm) {
4105:         for (b = 0; b < fdof; b++) {
4106:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4107:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4108:         }
4109:       } else {
4110:         for (b = 0; b < fdof; b++) {
4111:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4112:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4113:         }
4114:       }
4115:     }
4116:   }
4117:   *offset += fdof;
4118:   return(0);
4119: }

4123: 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[])
4124: {
4125:   PetscScalar    *a;
4126:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4127:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4128:   PetscInt        cind = 0, b;
4129:   PetscErrorCode  ierr;

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

4178: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4179: {
4180:   PetscScalar    *array;
4181:   const PetscInt *cone, *coneO;
4182:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4183:   PetscErrorCode  ierr;

4186:   PetscSectionGetChart(section, &pStart, &pEnd);
4187:   DMPlexGetConeSize(dm, point, &numPoints);
4188:   DMPlexGetCone(dm, point, &cone);
4189:   DMPlexGetConeOrientation(dm, point, &coneO);
4190:   VecGetArray(v, &array);
4191:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4192:     const PetscInt cp = !p ? point : cone[p-1];
4193:     const PetscInt o  = !p ? 0     : coneO[p-1];

4195:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4196:     PetscSectionGetDof(section, cp, &dof);
4197:     /* ADD_VALUES */
4198:     {
4199:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4200:       PetscScalar    *a;
4201:       PetscInt        cdof, coff, cind = 0, k;

4203:       PetscSectionGetConstraintDof(section, cp, &cdof);
4204:       PetscSectionGetOffset(section, cp, &coff);
4205:       a    = &array[coff];
4206:       if (!cdof) {
4207:         if (o >= 0) {
4208:           for (k = 0; k < dof; ++k) {
4209:             a[k] += values[off+k];
4210:           }
4211:         } else {
4212:           for (k = 0; k < dof; ++k) {
4213:             a[k] += values[off+dof-k-1];
4214:           }
4215:         }
4216:       } else {
4217:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4218:         if (o >= 0) {
4219:           for (k = 0; k < dof; ++k) {
4220:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4221:             a[k] += values[off+k];
4222:           }
4223:         } else {
4224:           for (k = 0; k < dof; ++k) {
4225:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4226:             a[k] += values[off+dof-k-1];
4227:           }
4228:         }
4229:       }
4230:     }
4231:   }
4232:   VecRestoreArray(v, &array);
4233:   return(0);
4234: }

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

4241:   Not collective

4243:   Input Parameters:
4244: + dm - The DM
4245: . section - The section describing the layout in v, or NULL to use the default section
4246: . v - The local vector
4247: . point - The sieve point in the DM
4248: . values - The array of values
4249: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

4254:   Level: intermediate

4256: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4257: @*/
4258: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4259: {
4260:   PetscSection    clSection;
4261:   IS              clPoints;
4262:   PetscScalar    *array;
4263:   PetscInt       *points = NULL;
4264:   const PetscInt *clp, *clperm;
4265:   PetscInt        depth, numFields, numPoints, p;
4266:   PetscErrorCode  ierr;

4270:   if (!section) {DMGetDefaultSection(dm, &section);}
4273:   DMPlexGetDepth(dm, &depth);
4274:   PetscSectionGetNumFields(section, &numFields);
4275:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4276:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4277:     return(0);
4278:   }
4279:   /* Get points */
4280:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4281:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4282:   /* Get array */
4283:   VecGetArray(v, &array);
4284:   /* Get values */
4285:   if (numFields > 0) {
4286:     PetscInt offset = 0, f;
4287:     for (f = 0; f < numFields; ++f) {
4288:       const PetscInt    **perms = NULL;
4289:       const PetscScalar **flips = NULL;

4291:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4292:       switch (mode) {
4293:       case INSERT_VALUES:
4294:         for (p = 0; p < numPoints; p++) {
4295:           const PetscInt    point = points[2*p];
4296:           const PetscInt    *perm = perms ? perms[p] : NULL;
4297:           const PetscScalar *flip = flips ? flips[p] : NULL;
4298:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4299:         } break;
4300:       case INSERT_ALL_VALUES:
4301:         for (p = 0; p < numPoints; p++) {
4302:           const PetscInt    point = points[2*p];
4303:           const PetscInt    *perm = perms ? perms[p] : NULL;
4304:           const PetscScalar *flip = flips ? flips[p] : NULL;
4305:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4306:         } break;
4307:       case INSERT_BC_VALUES:
4308:         for (p = 0; p < numPoints; p++) {
4309:           const PetscInt    point = points[2*p];
4310:           const PetscInt    *perm = perms ? perms[p] : NULL;
4311:           const PetscScalar *flip = flips ? flips[p] : NULL;
4312:           updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4313:         } break;
4314:       case ADD_VALUES:
4315:         for (p = 0; p < numPoints; p++) {
4316:           const PetscInt    point = points[2*p];
4317:           const PetscInt    *perm = perms ? perms[p] : NULL;
4318:           const PetscScalar *flip = flips ? flips[p] : NULL;
4319:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4320:         } break;
4321:       case ADD_ALL_VALUES:
4322:         for (p = 0; p < numPoints; p++) {
4323:           const PetscInt    point = points[2*p];
4324:           const PetscInt    *perm = perms ? perms[p] : NULL;
4325:           const PetscScalar *flip = flips ? flips[p] : NULL;
4326:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4327:         } break;
4328:       case ADD_BC_VALUES:
4329:         for (p = 0; p < numPoints; p++) {
4330:           const PetscInt    point = points[2*p];
4331:           const PetscInt    *perm = perms ? perms[p] : NULL;
4332:           const PetscScalar *flip = flips ? flips[p] : NULL;
4333:           updatePointFieldsBC_private(section, point, perm, flip, f, add, clperm, values, &offset, array);
4334:         } break;
4335:       default:
4336:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4337:       }
4338:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4339:     }
4340:   } else {
4341:     PetscInt dof, off;
4342:     const PetscInt    **perms = NULL;
4343:     const PetscScalar **flips = NULL;

4345:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4346:     switch (mode) {
4347:     case INSERT_VALUES:
4348:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4349:         const PetscInt    point = points[2*p];
4350:         const PetscInt    *perm = perms ? perms[p] : NULL;
4351:         const PetscScalar *flip = flips ? flips[p] : NULL;
4352:         PetscSectionGetDof(section, point, &dof);
4353:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4354:       } break;
4355:     case INSERT_ALL_VALUES:
4356:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4357:         const PetscInt    point = points[2*p];
4358:         const PetscInt    *perm = perms ? perms[p] : NULL;
4359:         const PetscScalar *flip = flips ? flips[p] : NULL;
4360:         PetscSectionGetDof(section, point, &dof);
4361:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4362:       } break;
4363:     case INSERT_BC_VALUES:
4364:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4365:         const PetscInt    point = points[2*p];
4366:         const PetscInt    *perm = perms ? perms[p] : NULL;
4367:         const PetscScalar *flip = flips ? flips[p] : NULL;
4368:         PetscSectionGetDof(section, point, &dof);
4369:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4370:       } break;
4371:     case ADD_VALUES:
4372:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4373:         const PetscInt    point = points[2*p];
4374:         const PetscInt    *perm = perms ? perms[p] : NULL;
4375:         const PetscScalar *flip = flips ? flips[p] : NULL;
4376:         PetscSectionGetDof(section, point, &dof);
4377:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4378:       } break;
4379:     case ADD_ALL_VALUES:
4380:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4381:         const PetscInt    point = points[2*p];
4382:         const PetscInt    *perm = perms ? perms[p] : NULL;
4383:         const PetscScalar *flip = flips ? flips[p] : NULL;
4384:         PetscSectionGetDof(section, point, &dof);
4385:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4386:       } break;
4387:     case ADD_BC_VALUES:
4388:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4389:         const PetscInt    point = points[2*p];
4390:         const PetscInt    *perm = perms ? perms[p] : NULL;
4391:         const PetscScalar *flip = flips ? flips[p] : NULL;
4392:         PetscSectionGetDof(section, point, &dof);
4393:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4394:       } break;
4395:     default:
4396:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4397:     }
4398:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4399:   }
4400:   /* Cleanup points */
4401:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4402:   /* Cleanup array */
4403:   VecRestoreArray(v, &array);
4404:   return(0);
4405: }

4409: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4410: {
4411:   PetscSection      clSection;
4412:   IS                clPoints;
4413:   PetscScalar       *array;
4414:   PetscInt          *points = NULL;
4415:   const PetscInt    *clp, *clperm;
4416:   PetscInt          numFields, numPoints, p;
4417:   PetscInt          offset = 0, f;
4418:   PetscErrorCode    ierr;

4422:   if (!section) {DMGetDefaultSection(dm, &section);}
4425:   PetscSectionGetNumFields(section, &numFields);
4426:   /* Get points */
4427:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4428:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4429:   /* Get array */
4430:   VecGetArray(v, &array);
4431:   /* Get values */
4432:   for (f = 0; f < numFields; ++f) {
4433:     const PetscInt    **perms = NULL;
4434:     const PetscScalar **flips = NULL;

4436:     if (!fieldActive[f]) {
4437:       for (p = 0; p < numPoints*2; p += 2) {
4438:         PetscInt fdof;
4439:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4440:         offset += fdof;
4441:       }
4442:       continue;
4443:     }
4444:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4445:     switch (mode) {
4446:     case INSERT_VALUES:
4447:       for (p = 0; p < numPoints; p++) {
4448:         const PetscInt    point = points[2*p];
4449:         const PetscInt    *perm = perms ? perms[p] : NULL;
4450:         const PetscScalar *flip = flips ? flips[p] : NULL;
4451:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4452:       } break;
4453:     case INSERT_ALL_VALUES:
4454:       for (p = 0; p < numPoints; p++) {
4455:         const PetscInt    point = points[2*p];
4456:         const PetscInt    *perm = perms ? perms[p] : NULL;
4457:         const PetscScalar *flip = flips ? flips[p] : NULL;
4458:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4459:         } break;
4460:     case INSERT_BC_VALUES:
4461:       for (p = 0; p < numPoints; p++) {
4462:         const PetscInt    point = points[2*p];
4463:         const PetscInt    *perm = perms ? perms[p] : NULL;
4464:         const PetscScalar *flip = flips ? flips[p] : NULL;
4465:         updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4466:       } break;
4467:     case ADD_VALUES:
4468:       for (p = 0; p < numPoints; p++) {
4469:         const PetscInt    point = points[2*p];
4470:         const PetscInt    *perm = perms ? perms[p] : NULL;
4471:         const PetscScalar *flip = flips ? flips[p] : NULL;
4472:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4473:       } break;
4474:     case ADD_ALL_VALUES:
4475:       for (p = 0; p < numPoints; p++) {
4476:         const PetscInt    point = points[2*p];
4477:         const PetscInt    *perm = perms ? perms[p] : NULL;
4478:         const PetscScalar *flip = flips ? flips[p] : NULL;
4479:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4480:       } break;
4481:     default:
4482:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4483:     }
4484:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4485:   }
4486:   /* Cleanup points */
4487:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4488:   /* Cleanup array */
4489:   VecRestoreArray(v, &array);
4490:   return(0);
4491: }

4495: PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4496: {
4497:   PetscMPIInt    rank;
4498:   PetscInt       i, j;

4502:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4503:   PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);
4504:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4505:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4506:   numCIndices = numCIndices ? numCIndices : numRIndices;
4507:   for (i = 0; i < numRIndices; i++) {
4508:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4509:     for (j = 0; j < numCIndices; j++) {
4510: #if defined(PETSC_USE_COMPLEX)
4511:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4512: #else
4513:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4514: #endif
4515:     }
4516:     PetscViewerASCIIPrintf(viewer, "\n");
4517:   }
4518:   return(0);
4519: }

4523: /* . off - The global offset of this point */
4524: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4525: {
4526:   PetscInt        dof;    /* The number of unknowns on this point */
4527:   PetscInt        cdof;   /* The number of constraints on this point */
4528:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4529:   PetscInt        cind = 0, k;
4530:   PetscErrorCode  ierr;

4533:   PetscSectionGetDof(section, point, &dof);
4534:   PetscSectionGetConstraintDof(section, point, &cdof);
4535:   if (!cdof || setBC) {
4536:     if (perm) {
4537:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4538:     } else {
4539:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4540:     }
4541:   } else {
4542:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4543:     if (perm) {
4544:       for (k = 0; k < dof; ++k) {
4545:         if ((cind < cdof) && (k == cdofs[cind])) {
4546:           /* Insert check for returning constrained indices */
4547:           indices[*loff+perm[k]] = -(off+k+1);
4548:           ++cind;
4549:         } else {
4550:           indices[*loff+perm[k]] = off+k-cind;
4551:         }
4552:       }
4553:     } else {
4554:       for (k = 0; k < dof; ++k) {
4555:         if ((cind < cdof) && (k == cdofs[cind])) {
4556:           /* Insert check for returning constrained indices */
4557:           indices[*loff+k] = -(off+k+1);
4558:           ++cind;
4559:         } else {
4560:           indices[*loff+k] = off+k-cind;
4561:         }
4562:       }
4563:     }
4564:   }
4565:   *loff += dof;
4566:   return(0);
4567: }

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

4578:   PetscSectionGetNumFields(section, &numFields);
4579:   for (f = 0, foff = 0; f < numFields; ++f) {
4580:     PetscInt        fdof, cfdof;
4581:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4582:     PetscInt        cind = 0, b;
4583:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4585:     PetscSectionGetFieldDof(section, point, f, &fdof);
4586:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4587:     if (!cfdof || setBC) {
4588:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4589:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4590:     } else {
4591:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4592:       if (perm) {
4593:         for (b = 0; b < fdof; b++) {
4594:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4595:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4596:             ++cind;
4597:           } else {
4598:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4599:           }
4600:         }
4601:       } else {
4602:         for (b = 0; b < fdof; b++) {
4603:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4604:             indices[foffs[f]+b] = -(off+foff+b+1);
4605:             ++cind;
4606:           } else {
4607:             indices[foffs[f]+b] = off+foff+b-cind;
4608:           }
4609:         }
4610:       }
4611:     }
4612:     foff     += (setBC ? fdof : (fdof - cfdof));
4613:     foffs[f] += fdof;
4614:   }
4615:   return(0);
4616: }

4620: 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)
4621: {
4622:   Mat             cMat;
4623:   PetscSection    aSec, cSec;
4624:   IS              aIS;
4625:   PetscInt        aStart = -1, aEnd = -1;
4626:   const PetscInt  *anchors;
4627:   PetscInt        numFields, f, p, q, newP = 0;
4628:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4629:   PetscInt        *newPoints, *indices, *newIndices;
4630:   PetscInt        maxAnchor, maxDof;
4631:   PetscInt        newOffsets[32];
4632:   PetscInt        *pointMatOffsets[32];
4633:   PetscInt        *newPointOffsets[32];
4634:   PetscScalar     *pointMat[32];
4635:   PetscScalar     *newValues=NULL,*tmpValues;
4636:   PetscBool       anyConstrained = PETSC_FALSE;
4637:   PetscErrorCode  ierr;

4642:   PetscSectionGetNumFields(section, &numFields);

4644:   DMPlexGetAnchors(dm,&aSec,&aIS);
4645:   /* if there are point-to-point constraints */
4646:   if (aSec) {
4647:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4648:     ISGetIndices(aIS,&anchors);
4649:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4650:     /* figure out how many points are going to be in the new element matrix
4651:      * (we allow double counting, because it's all just going to be summed
4652:      * into the global matrix anyway) */
4653:     for (p = 0; p < 2*numPoints; p+=2) {
4654:       PetscInt b    = points[p];
4655:       PetscInt bDof = 0, bSecDof;

4657:       PetscSectionGetDof(section,b,&bSecDof);
4658:       if (!bSecDof) {
4659:         continue;
4660:       }
4661:       if (b >= aStart && b < aEnd) {
4662:         PetscSectionGetDof(aSec,b,&bDof);
4663:       }
4664:       if (bDof) {
4665:         /* this point is constrained */
4666:         /* it is going to be replaced by its anchors */
4667:         PetscInt bOff, q;

4669:         anyConstrained = PETSC_TRUE;
4670:         newNumPoints  += bDof;
4671:         PetscSectionGetOffset(aSec,b,&bOff);
4672:         for (q = 0; q < bDof; q++) {
4673:           PetscInt a = anchors[bOff + q];
4674:           PetscInt aDof;

4676:           PetscSectionGetDof(section,a,&aDof);
4677:           newNumIndices += aDof;
4678:           for (f = 0; f < numFields; ++f) {
4679:             PetscInt fDof;

4681:             PetscSectionGetFieldDof(section, a, f, &fDof);
4682:             newOffsets[f+1] += fDof;
4683:           }
4684:         }
4685:       }
4686:       else {
4687:         /* this point is not constrained */
4688:         newNumPoints++;
4689:         newNumIndices += bSecDof;
4690:         for (f = 0; f < numFields; ++f) {
4691:           PetscInt fDof;

4693:           PetscSectionGetFieldDof(section, b, f, &fDof);
4694:           newOffsets[f+1] += fDof;
4695:         }
4696:       }
4697:     }
4698:   }
4699:   if (!anyConstrained) {
4700:     if (outNumPoints)  *outNumPoints  = 0;
4701:     if (outNumIndices) *outNumIndices = 0;
4702:     if (outPoints)     *outPoints     = NULL;
4703:     if (outValues)     *outValues     = NULL;
4704:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4705:     return(0);
4706:   }

4708:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4709:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4713:   if (!outPoints && !outValues) {
4714:     if (offsets) {
4715:       for (f = 0; f <= numFields; f++) {
4716:         offsets[f] = newOffsets[f];
4717:       }
4718:     }
4719:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4720:     return(0);
4721:   }

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

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

4727:   /* workspaces */
4728:   if (numFields) {
4729:     for (f = 0; f < numFields; f++) {
4730:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4731:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4732:     }
4733:   }
4734:   else {
4735:     DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4736:     DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
4737:   }

4739:   /* get workspaces for the point-to-point matrices */
4740:   if (numFields) {
4741:     PetscInt totalOffset, totalMatOffset;

4743:     for (p = 0; p < numPoints; p++) {
4744:       PetscInt b    = points[2*p];
4745:       PetscInt bDof = 0, bSecDof;

4747:       PetscSectionGetDof(section,b,&bSecDof);
4748:       if (!bSecDof) {
4749:         for (f = 0; f < numFields; f++) {
4750:           newPointOffsets[f][p + 1] = 0;
4751:           pointMatOffsets[f][p + 1] = 0;
4752:         }
4753:         continue;
4754:       }
4755:       if (b >= aStart && b < aEnd) {
4756:         PetscSectionGetDof(aSec, b, &bDof);
4757:       }
4758:       if (bDof) {
4759:         for (f = 0; f < numFields; f++) {
4760:           PetscInt fDof, q, bOff, allFDof = 0;

4762:           PetscSectionGetFieldDof(section, b, f, &fDof);
4763:           PetscSectionGetOffset(aSec, b, &bOff);
4764:           for (q = 0; q < bDof; q++) {
4765:             PetscInt a = anchors[bOff + q];
4766:             PetscInt aFDof;

4768:             PetscSectionGetFieldDof(section, a, f, &aFDof);
4769:             allFDof += aFDof;
4770:           }
4771:           newPointOffsets[f][p+1] = allFDof;
4772:           pointMatOffsets[f][p+1] = fDof * allFDof;
4773:         }
4774:       }
4775:       else {
4776:         for (f = 0; f < numFields; f++) {
4777:           PetscInt fDof;

4779:           PetscSectionGetFieldDof(section, b, f, &fDof);
4780:           newPointOffsets[f][p+1] = fDof;
4781:           pointMatOffsets[f][p+1] = 0;
4782:         }
4783:       }
4784:     }
4785:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4786:       newPointOffsets[f][0] = totalOffset;
4787:       pointMatOffsets[f][0] = totalMatOffset;
4788:       for (p = 0; p < numPoints; p++) {
4789:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4790:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4791:       }
4792:       totalOffset    = newPointOffsets[f][numPoints];
4793:       totalMatOffset = pointMatOffsets[f][numPoints];
4794:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4795:     }
4796:   }
4797:   else {
4798:     for (p = 0; p < numPoints; p++) {
4799:       PetscInt b    = points[2*p];
4800:       PetscInt bDof = 0, bSecDof;

4802:       PetscSectionGetDof(section,b,&bSecDof);
4803:       if (!bSecDof) {
4804:         newPointOffsets[0][p + 1] = 0;
4805:         pointMatOffsets[0][p + 1] = 0;
4806:         continue;
4807:       }
4808:       if (b >= aStart && b < aEnd) {
4809:         PetscSectionGetDof(aSec, b, &bDof);
4810:       }
4811:       if (bDof) {
4812:         PetscInt bOff, q, allDof = 0;

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

4818:           PetscSectionGetDof(section, a, &aDof);
4819:           allDof += aDof;
4820:         }
4821:         newPointOffsets[0][p+1] = allDof;
4822:         pointMatOffsets[0][p+1] = bSecDof * allDof;
4823:       }
4824:       else {
4825:         newPointOffsets[0][p+1] = bSecDof;
4826:         pointMatOffsets[0][p+1] = 0;
4827:       }
4828:     }
4829:     newPointOffsets[0][0] = 0;
4830:     pointMatOffsets[0][0] = 0;
4831:     for (p = 0; p < numPoints; p++) {
4832:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4833:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4834:     }
4835:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4836:   }

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

4841:   /* get the point-to-point matrices; construct newPoints */
4842:   PetscSectionGetMaxDof(aSec, &maxAnchor);
4843:   PetscSectionGetMaxDof(section, &maxDof);
4844:   DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
4845:   DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
4846:   if (numFields) {
4847:     for (p = 0, newP = 0; p < numPoints; p++) {
4848:       PetscInt b    = points[2*p];
4849:       PetscInt o    = points[2*p+1];
4850:       PetscInt bDof = 0, bSecDof;

4852:       PetscSectionGetDof(section, b, &bSecDof);
4853:       if (!bSecDof) {
4854:         continue;
4855:       }
4856:       if (b >= aStart && b < aEnd) {
4857:         PetscSectionGetDof(aSec, b, &bDof);
4858:       }
4859:       if (bDof) {
4860:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

4862:         fStart[0] = 0;
4863:         fEnd[0]   = 0;
4864:         for (f = 0; f < numFields; f++) {
4865:           PetscInt fDof;

4867:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
4868:           fStart[f+1] = fStart[f] + fDof;
4869:           fEnd[f+1]   = fStart[f+1];
4870:         }
4871:         PetscSectionGetOffset(cSec, b, &bOff);
4872:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

4874:         fAnchorStart[0] = 0;
4875:         fAnchorEnd[0]   = 0;
4876:         for (f = 0; f < numFields; f++) {
4877:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

4879:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4880:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4881:         }
4882:         PetscSectionGetOffset(aSec, b, &bOff);
4883:         for (q = 0; q < bDof; q++) {
4884:           PetscInt a = anchors[bOff + q], aOff;

4886:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4887:           newPoints[2*(newP + q)]     = a;
4888:           newPoints[2*(newP + q) + 1] = 0;
4889:           PetscSectionGetOffset(section, a, &aOff);
4890:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
4891:         }
4892:         newP += bDof;

4894:         if (outValues) {
4895:           /* get the point-to-point submatrix */
4896:           for (f = 0; f < numFields; f++) {
4897:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
4898:           }
4899:         }
4900:       }
4901:       else {
4902:         newPoints[2 * newP]     = b;
4903:         newPoints[2 * newP + 1] = o;
4904:         newP++;
4905:       }
4906:     }
4907:   } else {
4908:     for (p = 0; p < numPoints; p++) {
4909:       PetscInt b    = points[2*p];
4910:       PetscInt o    = points[2*p+1];
4911:       PetscInt bDof = 0, bSecDof;

4913:       PetscSectionGetDof(section, b, &bSecDof);
4914:       if (!bSecDof) {
4915:         continue;
4916:       }
4917:       if (b >= aStart && b < aEnd) {
4918:         PetscSectionGetDof(aSec, b, &bDof);
4919:       }
4920:       if (bDof) {
4921:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

4932:           newPoints[2*(newP + q)]     = a;
4933:           newPoints[2*(newP + q) + 1] = 0;
4934:           PetscSectionGetOffset(section, a, &aOff);
4935:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
4936:         }
4937:         newP += bDof;

4939:         /* get the point-to-point submatrix */
4940:         if (outValues) {
4941:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
4942:         }
4943:       }
4944:       else {
4945:         newPoints[2 * newP]     = b;
4946:         newPoints[2 * newP + 1] = o;
4947:         newP++;
4948:       }
4949:     }
4950:   }

4952:   if (outValues) {
4953:     DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
4954:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
4955:     /* multiply constraints on the right */
4956:     if (numFields) {
4957:       for (f = 0; f < numFields; f++) {
4958:         PetscInt oldOff = offsets[f];

4960:         for (p = 0; p < numPoints; p++) {
4961:           PetscInt cStart = newPointOffsets[f][p];
4962:           PetscInt b      = points[2 * p];
4963:           PetscInt c, r, k;
4964:           PetscInt dof;

4966:           PetscSectionGetFieldDof(section,b,f,&dof);
4967:           if (!dof) {
4968:             continue;
4969:           }
4970:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4971:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
4972:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

4974:             for (r = 0; r < numIndices; r++) {
4975:               for (c = 0; c < nCols; c++) {
4976:                 for (k = 0; k < dof; k++) {
4977:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
4978:                 }
4979:               }
4980:             }
4981:           }
4982:           else {
4983:             /* copy this column as is */
4984:             for (r = 0; r < numIndices; r++) {
4985:               for (c = 0; c < dof; c++) {
4986:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4987:               }
4988:             }
4989:           }
4990:           oldOff += dof;
4991:         }
4992:       }
4993:     }
4994:     else {
4995:       PetscInt oldOff = 0;
4996:       for (p = 0; p < numPoints; p++) {
4997:         PetscInt cStart = newPointOffsets[0][p];
4998:         PetscInt b      = points[2 * p];
4999:         PetscInt c, r, k;
5000:         PetscInt dof;

5002:         PetscSectionGetDof(section,b,&dof);
5003:         if (!dof) {
5004:           continue;
5005:         }
5006:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5007:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5008:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5010:           for (r = 0; r < numIndices; r++) {
5011:             for (c = 0; c < nCols; c++) {
5012:               for (k = 0; k < dof; k++) {
5013:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5014:               }
5015:             }
5016:           }
5017:         }
5018:         else {
5019:           /* copy this column as is */
5020:           for (r = 0; r < numIndices; r++) {
5021:             for (c = 0; c < dof; c++) {
5022:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5023:             }
5024:           }
5025:         }
5026:         oldOff += dof;
5027:       }
5028:     }

5030:     if (multiplyLeft) {
5031:       DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5032:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5033:       /* multiply constraints transpose on the left */
5034:       if (numFields) {
5035:         for (f = 0; f < numFields; f++) {
5036:           PetscInt oldOff = offsets[f];

5038:           for (p = 0; p < numPoints; p++) {
5039:             PetscInt rStart = newPointOffsets[f][p];
5040:             PetscInt b      = points[2 * p];
5041:             PetscInt c, r, k;
5042:             PetscInt dof;

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

5049:               for (r = 0; r < nRows; r++) {
5050:                 for (c = 0; c < newNumIndices; c++) {
5051:                   for (k = 0; k < dof; k++) {
5052:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5053:                   }
5054:                 }
5055:               }
5056:             }
5057:             else {
5058:               /* copy this row as is */
5059:               for (r = 0; r < dof; r++) {
5060:                 for (c = 0; c < newNumIndices; c++) {
5061:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5062:                 }
5063:               }
5064:             }
5065:             oldOff += dof;
5066:           }
5067:         }
5068:       }
5069:       else {
5070:         PetscInt oldOff = 0;

5072:         for (p = 0; p < numPoints; p++) {
5073:           PetscInt rStart = newPointOffsets[0][p];
5074:           PetscInt b      = points[2 * p];
5075:           PetscInt c, r, k;
5076:           PetscInt dof;

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

5083:             for (r = 0; r < nRows; r++) {
5084:               for (c = 0; c < newNumIndices; c++) {
5085:                 for (k = 0; k < dof; k++) {
5086:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5087:                 }
5088:               }
5089:             }
5090:           }
5091:           else {
5092:             /* copy this row as is */
5093:             for (r = 0; r < dof; r++) {
5094:               for (c = 0; c < newNumIndices; c++) {
5095:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5096:               }
5097:             }
5098:           }
5099:           oldOff += dof;
5100:         }
5101:       }

5103:       DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5104:     }
5105:     else {
5106:       newValues = tmpValues;
5107:     }
5108:   }

5110:   /* clean up */
5111:   DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
5112:   DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);

5114:   if (numFields) {
5115:     for (f = 0; f < numFields; f++) {
5116:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
5117:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
5118:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
5119:     }
5120:   }
5121:   else {
5122:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
5123:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
5124:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
5125:   }
5126:   ISRestoreIndices(aIS,&anchors);

5128:   /* output */
5129:   if (outPoints) {
5130:     *outPoints = newPoints;
5131:   }
5132:   else {
5133:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5134:   }
5135:   if (outValues) {
5136:     *outValues = newValues;
5137:   }
5138:   for (f = 0; f <= numFields; f++) {
5139:     offsets[f] = newOffsets[f];
5140:   }
5141:   return(0);
5142: }

5146: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5147: {
5148:   PetscSection    clSection;
5149:   IS              clPoints;
5150:   const PetscInt *clp;
5151:   const PetscInt  **perms[32] = {NULL};
5152:   PetscInt       *points = NULL, *pointsNew;
5153:   PetscInt        numPoints, numPointsNew;
5154:   PetscInt        offsets[32];
5155:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5156:   PetscErrorCode  ierr;

5164:   PetscSectionGetNumFields(section, &Nf);
5165:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5166:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5167:   /* Get points in closure */
5168:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5169:   /* Get number of indices and indices per field */
5170:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5171:     PetscInt dof, fdof;

5173:     PetscSectionGetDof(section, points[p], &dof);
5174:     for (f = 0; f < Nf; ++f) {
5175:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5176:       offsets[f+1] += fdof;
5177:     }
5178:     Nind += dof;
5179:   }
5180:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5181:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5182:   if (!Nf) offsets[1] = Nind;
5183:   /* Get dual space symmetries */
5184:   for (f = 0; f < PetscMax(1,Nf); f++) {
5185:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5186:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5187:   }
5188:   /* Correct for hanging node constraints */
5189:   {
5190:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5191:     if (numPointsNew) {
5192:       for (f = 0; f < PetscMax(1,Nf); f++) {
5193:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5194:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5195:       }
5196:       for (f = 0; f < PetscMax(1,Nf); f++) {
5197:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5198:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5199:       }
5200:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5201:       numPoints = numPointsNew;
5202:       Nind      = NindNew;
5203:       points    = pointsNew;
5204:     }
5205:   }
5206:   /* Calculate indices */
5207:   DMGetWorkArray(dm, Nind, PETSC_INT, indices);
5208:   if (Nf) {
5209:     if (outOffsets) {
5210:       PetscInt f;

5212:       for (f = 0; f <= Nf; f++) {
5213:         outOffsets[f] = offsets[f];
5214:       }
5215:     }
5216:     for (p = 0; p < numPoints; p++) {
5217:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5218:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5219:     }
5220:   } else {
5221:     for (p = 0, off = 0; p < numPoints; p++) {
5222:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5224:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5225:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5226:     }
5227:   }
5228:   /* Cleanup points */
5229:   for (f = 0; f < PetscMax(1,Nf); f++) {
5230:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5231:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5232:   }
5233:   if (numPointsNew) {
5234:     DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);
5235:   } else {
5236:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5237:   }
5238:   if (numIndices) *numIndices = Nind;
5239:   return(0);
5240: }

5244: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5245: {

5251:   DMRestoreWorkArray(dm, 0, PETSC_INT, indices);
5252:   return(0);
5253: }

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

5260:   Not collective

5262:   Input Parameters:
5263: + dm - The DM
5264: . section - The section describing the layout in v, or NULL to use the default section
5265: . globalSection - The section describing the layout in v, or NULL to use the default global section
5266: . A - The matrix
5267: . point - The sieve point in the DM
5268: . values - The array of values
5269: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5274:   Level: intermediate

5276: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5277: @*/
5278: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5279: {
5280:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5281:   PetscSection        clSection;
5282:   IS                  clPoints;
5283:   PetscInt           *points = NULL, *newPoints;
5284:   const PetscInt     *clp;
5285:   PetscInt           *indices;
5286:   PetscInt            offsets[32];
5287:   const PetscInt    **perms[32] = {NULL};
5288:   const PetscScalar **flips[32] = {NULL};
5289:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5290:   PetscScalar        *valCopy = NULL;
5291:   PetscScalar        *newValues;
5292:   PetscErrorCode      ierr;

5296:   if (!section) {DMGetDefaultSection(dm, &section);}
5298:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5301:   PetscSectionGetNumFields(section, &numFields);
5302:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5303:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5304:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5305:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5306:     PetscInt fdof;

5308:     PetscSectionGetDof(section, points[p], &dof);
5309:     for (f = 0; f < numFields; ++f) {
5310:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5311:       offsets[f+1] += fdof;
5312:     }
5313:     numIndices += dof;
5314:   }
5315:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5329:         if (!numFields) {
5330:           PetscSectionGetDof(section,point,&fdof);
5331:         } else {
5332:           PetscSectionGetFieldDof(section,point,f,&fdof);
5333:         }
5334:         if (flip) {
5335:           PetscInt i, j, k;

5337:           if (!valCopy) {
5338:             DMGetWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5339:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5340:             values = valCopy;
5341:           }
5342:           for (i = 0; i < fdof; i++) {
5343:             PetscScalar fval = flip[i];

5345:             for (k = 0; k < numIndices; k++) {
5346:               valCopy[numIndices * (foffset + i) + k] *= fval;
5347:               valCopy[numIndices * k + (foffset + i)] *= fval;
5348:             }
5349:           }
5350:         }
5351:         foffset += fdof;
5352:       }
5353:     }
5354:   }
5355:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5356:   if (newNumPoints) {
5357:     if (valCopy) {
5358:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5359:     }
5360:     for (f = 0; f < PetscMax(1,numFields); f++) {
5361:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5362:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5363:     }
5364:     for (f = 0; f < PetscMax(1,numFields); f++) {
5365:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5366:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5367:     }
5368:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5369:     numPoints  = newNumPoints;
5370:     numIndices = newNumIndices;
5371:     points     = newPoints;
5372:     values     = newValues;
5373:   }
5374:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5375:   if (numFields) {
5376:     for (p = 0; p < numPoints; p++) {
5377:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5378:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5379:     }
5380:   } else {
5381:     for (p = 0, off = 0; p < numPoints; p++) {
5382:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5383:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5384:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5385:     }
5386:   }
5387:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5388:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5389:   if (mesh->printFEM > 1) {
5390:     PetscInt i;
5391:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5392:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5393:     PetscPrintf(PETSC_COMM_SELF, "\n");
5394:   }
5395:   if (ierr) {
5396:     PetscMPIInt    rank;
5397:     PetscErrorCode ierr2;

5399:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5400:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5401:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5402:     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5403: 
5404:   }
5405:   for (f = 0; f < PetscMax(1,numFields); f++) {
5406:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5407:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5408:   }
5409:   if (newNumPoints) {
5410:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5411:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5412:   }
5413:   else {
5414:     if (valCopy) {
5415:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5416:     }
5417:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5418:   }
5419:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5420:   return(0);
5421: }

5425: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5426: {
5427:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5428:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5429:   PetscInt       *cpoints = NULL;
5430:   PetscInt       *findices, *cindices;
5431:   PetscInt        foffsets[32], coffsets[32];
5432:   CellRefiner     cellRefiner;
5433:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5434:   PetscErrorCode  ierr;

5439:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5441:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5443:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5445:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5448:   PetscSectionGetNumFields(fsection, &numFields);
5449:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5450:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5451:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5452:   /* Column indices */
5453:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5454:   maxFPoints = numCPoints;
5455:   /* Compress out points not in the section */
5456:   /*   TODO: Squeeze out points with 0 dof as well */
5457:   PetscSectionGetChart(csection, &pStart, &pEnd);
5458:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5459:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5460:       cpoints[q*2]   = cpoints[p];
5461:       cpoints[q*2+1] = cpoints[p+1];
5462:       ++q;
5463:     }
5464:   }
5465:   numCPoints = q;
5466:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5467:     PetscInt fdof;

5469:     PetscSectionGetDof(csection, cpoints[p], &dof);
5470:     if (!dof) continue;
5471:     for (f = 0; f < numFields; ++f) {
5472:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5473:       coffsets[f+1] += fdof;
5474:     }
5475:     numCIndices += dof;
5476:   }
5477:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5478:   /* Row indices */
5479:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5480:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5481:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5482:   for (r = 0, q = 0; r < numSubcells; ++r) {
5483:     /* TODO Map from coarse to fine cells */
5484:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5485:     /* Compress out points not in the section */
5486:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5487:     for (p = 0; p < numFPoints*2; p += 2) {
5488:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5489:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5490:         if (!dof) continue;
5491:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5492:         if (s < q) continue;
5493:         ftotpoints[q*2]   = fpoints[p];
5494:         ftotpoints[q*2+1] = fpoints[p+1];
5495:         ++q;
5496:       }
5497:     }
5498:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5499:   }
5500:   numFPoints = q;
5501:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5502:     PetscInt fdof;

5504:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5505:     if (!dof) continue;
5506:     for (f = 0; f < numFields; ++f) {
5507:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5508:       foffsets[f+1] += fdof;
5509:     }
5510:     numFIndices += dof;
5511:   }
5512:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5514:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5515:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5516:   DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5517:   DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5518:   if (numFields) {
5519:     const PetscInt **permsF[32] = {NULL};
5520:     const PetscInt **permsC[32] = {NULL};

5522:     for (f = 0; f < numFields; f++) {
5523:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5524:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5525:     }
5526:     for (p = 0; p < numFPoints; p++) {
5527:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5528:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5529:     }
5530:     for (p = 0; p < numCPoints; p++) {
5531:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5532:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5533:     }
5534:     for (f = 0; f < numFields; f++) {
5535:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5536:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5537:     }
5538:   } else {
5539:     const PetscInt **permsF = NULL;
5540:     const PetscInt **permsC = NULL;

5542:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5543:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5544:     for (p = 0, off = 0; p < numFPoints; p++) {
5545:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5547:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5548:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5549:     }
5550:     for (p = 0, off = 0; p < numCPoints; p++) {
5551:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5553:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5554:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5555:     }
5556:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5557:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5558:   }
5559:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5560:   /* TODO: flips */
5561:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5562:   if (ierr) {
5563:     PetscMPIInt    rank;
5564:     PetscErrorCode ierr2;

5566:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5567:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5568:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5569:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5570:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5571: 
5572:   }
5573:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5574:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5575:   DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5576:   DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5577:   return(0);
5578: }

5582: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5583: {
5584:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5585:   PetscInt      *cpoints = NULL;
5586:   PetscInt       foffsets[32], coffsets[32];
5587:   CellRefiner    cellRefiner;
5588:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

5594:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5596:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5598:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5600:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5602:   PetscSectionGetNumFields(fsection, &numFields);
5603:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5604:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5605:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5606:   /* Column indices */
5607:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5608:   maxFPoints = numCPoints;
5609:   /* Compress out points not in the section */
5610:   /*   TODO: Squeeze out points with 0 dof as well */
5611:   PetscSectionGetChart(csection, &pStart, &pEnd);
5612:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5613:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5614:       cpoints[q*2]   = cpoints[p];
5615:       cpoints[q*2+1] = cpoints[p+1];
5616:       ++q;
5617:     }
5618:   }
5619:   numCPoints = q;
5620:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5621:     PetscInt fdof;

5623:     PetscSectionGetDof(csection, cpoints[p], &dof);
5624:     if (!dof) continue;
5625:     for (f = 0; f < numFields; ++f) {
5626:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5627:       coffsets[f+1] += fdof;
5628:     }
5629:     numCIndices += dof;
5630:   }
5631:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5632:   /* Row indices */
5633:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5634:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5635:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5636:   for (r = 0, q = 0; r < numSubcells; ++r) {
5637:     /* TODO Map from coarse to fine cells */
5638:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5639:     /* Compress out points not in the section */
5640:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5641:     for (p = 0; p < numFPoints*2; p += 2) {
5642:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5643:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5644:         if (!dof) continue;
5645:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5646:         if (s < q) continue;
5647:         ftotpoints[q*2]   = fpoints[p];
5648:         ftotpoints[q*2+1] = fpoints[p+1];
5649:         ++q;
5650:       }
5651:     }
5652:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5653:   }
5654:   numFPoints = q;
5655:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5656:     PetscInt fdof;

5658:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5659:     if (!dof) continue;
5660:     for (f = 0; f < numFields; ++f) {
5661:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5662:       foffsets[f+1] += fdof;
5663:     }
5664:     numFIndices += dof;
5665:   }
5666:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

5674:     for (f = 0; f < numFields; f++) {
5675:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5676:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5677:     }
5678:     for (p = 0; p < numFPoints; p++) {
5679:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5680:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5681:     }
5682:     for (p = 0; p < numCPoints; p++) {
5683:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5684:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5685:     }
5686:     for (f = 0; f < numFields; f++) {
5687:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5688:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5689:     }
5690:   } else {
5691:     const PetscInt **permsF = NULL;
5692:     const PetscInt **permsC = NULL;

5694:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5695:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5696:     for (p = 0, off = 0; p < numFPoints; p++) {
5697:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5699:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5700:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5701:     }
5702:     for (p = 0, off = 0; p < numCPoints; p++) {
5703:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5705:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5706:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5707:     }
5708:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5709:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5710:   }
5711:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5712:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5713:   return(0);
5714: }

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

5721:   Input Parameter:
5722: . dm - The DMPlex object

5724:   Output Parameters:
5725: + cMax - The first hybrid cell
5726: . fMax - The first hybrid face
5727: . eMax - The first hybrid edge
5728: - vMax - The first hybrid vertex

5730:   Level: developer

5732: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5733: @*/
5734: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5735: {
5736:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5737:   PetscInt       dim;

5742:   DMGetDimension(dm, &dim);
5743:   if (cMax) *cMax = mesh->hybridPointMax[dim];
5744:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5745:   if (eMax) *eMax = mesh->hybridPointMax[1];
5746:   if (vMax) *vMax = mesh->hybridPointMax[0];
5747:   return(0);
5748: }

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

5755:   Input Parameters:
5756: . dm   - The DMPlex object
5757: . cMax - The first hybrid cell
5758: . fMax - The first hybrid face
5759: . eMax - The first hybrid edge
5760: - vMax - The first hybrid vertex

5762:   Level: developer

5764: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5765: @*/
5766: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5767: {
5768:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5769:   PetscInt       dim;

5774:   DMGetDimension(dm, &dim);
5775:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5776:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5777:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5778:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5779:   return(0);
5780: }

5784: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5785: {
5786:   DM_Plex *mesh = (DM_Plex*) dm->data;

5791:   *cellHeight = mesh->vtkCellHeight;
5792:   return(0);
5793: }

5797: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5798: {
5799:   DM_Plex *mesh = (DM_Plex*) dm->data;

5803:   mesh->vtkCellHeight = cellHeight;
5804:   return(0);
5805: }

5809: /* We can easily have a form that takes an IS instead */
5810: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5811: {
5812:   PetscSection   section, globalSection;
5813:   PetscInt      *numbers, p;

5817:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
5818:   PetscSectionSetChart(section, pStart, pEnd);
5819:   for (p = pStart; p < pEnd; ++p) {
5820:     PetscSectionSetDof(section, p, 1);
5821:   }
5822:   PetscSectionSetUp(section);
5823:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
5824:   PetscMalloc1(pEnd - pStart, &numbers);
5825:   for (p = pStart; p < pEnd; ++p) {
5826:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5827:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5828:     else                       numbers[p-pStart] += shift;
5829:   }
5830:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5831:   if (globalSize) {
5832:     PetscLayout layout;
5833:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
5834:     PetscLayoutGetSize(layout, globalSize);
5835:     PetscLayoutDestroy(&layout);
5836:   }
5837:   PetscSectionDestroy(&section);
5838:   PetscSectionDestroy(&globalSection);
5839:   return(0);
5840: }

5844: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5845: {
5846:   PetscInt       cellHeight, cStart, cEnd, cMax;

5850:   DMPlexGetVTKCellHeight(dm, &cellHeight);
5851:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5852:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5853:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5854:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
5855:   return(0);
5856: }

5860: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5861: {
5862:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5867:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
5868:   *globalCellNumbers = mesh->globalCellNumbers;
5869:   return(0);
5870: }

5874: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
5875: {
5876:   PetscInt       vStart, vEnd, vMax;

5881:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5882:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
5883:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
5884:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
5885:   return(0);
5886: }

5890: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5891: {
5892:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5897:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
5898:   *globalVertexNumbers = mesh->globalVertexNumbers;
5899:   return(0);
5900: }

5904: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
5905: {
5906:   IS             nums[4];
5907:   PetscInt       depths[4];
5908:   PetscInt       depth, d, shift = 0;

5913:   DMPlexGetDepth(dm, &depth);
5914:   /* For unstratified meshes use dim instead of depth */
5915:   if (depth < 0) {DMGetDimension(dm, &depth);}
5916:   depths[0] = depth; depths[1] = 0;
5917:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
5918:   for (d = 0; d <= depth; ++d) {
5919:     PetscInt pStart, pEnd, gsize;

5921:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
5922:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
5923:     shift += gsize;
5924:   }
5925:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
5926:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
5927:   return(0);
5928: }

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

5935:   Input Parameters:
5936:   + dm - The DMPlex object

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

5940:   Level: developer

5942: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5943: @*/
5944: PetscErrorCode DMPlexCheckSymmetry(DM dm)
5945: {
5946:   PetscSection    coneSection, supportSection;
5947:   const PetscInt *cone, *support;
5948:   PetscInt        coneSize, c, supportSize, s;
5949:   PetscInt        pStart, pEnd, p, csize, ssize;
5950:   PetscErrorCode  ierr;

5954:   DMPlexGetConeSection(dm, &coneSection);
5955:   DMPlexGetSupportSection(dm, &supportSection);
5956:   /* Check that point p is found in the support of its cone points, and vice versa */
5957:   DMPlexGetChart(dm, &pStart, &pEnd);
5958:   for (p = pStart; p < pEnd; ++p) {
5959:     DMPlexGetConeSize(dm, p, &coneSize);
5960:     DMPlexGetCone(dm, p, &cone);
5961:     for (c = 0; c < coneSize; ++c) {
5962:       PetscBool dup = PETSC_FALSE;
5963:       PetscInt  d;
5964:       for (d = c-1; d >= 0; --d) {
5965:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5966:       }
5967:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
5968:       DMPlexGetSupport(dm, cone[c], &support);
5969:       for (s = 0; s < supportSize; ++s) {
5970:         if (support[s] == p) break;
5971:       }
5972:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5973:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
5974:         for (s = 0; s < coneSize; ++s) {
5975:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
5976:         }
5977:         PetscPrintf(PETSC_COMM_SELF, "\n");
5978:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
5979:         for (s = 0; s < supportSize; ++s) {
5980:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
5981:         }
5982:         PetscPrintf(PETSC_COMM_SELF, "\n");
5983:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
5984:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
5985:       }
5986:     }
5987:     DMPlexGetSupportSize(dm, p, &supportSize);
5988:     DMPlexGetSupport(dm, p, &support);
5989:     for (s = 0; s < supportSize; ++s) {
5990:       DMPlexGetConeSize(dm, support[s], &coneSize);
5991:       DMPlexGetCone(dm, support[s], &cone);
5992:       for (c = 0; c < coneSize; ++c) {
5993:         if (cone[c] == p) break;
5994:       }
5995:       if (c >= coneSize) {
5996:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
5997:         for (c = 0; c < supportSize; ++c) {
5998:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
5999:         }
6000:         PetscPrintf(PETSC_COMM_SELF, "\n");
6001:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6002:         for (c = 0; c < coneSize; ++c) {
6003:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6004:         }
6005:         PetscPrintf(PETSC_COMM_SELF, "\n");
6006:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6007:       }
6008:     }
6009:   }
6010:   PetscSectionGetStorageSize(coneSection, &csize);
6011:   PetscSectionGetStorageSize(supportSection, &ssize);
6012:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6013:   return(0);
6014: }

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

6021:   Input Parameters:
6022: + dm - The DMPlex object
6023: . isSimplex - Are the cells simplices or tensor products
6024: - cellHeight - Normally 0

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

6028:   Level: developer

6030: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6031: @*/
6032: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6033: {
6034:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6039:   DMGetDimension(dm, &dim);
6040:   switch (dim) {
6041:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6042:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6043:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6044:   default:
6045:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6046:   }
6047:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6048:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6049:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6050:   cMax = cMax >= 0 ? cMax : cEnd;
6051:   for (c = cStart; c < cMax; ++c) {
6052:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6054:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6055:     for (cl = 0; cl < closureSize*2; cl += 2) {
6056:       const PetscInt p = closure[cl];
6057:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6058:     }
6059:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6060:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6061:   }
6062:   for (c = cMax; c < cEnd; ++c) {
6063:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6065:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6066:     for (cl = 0; cl < closureSize*2; cl += 2) {
6067:       const PetscInt p = closure[cl];
6068:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6069:     }
6070:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6071:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6072:   }
6073:   return(0);
6074: }

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

6081:   Input Parameters:
6082: + dm - The DMPlex object
6083: . isSimplex - Are the cells simplices or tensor products
6084: - cellHeight - Normally 0

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

6088:   Level: developer

6090: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6091: @*/
6092: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6093: {
6094:   PetscInt       pMax[4];
6095:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6100:   DMGetDimension(dm, &dim);
6101:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6102:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6103:   for (h = cellHeight; h < dim; ++h) {
6104:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6105:     for (c = cStart; c < cEnd; ++c) {
6106:       const PetscInt *cone, *ornt, *faces;
6107:       PetscInt        numFaces, faceSize, coneSize,f;
6108:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6110:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6111:       DMPlexGetConeSize(dm, c, &coneSize);
6112:       DMPlexGetCone(dm, c, &cone);
6113:       DMPlexGetConeOrientation(dm, c, &ornt);
6114:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6115:       for (cl = 0; cl < closureSize*2; cl += 2) {
6116:         const PetscInt p = closure[cl];
6117:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6118:       }
6119:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6120:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6121:       for (f = 0; f < numFaces; ++f) {
6122:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6124:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6125:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6126:           const PetscInt p = fclosure[cl];
6127:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6128:         }
6129:         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);
6130:         for (v = 0; v < fnumCorners; ++v) {
6131:           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]);
6132:         }
6133:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6134:       }
6135:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6136:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6137:     }
6138:   }
6139:   return(0);
6140: }

6144: /* Pointwise interpolation
6145:      Just code FEM for now
6146:      u^f = I u^c
6147:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6148:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6149:      I_{ij} = psi^f_i phi^c_j
6150: */
6151: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6152: {
6153:   PetscSection   gsc, gsf;
6154:   PetscInt       m, n;
6155:   void          *ctx;
6156:   DM             cdm;
6157:   PetscBool      regular;

6161:   DMGetDefaultGlobalSection(dmFine, &gsf);
6162:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6163:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6164:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6166:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6167:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6168:   MatSetType(*interpolation, dmCoarse->mattype);
6169:   DMGetApplicationContext(dmFine, &ctx);

6171:   DMGetCoarseDM(dmFine, &cdm);
6172:   DMPlexGetRegularRefinement(dmFine, &regular);
6173:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6174:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6175:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6176:   /* Use naive scaling */
6177:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6178:   return(0);
6179: }

6183: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6184: {
6186:   VecScatter     ctx;

6189:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6190:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6191:   VecScatterDestroy(&ctx);
6192:   return(0);
6193: }

6197: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6198: {
6199:   PetscSection   section;
6200:   IS            *bcPoints, *bcComps;
6201:   PetscBool     *isFE;
6202:   PetscInt      *bcFields, *numComp, *numDof;
6203:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6204:   PetscInt       cStart, cEnd, cEndInterior;

6208:   DMGetNumFields(dm, &numFields);
6209:   if (!numFields) return(0);
6210:   /* FE and FV boundary conditions are handled slightly differently */
6211:   PetscMalloc1(numFields, &isFE);
6212:   for (f = 0; f < numFields; ++f) {
6213:     PetscObject  obj;
6214:     PetscClassId id;

6216:     DMGetField(dm, f, &obj);
6217:     PetscObjectGetClassId(obj, &id);
6218:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6219:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6220:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6221:   }
6222:   /* Allocate boundary point storage for FEM boundaries */
6223:   DMPlexGetDepth(dm, &depth);
6224:   DMGetDimension(dm, &dim);
6225:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6226:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6227:   PetscDSGetNumBoundary(dm->prob, &numBd);
6228:   for (bd = 0; bd < numBd; ++bd) {
6229:     PetscInt                field;
6230:     DMBoundaryConditionType type;
6231:     const char             *labelName;
6232:     DMLabel                 label;

6234:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6235:     DMGetLabel(dm,labelName,&label);
6236:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6237:   }
6238:   /* Add ghost cell boundaries for FVM */
6239:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6240:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6241:   /* Constrain ghost cells for FV */
6242:   for (f = 0; f < numFields; ++f) {
6243:     PetscInt *newidx, c;

6245:     if (isFE[f] || cEndInterior < 0) continue;
6246:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6247:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6248:     bcFields[bc] = f;
6249:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6250:   }
6251:   /* Handle FEM Dirichlet boundaries */
6252:   for (bd = 0; bd < numBd; ++bd) {
6253:     const char             *bdLabel;
6254:     DMLabel                 label;
6255:     const PetscInt         *comps;
6256:     const PetscInt         *values;
6257:     PetscInt                bd2, field, numComps, numValues;
6258:     DMBoundaryConditionType type;
6259:     PetscBool               duplicate = PETSC_FALSE;

6261:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6262:     DMGetLabel(dm, bdLabel, &label);
6263:     if (!isFE[field] || !label) continue;
6264:     /* Only want to modify label once */
6265:     for (bd2 = 0; bd2 < bd; ++bd2) {
6266:       const char *bdname;
6267:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6268:       PetscStrcmp(bdname, bdLabel, &duplicate);
6269:       if (duplicate) break;
6270:     }
6271:     if (!duplicate && (isFE[field])) {
6272:       /* don't complete cells, which are just present to give orientation to the boundary */
6273:       DMPlexLabelComplete(dm, label);
6274:     }
6275:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6276:     if (type & DM_BC_ESSENTIAL) {
6277:       PetscInt       *newidx;
6278:       PetscInt        n, newn = 0, p, v;

6280:       bcFields[bc] = field;
6281:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6282:       for (v = 0; v < numValues; ++v) {
6283:         IS              tmp;
6284:         const PetscInt *idx;

6286:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6287:         if (!tmp) continue;
6288:         ISGetLocalSize(tmp, &n);
6289:         ISGetIndices(tmp, &idx);
6290:         if (isFE[field]) {
6291:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6292:         } else {
6293:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6294:         }
6295:         ISRestoreIndices(tmp, &idx);
6296:         ISDestroy(&tmp);
6297:       }
6298:       PetscMalloc1(newn,&newidx);
6299:       newn = 0;
6300:       for (v = 0; v < numValues; ++v) {
6301:         IS              tmp;
6302:         const PetscInt *idx;

6304:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6305:         if (!tmp) continue;
6306:         ISGetLocalSize(tmp, &n);
6307:         ISGetIndices(tmp, &idx);
6308:         if (isFE[field]) {
6309:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6310:         } else {
6311:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6312:         }
6313:         ISRestoreIndices(tmp, &idx);
6314:         ISDestroy(&tmp);
6315:       }
6316:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6317:     }
6318:   }
6319:   /* Handle discretization */
6320:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6321:   for (f = 0; f < numFields; ++f) {
6322:     PetscObject obj;

6324:     DMGetField(dm, f, &obj);
6325:     if (isFE[f]) {
6326:       PetscFE         fe = (PetscFE) obj;
6327:       const PetscInt *numFieldDof;
6328:       PetscInt        d;

6330:       PetscFEGetNumComponents(fe, &numComp[f]);
6331:       PetscFEGetNumDof(fe, &numFieldDof);
6332:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6333:     } else {
6334:       PetscFV fv = (PetscFV) obj;

6336:       PetscFVGetNumComponents(fv, &numComp[f]);
6337:       numDof[f*(dim+1)+dim] = numComp[f];
6338:     }
6339:   }
6340:   for (f = 0; f < numFields; ++f) {
6341:     PetscInt d;
6342:     for (d = 1; d < dim; ++d) {
6343:       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.");
6344:     }
6345:   }
6346:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6347:   for (f = 0; f < numFields; ++f) {
6348:     PetscFE     fe;
6349:     const char *name;

6351:     DMGetField(dm, f, (PetscObject *) &fe);
6352:     PetscObjectGetName((PetscObject) fe, &name);
6353:     PetscSectionSetFieldName(section, f, name);
6354:   }
6355:   DMSetDefaultSection(dm, section);
6356:   PetscSectionDestroy(&section);
6357:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6358:   PetscFree3(bcFields,bcPoints,bcComps);
6359:   PetscFree2(numComp,numDof);
6360:   PetscFree(isFE);
6361:   return(0);
6362: }

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

6369:   Input Parameter:
6370: . dm - The DMPlex object

6372:   Output Parameter:
6373: . regular - The flag

6375:   Level: intermediate

6377: .seealso: DMPlexSetRegularRefinement()
6378: @*/
6379: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6380: {
6384:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6385:   return(0);
6386: }

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

6393:   Input Parameters:
6394: + dm - The DMPlex object
6395: - regular - The flag

6397:   Level: intermediate

6399: .seealso: DMPlexGetRegularRefinement()
6400: @*/
6401: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6402: {
6405:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6406:   return(0);
6407: }

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

6416:   not collective

6418:   Input Parameters:
6419: . dm - The DMPlex object

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


6426:   Level: intermediate

6428: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6429: @*/
6430: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6431: {
6432:   DM_Plex *plex = (DM_Plex *)dm->data;

6437:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6438:   if (anchorSection) *anchorSection = plex->anchorSection;
6439:   if (anchorIS) *anchorIS = plex->anchorIS;
6440:   return(0);
6441: }

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

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

6453:   collective on dm

6455:   Input Parameters:
6456: + dm - The DMPlex object
6457: . 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).
6458: - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).

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

6462:   Level: intermediate

6464: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6465: @*/
6466: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6467: {
6468:   DM_Plex        *plex = (DM_Plex *)dm->data;
6469:   PetscMPIInt    result;

6474:   if (anchorSection) {
6476:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6477:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6478:   }
6479:   if (anchorIS) {
6481:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6482:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6483:   }

6485:   PetscObjectReference((PetscObject)anchorSection);
6486:   PetscSectionDestroy(&plex->anchorSection);
6487:   plex->anchorSection = anchorSection;

6489:   PetscObjectReference((PetscObject)anchorIS);
6490:   ISDestroy(&plex->anchorIS);
6491:   plex->anchorIS = anchorIS;

6493: #if defined(PETSC_USE_DEBUG)
6494:   if (anchorIS && anchorSection) {
6495:     PetscInt size, a, pStart, pEnd;
6496:     const PetscInt *anchors;

6498:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6499:     ISGetLocalSize(anchorIS,&size);
6500:     ISGetIndices(anchorIS,&anchors);
6501:     for (a = 0; a < size; a++) {
6502:       PetscInt p;

6504:       p = anchors[a];
6505:       if (p >= pStart && p < pEnd) {
6506:         PetscInt dof;

6508:         PetscSectionGetDof(anchorSection,p,&dof);
6509:         if (dof) {
6510:           PetscErrorCode ierr2;

6512:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6513:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6514:         }
6515:       }
6516:     }
6517:     ISRestoreIndices(anchorIS,&anchors);
6518:   }
6519: #endif
6520:   /* reset the generic constraints */
6521:   DMSetDefaultConstraints(dm,NULL,NULL);
6522:   return(0);
6523: }

6527: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6528: {
6529:   PetscSection anchorSection;
6530:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6535:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6536:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6537:   PetscSectionGetNumFields(section,&numFields);
6538:   if (numFields) {
6539:     PetscInt f;
6540:     PetscSectionSetNumFields(*cSec,numFields);

6542:     for (f = 0; f < numFields; f++) {
6543:       PetscInt numComp;

6545:       PetscSectionGetFieldComponents(section,f,&numComp);
6546:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6547:     }
6548:   }
6549:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6550:   PetscSectionGetChart(section,&sStart,&sEnd);
6551:   pStart = PetscMax(pStart,sStart);
6552:   pEnd   = PetscMin(pEnd,sEnd);
6553:   pEnd   = PetscMax(pStart,pEnd);
6554:   PetscSectionSetChart(*cSec,pStart,pEnd);
6555:   for (p = pStart; p < pEnd; p++) {
6556:     PetscSectionGetDof(anchorSection,p,&dof);
6557:     if (dof) {
6558:       PetscSectionGetDof(section,p,&dof);
6559:       PetscSectionSetDof(*cSec,p,dof);
6560:       for (f = 0; f < numFields; f++) {
6561:         PetscSectionGetFieldDof(section,p,f,&dof);
6562:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6563:       }
6564:     }
6565:   }
6566:   PetscSectionSetUp(*cSec);
6567:   return(0);
6568: }

6572: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6573: {
6574:   PetscSection aSec;
6575:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6576:   const PetscInt *anchors;
6577:   PetscInt numFields, f;
6578:   IS aIS;

6583:   PetscSectionGetStorageSize(cSec, &m);
6584:   PetscSectionGetStorageSize(section, &n);
6585:   MatCreate(PETSC_COMM_SELF,cMat);
6586:   MatSetSizes(*cMat,m,n,m,n);
6587:   MatSetType(*cMat,MATSEQAIJ);
6588:   DMPlexGetAnchors(dm,&aSec,&aIS);
6589:   ISGetIndices(aIS,&anchors);
6590:   /* cSec will be a subset of aSec and section */
6591:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6592:   PetscMalloc1(m+1,&i);
6593:   i[0] = 0;
6594:   PetscSectionGetNumFields(section,&numFields);
6595:   for (p = pStart; p < pEnd; p++) {
6596:     PetscInt rDof, rOff, r;

6598:     PetscSectionGetDof(aSec,p,&rDof);
6599:     if (!rDof) continue;
6600:     PetscSectionGetOffset(aSec,p,&rOff);
6601:     if (numFields) {
6602:       for (f = 0; f < numFields; f++) {
6603:         annz = 0;
6604:         for (r = 0; r < rDof; r++) {
6605:           a = anchors[rOff + r];
6606:           PetscSectionGetFieldDof(section,a,f,&aDof);
6607:           annz += aDof;
6608:         }
6609:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6610:         PetscSectionGetFieldOffset(cSec,p,f,&off);
6611:         for (q = 0; q < dof; q++) {
6612:           i[off + q + 1] = i[off + q] + annz;
6613:         }
6614:       }
6615:     }
6616:     else {
6617:       annz = 0;
6618:       for (q = 0; q < dof; q++) {
6619:         a = anchors[off + q];
6620:         PetscSectionGetDof(section,a,&aDof);
6621:         annz += aDof;
6622:       }
6623:       PetscSectionGetDof(cSec,p,&dof);
6624:       PetscSectionGetOffset(cSec,p,&off);
6625:       for (q = 0; q < dof; q++) {
6626:         i[off + q + 1] = i[off + q] + annz;
6627:       }
6628:     }
6629:   }
6630:   nnz = i[m];
6631:   PetscMalloc1(nnz,&j);
6632:   offset = 0;
6633:   for (p = pStart; p < pEnd; p++) {
6634:     if (numFields) {
6635:       for (f = 0; f < numFields; f++) {
6636:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6637:         for (q = 0; q < dof; q++) {
6638:           PetscInt rDof, rOff, r;
6639:           PetscSectionGetDof(aSec,p,&rDof);
6640:           PetscSectionGetOffset(aSec,p,&rOff);
6641:           for (r = 0; r < rDof; r++) {
6642:             PetscInt s;

6644:             a = anchors[rOff + r];
6645:             PetscSectionGetFieldDof(section,a,f,&aDof);
6646:             PetscSectionGetFieldOffset(section,a,f,&aOff);
6647:             for (s = 0; s < aDof; s++) {
6648:               j[offset++] = aOff + s;
6649:             }
6650:           }
6651:         }
6652:       }
6653:     }
6654:     else {
6655:       PetscSectionGetDof(cSec,p,&dof);
6656:       for (q = 0; q < dof; q++) {
6657:         PetscInt rDof, rOff, r;
6658:         PetscSectionGetDof(aSec,p,&rDof);
6659:         PetscSectionGetOffset(aSec,p,&rOff);
6660:         for (r = 0; r < rDof; r++) {
6661:           PetscInt s;

6663:           a = anchors[rOff + r];
6664:           PetscSectionGetDof(section,a,&aDof);
6665:           PetscSectionGetOffset(section,a,&aOff);
6666:           for (s = 0; s < aDof; s++) {
6667:             j[offset++] = aOff + s;
6668:           }
6669:         }
6670:       }
6671:     }
6672:   }
6673:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
6674:   PetscFree(i);
6675:   PetscFree(j);
6676:   ISRestoreIndices(aIS,&anchors);
6677:   return(0);
6678: }

6682: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6683: {
6684:   DM_Plex        *plex = (DM_Plex *)dm->data;
6685:   PetscSection   anchorSection, section, cSec;
6686:   Mat            cMat;

6691:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6692:   if (anchorSection) {
6693:     PetscDS  ds;
6694:     PetscInt nf;

6696:     DMGetDefaultSection(dm,&section);
6697:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
6698:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
6699:     DMGetDS(dm,&ds);
6700:     PetscDSGetNumFields(ds,&nf);
6701:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
6702:     DMSetDefaultConstraints(dm,cSec,cMat);
6703:     PetscSectionDestroy(&cSec);
6704:     MatDestroy(&cMat);
6705:   }
6706:   return(0);
6707: }