Actual source code: plex.c

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

  8: /* Logging support */
  9: PetscLogEvent DMPLEX_Interpolate, PETSCPARTITIONER_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;

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

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

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

 48: PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
 49: {
 50:   DM                 dm;
 51:   PetscSection       s;
 52:   PetscDraw          draw, popup;
 53:   DM                 cdm;
 54:   PetscSection       coordSection;
 55:   Vec                coordinates;
 56:   const PetscScalar *coords, *array;
 57:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
 58:   PetscReal          vbound[2], time;
 59:   PetscBool          isnull, flg;
 60:   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
 61:   const char        *name;
 62:   char               title[PETSC_MAX_PATH_LEN];
 63:   PetscErrorCode     ierr;

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

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

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

 85:   VecGetLocalSize(coordinates, &N);
 86:   VecGetArrayRead(coordinates, &coords);
 87:   for (c = 0; c < N; c += dim) {
 88:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
 89:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
 90:   }
 91:   VecRestoreArrayRead(coordinates, &coords);
 92:   PetscDrawClear(draw);

 94:   /* Could implement something like DMDASelectFields() */
 95:   for (f = 0; f < Nf; ++f) {
 96:     DM   fdm = dm;
 97:     Vec  fv  = v;
 98:     IS   fis;
 99:     char prefix[PETSC_MAX_PATH_LEN];
100:     const char *fname;

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

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

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

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

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

137:         DMPlexPointLocalRead(fdm, c, array, &a);
138:         if (a) {
139:           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
140:           color[1] = color[2] = color[3] = color[0];
141:         } else {
142:           PetscScalar *vals = NULL;
143:           PetscInt     numVals, va;

145:           DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
146:           if (numVals % Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %D does not divide the number of values in the closure %D", Nc, numVals);
147:           switch (numVals/Nc) {
148:           case 3: /* P1 Triangle */
149:           case 4: /* P1 Quadrangle */
150:             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
151:             break;
152:           case 6: /* P2 Triangle */
153:           case 8: /* P2 Quadrangle */
154:             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
155:             break;
156:           default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
157:           }
158:           DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
159:         }
160:         DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
161:         switch (numCoords) {
162:         case 6:
163:           PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
164:           break;
165:         case 8:
166:           PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
167:           PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0]);
168:           break;
169:         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
170:         }
171:         DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
172:       }
173:       VecRestoreArrayRead(fv, &array);
174:       PetscDrawFlush(draw);
175:       PetscDrawPause(draw);
176:       PetscDrawSave(draw);
177:     }
178:     if (Nf > 1) {
179:       VecRestoreSubVector(v, fis, &fv);
180:       ISDestroy(&fis);
181:       DMDestroy(&fdm);
182:     }
183:   }
184:   return(0);
185: }

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

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

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

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

218:     DMGetDefaultSection(dm, &section);
219:     DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
220:     PetscObjectReference((PetscObject) v);  /* viewer drops reference */
221:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
222:   } else if (ishdf5) {
223: #if defined(PETSC_HAVE_HDF5)
224:     VecView_Plex_Local_HDF5(v, viewer);
225: #else
226:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
227: #endif
228:   } else if (isdraw) {
229:     VecView_Plex_Local_Draw(v, viewer);
230:   } else {
231:     if (isseq) {VecView_Seq(v, viewer);}
232:     else       {VecView_MPI(v, viewer);}
233:   }
234:   return(0);
235: }

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

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

255:     DMGetLocalVector(dm, &locv);
256:     PetscObjectGetName((PetscObject) v, &name);
257:     PetscObjectSetName((PetscObject) locv, name);
258:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
259:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
260:     DMGetOutputSequenceNumber(dm, NULL, &time);
261:     DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
262:     VecView_Plex_Local(locv, viewer);
263:     DMRestoreLocalVector(dm, &locv);
264:   } else if (ishdf5) {
265: #if defined(PETSC_HAVE_HDF5)
266:     VecView_Plex_HDF5(v, viewer);
267: #else
268:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
269: #endif
270:   } else if (isdraw) {
271:     Vec         locv;
272:     const char *name;

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

290: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
291: {
292:   DM                dm;
293:   MPI_Comm          comm;
294:   PetscViewerFormat format;
295:   Vec               v;
296:   PetscBool         isvtk, ishdf5;
297:   PetscErrorCode    ierr;

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

310:     if (dm->sfNatural) {
311:       VecGetLocalSize(originalv, &n);
312:       PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
313:       if (n == nroots) {
314:         DMGetGlobalVector(dm, &v);
315:         DMPlexGlobalToNaturalBegin(dm, originalv, v);
316:         DMPlexGlobalToNaturalEnd(dm, originalv, v);
317:         PetscObjectGetName((PetscObject) originalv, &vecname);
318:         PetscObjectSetName((PetscObject) v, vecname);
319:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
320:     } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
321:   } else {
322:     /* we are viewing a natural DMPlex vec. */
323:     v = originalv;
324:   }
325:   if (ishdf5) {
326: #if defined(PETSC_HAVE_HDF5)
327:     VecView_Plex_HDF5_Native(v, viewer);
328: #else
329:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
330: #endif
331:   } else if (isvtk) {
332:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
333:   } else {
334:     PetscBool isseq;

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

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

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

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

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

380:   VecGetDM(v, &dm);
381:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
382:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
383:   if (ishdf5) {
384: #if defined(PETSC_HAVE_HDF5)
385:     VecLoad_Plex_HDF5(v, viewer);
386: #else
387:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
388: #endif
389:   } else {
390:     VecLoad_Default(v, viewer);
391:   }
392:   return(0);
393: }

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

403:   VecGetDM(originalv, &dm);
404:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
405:   PetscViewerGetFormat(viewer, &format);
406:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
407:   if (format == PETSC_VIEWER_NATIVE) {
408:     if (dm->sfNatural) {
409:       if (ishdf5) {
410: #if defined(PETSC_HAVE_HDF5)
411:         Vec         v;
412:         const char *vecname;

414:         DMGetGlobalVector(dm, &v);
415:         PetscObjectGetName((PetscObject) originalv, &vecname);
416:         PetscObjectSetName((PetscObject) v, vecname);
417:         VecLoad_Plex_HDF5_Native(v, viewer);
418:         DMPlexNaturalToGlobalBegin(dm, v, originalv);
419:         DMPlexNaturalToGlobalEnd(dm, v, originalv);
420:         DMRestoreGlobalVector(dm, &v);
421: #else
422:         SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
423: #endif
424:       } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
425:     }
426:   }
427:   return(0);
428: }

430: PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
431: {
432:   PetscSection       coordSection;
433:   Vec                coordinates;
434:   DMLabel            depthLabel;
435:   const char        *name[4];
436:   const PetscScalar *a;
437:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
438:   PetscErrorCode     ierr;

441:   DMGetDimension(dm, &dim);
442:   DMGetCoordinatesLocal(dm, &coordinates);
443:   DMGetCoordinateSection(dm, &coordSection);
444:   DMPlexGetDepthLabel(dm, &depthLabel);
445:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
446:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
447:   VecGetArrayRead(coordinates, &a);
448:   name[0]     = "vertex";
449:   name[1]     = "edge";
450:   name[dim-1] = "face";
451:   name[dim]   = "cell";
452:   for (c = cStart; c < cEnd; ++c) {
453:     PetscInt *closure = NULL;
454:     PetscInt  closureSize, cl;

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

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

485: PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
486: {
487:   DM_Plex          *mesh = (DM_Plex*) dm->data;
488:   DM                cdm;
489:   DMLabel           markers;
490:   PetscSection      coordSection;
491:   Vec               coordinates;
492:   PetscViewerFormat format;
493:   PetscErrorCode    ierr;

496:   DMGetCoordinateDM(dm, &cdm);
497:   DMGetDefaultSection(cdm, &coordSection);
498:   DMGetCoordinatesLocal(dm, &coordinates);
499:   PetscViewerGetFormat(viewer, &format);
500:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
501:     const char *name;
502:     PetscInt    maxConeSize, maxSupportSize;
503:     PetscInt    pStart, pEnd, p;
504:     PetscMPIInt rank, size;

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

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

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

545:       DMGetPointSF(dm, &sf);
546:       PetscSFView(sf, viewer);
547:     }
548:     PetscViewerFlush(viewer);
549:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
550:     const char  *name, *color;
551:     const char  *defcolors[3]  = {"gray", "orange", "green"};
552:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
553:     PetscReal    scale         = 2.0;
554:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
555:     double       tcoords[3];
556:     PetscScalar *coords;
557:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
558:     PetscMPIInt  rank, size;
559:     char         **names, **colors, **lcolors;

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

612:       PetscSectionGetDof(coordSection, v, &dof);
613:       PetscSectionGetOffset(coordSection, v, &off);
614:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
615:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
616:       for (d = 0; d < dof; ++d) {
617:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
618:         tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
619:       }
620:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
621:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
622:       for (d = 0; d < dof; ++d) {
623:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
624:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
625:       }
626:       color = colors[rank%numColors];
627:       for (l = 0; l < numLabels; ++l) {
628:         PetscInt val;
629:         DMGetLabelValue(dm, names[l], v, &val);
630:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
631:       }
632:       if (useNumbers) {
633:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
634:       } else {
635:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
636:       }
637:     }
638:     VecRestoreArray(coordinates, &coords);
639:     PetscViewerFlush(viewer);
640:     /* Plot edges */
641:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
642:     if (dim < 3 && useNumbers) {
643:       VecGetArray(coordinates, &coords);
644:       PetscViewerASCIIPrintf(viewer, "\\path\n");
645:       for (e = eStart; e < eEnd; ++e) {
646:         const PetscInt *cone;
647:         PetscInt        coneSize, offA, offB, dof, d;

649:         DMPlexGetConeSize(dm, e, &coneSize);
650:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
651:         DMPlexGetCone(dm, e, &cone);
652:         PetscSectionGetDof(coordSection, cone[0], &dof);
653:         PetscSectionGetOffset(coordSection, cone[0], &offA);
654:         PetscSectionGetOffset(coordSection, cone[1], &offB);
655:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
656:         for (d = 0; d < dof; ++d) {
657:           tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
658:           tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
659:         }
660:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
661:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
662:         for (d = 0; d < dof; ++d) {
663:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
664:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
665:         }
666:         color = colors[rank%numColors];
667:         for (l = 0; l < numLabels; ++l) {
668:           PetscInt val;
669:           DMGetLabelValue(dm, names[l], v, &val);
670:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
671:         }
672:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
673:       }
674:       VecRestoreArray(coordinates, &coords);
675:       PetscViewerFlush(viewer);
676:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
677:     }
678:     /* Plot cells */
679:     if (dim == 3 || !useNumbers) {
680:       for (e = eStart; e < eEnd; ++e) {
681:         const PetscInt *cone;

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

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

703:           if ((point < vStart) || (point >= vEnd)) continue;
704:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
705:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
706:           if (firstPoint < 0) firstPoint = point;
707:         }
708:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
709:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
710:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
711:       }
712:     }
713:     PetscViewerFlush(viewer);
714:     PetscViewerASCIIPopSynchronized(viewer);
715:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
716:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
717:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
718:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
719:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
720:     PetscFree3(names, colors, lcolors);
721:   } else {
722:     MPI_Comm    comm;
723:     PetscInt   *sizes, *hybsizes;
724:     PetscInt    locDepth, depth, dim, d, pMax[4];
725:     PetscInt    pStart, pEnd, p;
726:     PetscInt    numLabels, l;
727:     const char *name;
728:     PetscMPIInt size;

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

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

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

811: PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
812: {
813:   PetscDraw          draw;
814:   DM                 cdm;
815:   PetscSection       coordSection;
816:   Vec                coordinates;
817:   const PetscScalar *coords;
818:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
819:   PetscBool          isnull;
820:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
821:   PetscErrorCode     ierr;

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

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

837:   VecGetLocalSize(coordinates, &N);
838:   VecGetArrayRead(coordinates, &coords);
839:   for (c = 0; c < N; c += dim) {
840:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
841:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
842:   }
843:   VecRestoreArrayRead(coordinates, &coords);
844:   PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
845:   PetscDrawClear(draw);

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

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

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

882:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
883:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
884:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
885:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
886:   if (iascii) {
887:     DMPlexView_Ascii(dm, viewer);
888:   } else if (ishdf5) {
889: #if defined(PETSC_HAVE_HDF5)
890:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
891:     DMPlexView_HDF5(dm, viewer);
892:     PetscViewerPopFormat(viewer);
893: #else
894:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
895: #endif
896:   } else if (isvtk) {
897:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
898:   } else if (isdraw) {
899:     DMPlexView_Draw(dm, viewer);
900:   }
901:   return(0);
902: }

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

912:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
913:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
914:   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
915:   else if (ishdf5) {
916: #if defined(PETSC_HAVE_HDF5)
917:     DMPlexLoad_HDF5(dm, viewer);
918: #else
919:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
920: #endif
921:   }
922:   return(0);
923: }


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

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

961: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
962: {
963:   PetscSection           sectionGlobal;
964:   PetscInt               bs = -1, mbs;
965:   PetscInt               localSize;
966:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
967:   PetscErrorCode         ierr;
968:   MatType                mtype;
969:   ISLocalToGlobalMapping ltog;

972:   MatInitializePackage();
973:   mtype = dm->mattype;
974:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
975:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
976:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
977:   MatCreate(PetscObjectComm((PetscObject)dm), J);
978:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
979:   MatSetType(*J, mtype);
980:   MatSetFromOptions(*J);
981:   MatGetBlockSize(*J, &mbs);
982:   if (mbs > 1) bs = mbs;
983:   PetscStrcmp(mtype, MATSHELL, &isShell);
984:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
985:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
986:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
987:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
988:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
989:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
990:   PetscStrcmp(mtype, MATIS, &isMatIS);
991:   if (!isShell) {
992:     PetscSection subSection;
993:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
994:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin, *ltogidx, lsize;
995:     PetscInt     pStart, pEnd, p, dof, cdof;

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

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

1013:       PetscSectionGetDof(sectionGlobal, p, &dof);
1014:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1015:       dof  = dof < 0 ? -(dof+1) : dof;
1016:       bdof = cdof && (dof-cdof) ? 1 : dof;
1017:       if (dof) {
1018:         if (bs < 0)          {bs = bdof;}
1019:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1020:       }
1021:       if (isMatIS) {
1022:         PetscInt loff,c,off;
1023:         PetscSectionGetOffset(subSection, p, &loff);
1024:         PetscSectionGetOffset(sectionGlobal, p, &off);
1025:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1026:       }
1027:     }
1028:     /* Must have same blocksize on all procs (some might have no points) */
1029:     bsLocal = bs;
1030:     MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1031:     bsLocal = bs < 0 ? bsMax : bs;
1032:     MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
1033:     if (bsMin != bsMax) {bs = 1;}
1034:     else                {bs = bsMax;}
1035:     bs   = bs < 0 ? 1 : bs;
1036:     if (isMatIS) {
1037:       PetscInt l;
1038:       /* Must reduce indices by blocksize */
1039:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1040:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1041:     }
1042:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1043:     if (isMatIS) {
1044:       ISLocalToGlobalMappingDestroy(&ltog);
1045:     }
1046:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1047:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1048:     PetscFree4(dnz, onz, dnzu, onzu);
1049:   }
1050:   MatSetDM(*J, dm);
1051:   return(0);
1052: }

1054: /*
1055:   DMPlexGetSubdomainGlobalSection - Returns the section associated with the subdomain

1057:   Not collective

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

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

1065:   Level: developer

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

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

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

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

1092:   Not collective

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

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

1101:   Level: beginner

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

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

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

1119:   Not collective

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

1126:   Output Parameters:

1128:   Level: beginner

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

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

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

1147:   Not collective

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

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

1156:   Level: beginner

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

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

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

1175:   Not collective

1177:   Input Parameters:
1178: + mesh - The DMPlex
1179: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1180: - size - The cone size for point p

1182:   Output Parameter:

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

1187:   Level: beginner

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

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

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

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

1207:   Not collective

1209:   Input Parameters:
1210: + mesh - The DMPlex
1211: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1212: - size - The additional cone size for point p

1214:   Output Parameter:

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

1219:   Level: beginner

1221: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1222: @*/
1223: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1224: {
1225:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1226:   PetscInt       csize;

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

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

1238: /*@C
1239:   DMPlexGetCone - Return 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()

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

1250:   Level: beginner

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

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

1258: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1259: @*/
1260: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1261: {
1262:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1263:   PetscInt       off;

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

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

1277:   Not collective

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

1284:   Output Parameter:

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

1289:   Level: beginner

1291: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1292: @*/
1293: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1294: {
1295:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1296:   PetscInt       pStart, pEnd;
1297:   PetscInt       dof, off, c;

1302:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1303:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1305:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1306:   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);
1307:   for (c = 0; c < dof; ++c) {
1308:     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);
1309:     mesh->cones[off+c] = cone[c];
1310:   }
1311:   return(0);
1312: }

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

1317:   Not collective

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

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

1329:   Level: beginner

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

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

1337: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1338: @*/
1339: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1340: {
1341:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1342:   PetscInt       off;

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

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

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

1363:   Not collective

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

1373:   Output Parameter:

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

1378:   Level: beginner

1380: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1381: @*/
1382: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1383: {
1384:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1385:   PetscInt       pStart, pEnd;
1386:   PetscInt       dof, off, c;

1391:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1392:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1394:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1395:   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);
1396:   for (c = 0; c < dof; ++c) {
1397:     PetscInt cdof, o = coneOrientation[c];

1399:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1400:     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);
1401:     mesh->coneOrientations[off+c] = o;
1402:   }
1403:   return(0);
1404: }

1406: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1407: {
1408:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1409:   PetscInt       pStart, pEnd;
1410:   PetscInt       dof, off;

1415:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1416:   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);
1417:   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);
1418:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1419:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1420:   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);
1421:   mesh->cones[off+conePos] = conePoint;
1422:   return(0);
1423: }

1425: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1426: {
1427:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1428:   PetscInt       pStart, pEnd;
1429:   PetscInt       dof, off;

1434:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1435:   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);
1436:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1437:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1438:   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);
1439:   mesh->coneOrientations[off+conePos] = coneOrientation;
1440:   return(0);
1441: }

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

1446:   Not collective

1448:   Input Parameters:
1449: + mesh - The DMPlex
1450: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1452:   Output Parameter:
1453: . size - The support size for point p

1455:   Level: beginner

1457: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1458: @*/
1459: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1460: {
1461:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1467:   PetscSectionGetDof(mesh->supportSection, p, size);
1468:   return(0);
1469: }

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

1474:   Not collective

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

1481:   Output Parameter:

1483:   Note:
1484:   This should be called after DMPlexSetChart().

1486:   Level: beginner

1488: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1489: @*/
1490: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1491: {
1492:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1499:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1500:   return(0);
1501: }

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

1506:   Not collective

1508:   Input Parameters:
1509: + mesh - The DMPlex
1510: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1515:   Level: beginner

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

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

1523: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1524: @*/
1525: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1526: {
1527:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1528:   PetscInt       off;

1534:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1535:   *support = &mesh->supports[off];
1536:   return(0);
1537: }

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

1542:   Not collective

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

1549:   Output Parameter:

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

1554:   Level: beginner

1556: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1557: @*/
1558: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1559: {
1560:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1561:   PetscInt       pStart, pEnd;
1562:   PetscInt       dof, off, c;

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

1579: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1580: {
1581:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1582:   PetscInt       pStart, pEnd;
1583:   PetscInt       dof, off;

1588:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1589:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1590:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1591:   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);
1592:   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);
1593:   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);
1594:   mesh->supports[off+supportPos] = supportPoint;
1595:   return(0);
1596: }

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

1601:   Not collective

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

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

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

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

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

1622:   Level: beginner

1624: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1625: @*/
1626: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1627: {
1628:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1629:   PetscInt       *closure, *fifo;
1630:   const PetscInt *tmp = NULL, *tmpO = NULL;
1631:   PetscInt        tmpSize, t;
1632:   PetscInt        depth       = 0, maxSize;
1633:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1634:   PetscErrorCode  ierr;

1638:   DMPlexGetDepth(dm, &depth);
1639:   /* This is only 1-level */
1640:   if (useCone) {
1641:     DMPlexGetConeSize(dm, p, &tmpSize);
1642:     DMPlexGetCone(dm, p, &tmp);
1643:     DMPlexGetConeOrientation(dm, p, &tmpO);
1644:   } else {
1645:     DMPlexGetSupportSize(dm, p, &tmpSize);
1646:     DMPlexGetSupport(dm, p, &tmp);
1647:   }
1648:   if (depth == 1) {
1649:     if (*points) {
1650:       closure = *points;
1651:     } else {
1652:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1653:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1654:     }
1655:     closure[0] = p; closure[1] = 0;
1656:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1657:       closure[closureSize]   = tmp[t];
1658:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1659:     }
1660:     if (numPoints) *numPoints = closureSize/2;
1661:     if (points)    *points    = closure;
1662:     return(0);
1663:   }
1664:   {
1665:     PetscInt c, coneSeries, s,supportSeries;

1667:     c = mesh->maxConeSize;
1668:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1669:     s = mesh->maxSupportSize;
1670:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1671:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1672:   }
1673:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1674:   if (*points) {
1675:     closure = *points;
1676:   } else {
1677:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1678:   }
1679:   closure[0] = p; closure[1] = 0;
1680:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1681:     const PetscInt cp = tmp[t];
1682:     const PetscInt co = tmpO ? tmpO[t] : 0;

1684:     closure[closureSize]   = cp;
1685:     closure[closureSize+1] = co;
1686:     fifo[fifoSize]         = cp;
1687:     fifo[fifoSize+1]       = co;
1688:   }
1689:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1690:   while (fifoSize - fifoStart) {
1691:     const PetscInt q   = fifo[fifoStart];
1692:     const PetscInt o   = fifo[fifoStart+1];
1693:     const PetscInt rev = o >= 0 ? 0 : 1;
1694:     const PetscInt off = rev ? -(o+1) : o;

1696:     if (useCone) {
1697:       DMPlexGetConeSize(dm, q, &tmpSize);
1698:       DMPlexGetCone(dm, q, &tmp);
1699:       DMPlexGetConeOrientation(dm, q, &tmpO);
1700:     } else {
1701:       DMPlexGetSupportSize(dm, q, &tmpSize);
1702:       DMPlexGetSupport(dm, q, &tmp);
1703:       tmpO = NULL;
1704:     }
1705:     for (t = 0; t < tmpSize; ++t) {
1706:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1707:       const PetscInt cp = tmp[i];
1708:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1709:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1710:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1711:       PetscInt       co = tmpO ? tmpO[i] : 0;
1712:       PetscInt       c;

1714:       if (rev) {
1715:         PetscInt childSize, coff;
1716:         DMPlexGetConeSize(dm, cp, &childSize);
1717:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1718:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1719:       }
1720:       /* Check for duplicate */
1721:       for (c = 0; c < closureSize; c += 2) {
1722:         if (closure[c] == cp) break;
1723:       }
1724:       if (c == closureSize) {
1725:         closure[closureSize]   = cp;
1726:         closure[closureSize+1] = co;
1727:         fifo[fifoSize]         = cp;
1728:         fifo[fifoSize+1]       = co;
1729:         closureSize           += 2;
1730:         fifoSize              += 2;
1731:       }
1732:     }
1733:     fifoStart += 2;
1734:   }
1735:   if (numPoints) *numPoints = closureSize/2;
1736:   if (points)    *points    = closure;
1737:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1738:   return(0);
1739: }

1741: /*@C
1742:   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

1744:   Not collective

1746:   Input Parameters:
1747: + mesh - The DMPlex
1748: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1749: . orientation - The orientation of the point
1750: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1751: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

1766:   Level: beginner

1768: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1769: @*/
1770: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1771: {
1772:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1773:   PetscInt       *closure, *fifo;
1774:   const PetscInt *tmp = NULL, *tmpO = NULL;
1775:   PetscInt        tmpSize, t;
1776:   PetscInt        depth       = 0, maxSize;
1777:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1778:   PetscErrorCode  ierr;

1782:   DMPlexGetDepth(dm, &depth);
1783:   /* This is only 1-level */
1784:   if (useCone) {
1785:     DMPlexGetConeSize(dm, p, &tmpSize);
1786:     DMPlexGetCone(dm, p, &tmp);
1787:     DMPlexGetConeOrientation(dm, p, &tmpO);
1788:   } else {
1789:     DMPlexGetSupportSize(dm, p, &tmpSize);
1790:     DMPlexGetSupport(dm, p, &tmp);
1791:   }
1792:   if (depth == 1) {
1793:     if (*points) {
1794:       closure = *points;
1795:     } else {
1796:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1797:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1798:     }
1799:     closure[0] = p; closure[1] = ornt;
1800:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1801:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1802:       closure[closureSize]   = tmp[i];
1803:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1804:     }
1805:     if (numPoints) *numPoints = closureSize/2;
1806:     if (points)    *points    = closure;
1807:     return(0);
1808:   }
1809:   {
1810:     PetscInt c, coneSeries, s,supportSeries;

1812:     c = mesh->maxConeSize;
1813:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1814:     s = mesh->maxSupportSize;
1815:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1816:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1817:   }
1818:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1819:   if (*points) {
1820:     closure = *points;
1821:   } else {
1822:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1823:   }
1824:   closure[0] = p; closure[1] = ornt;
1825:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1826:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1827:     const PetscInt cp = tmp[i];
1828:     PetscInt       co = tmpO ? tmpO[i] : 0;

1830:     if (ornt < 0) {
1831:       PetscInt childSize, coff;
1832:       DMPlexGetConeSize(dm, cp, &childSize);
1833:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
1834:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1835:     }
1836:     closure[closureSize]   = cp;
1837:     closure[closureSize+1] = co;
1838:     fifo[fifoSize]         = cp;
1839:     fifo[fifoSize+1]       = co;
1840:   }
1841:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1842:   while (fifoSize - fifoStart) {
1843:     const PetscInt q   = fifo[fifoStart];
1844:     const PetscInt o   = fifo[fifoStart+1];
1845:     const PetscInt rev = o >= 0 ? 0 : 1;
1846:     const PetscInt off = rev ? -(o+1) : o;

1848:     if (useCone) {
1849:       DMPlexGetConeSize(dm, q, &tmpSize);
1850:       DMPlexGetCone(dm, q, &tmp);
1851:       DMPlexGetConeOrientation(dm, q, &tmpO);
1852:     } else {
1853:       DMPlexGetSupportSize(dm, q, &tmpSize);
1854:       DMPlexGetSupport(dm, q, &tmp);
1855:       tmpO = NULL;
1856:     }
1857:     for (t = 0; t < tmpSize; ++t) {
1858:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1859:       const PetscInt cp = tmp[i];
1860:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1861:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1862:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1863:       PetscInt       co = tmpO ? tmpO[i] : 0;
1864:       PetscInt       c;

1866:       if (rev) {
1867:         PetscInt childSize, coff;
1868:         DMPlexGetConeSize(dm, cp, &childSize);
1869:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1870:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1871:       }
1872:       /* Check for duplicate */
1873:       for (c = 0; c < closureSize; c += 2) {
1874:         if (closure[c] == cp) break;
1875:       }
1876:       if (c == closureSize) {
1877:         closure[closureSize]   = cp;
1878:         closure[closureSize+1] = co;
1879:         fifo[fifoSize]         = cp;
1880:         fifo[fifoSize+1]       = co;
1881:         closureSize           += 2;
1882:         fifoSize              += 2;
1883:       }
1884:     }
1885:     fifoStart += 2;
1886:   }
1887:   if (numPoints) *numPoints = closureSize/2;
1888:   if (points)    *points    = closure;
1889:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1890:   return(0);
1891: }

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

1896:   Not collective

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

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

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

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

1914:   Level: beginner

1916: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1917: @*/
1918: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1919: {

1926:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
1927:   if (numPoints) *numPoints = 0;
1928:   return(0);
1929: }

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

1934:   Not collective

1936:   Input Parameter:
1937: . mesh - The DMPlex

1939:   Output Parameters:
1940: + maxConeSize - The maximum number of in-edges
1941: - maxSupportSize - The maximum number of out-edges

1943:   Level: beginner

1945: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1946: @*/
1947: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1948: {
1949:   DM_Plex *mesh = (DM_Plex*) dm->data;

1953:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1954:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1955:   return(0);
1956: }

1958: PetscErrorCode DMSetUp_Plex(DM dm)
1959: {
1960:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1961:   PetscInt       size;

1966:   PetscSectionSetUp(mesh->coneSection);
1967:   PetscSectionGetStorageSize(mesh->coneSection, &size);
1968:   PetscMalloc1(size, &mesh->cones);
1969:   PetscCalloc1(size, &mesh->coneOrientations);
1970:   if (mesh->maxSupportSize) {
1971:     PetscSectionSetUp(mesh->supportSection);
1972:     PetscSectionGetStorageSize(mesh->supportSection, &size);
1973:     PetscMalloc1(size, &mesh->supports);
1974:   }
1975:   return(0);
1976: }

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

1983:   if (subdm) {DMClone(dm, subdm);}
1984:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
1985:   return(0);
1986: }

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

1991:   Not collective

1993:   Input Parameter:
1994: . mesh - The DMPlex

1996:   Output Parameter:

1998:   Note:
1999:   This should be called after all calls to DMPlexSetCone()

2001:   Level: beginner

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

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

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

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

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

2042:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2043:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2044:     for (c = off; c < off+dof; ++c) {
2045:       const PetscInt q = mesh->cones[c];
2046:       PetscInt       offS;

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

2050:       mesh->supports[offS+offsets[q]] = p;
2051:       ++offsets[q];
2052:     }
2053:   }
2054:   PetscFree(offsets);
2055:   return(0);
2056: }

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

2064:   Collective on dm

2066:   Input Parameter:
2067: . mesh - The DMPlex

2069:   Output Parameter:

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

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

2079:   Level: beginner

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

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

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

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

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

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

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

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

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

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

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

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

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

2266:   Not Collective

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

2273:   Output Parameters:
2274: + numCoveredPoints - The number of points in the join
2275: - coveredPoints - The points in the join

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

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

2283:   Level: intermediate

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

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

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

2305:   Not Collective

2307:   Input Parameters:
2308: + dm - The DMPlex object
2309: . numPoints - The number of input points for the join
2310: - points - The input points

2312:   Output Parameters:
2313: + numCoveredPoints - The number of points in the join
2314: - coveredPoints - The points in the join

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

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

2322:   Level: intermediate

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


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

2350:   for (p = 0; p < numPoints; ++p) {
2351:     PetscInt closureSize;

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

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

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

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

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

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

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

2412:   Not Collective

2414:   Input Parameters:
2415: + dm - The DMPlex object
2416: . numPoints - The number of input points for the meet
2417: - points - The input points

2419:   Output Parameters:
2420: + numCoveredPoints - The number of points in the meet
2421: - coveredPoints - The points in the meet

2423:   Level: intermediate

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

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

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

2433: .keywords: mesh
2434: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2435: @*/
2436: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2437: {
2438:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2439:   PetscInt      *meet[2];
2440:   PetscInt       meetSize, i = 0;
2441:   PetscInt       dof, off, p, c, m;

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

2461:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2462:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2463:     for (c = 0; c < dof; ++c) {
2464:       const PetscInt point = mesh->cones[off+c];

2466:       for (m = 0; m < meetSize; ++m) {
2467:         if (point == meet[i][m]) {
2468:           meet[1-i][newMeetSize++] = point;
2469:           break;
2470:         }
2471:       }
2472:     }
2473:     meetSize = newMeetSize;
2474:     i        = 1-i;
2475:   }
2476:   *numCoveringPoints = meetSize;
2477:   *coveringPoints    = meet[i];
2478:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2479:   return(0);
2480: }

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

2485:   Not Collective

2487:   Input Parameters:
2488: + dm - The DMPlex object
2489: . numPoints - The number of input points for the meet
2490: - points - The input points

2492:   Output Parameters:
2493: + numCoveredPoints - The number of points in the meet
2494: - coveredPoints - The points in the meet

2496:   Level: intermediate

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

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

2504: .keywords: mesh
2505: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2506: @*/
2507: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2508: {

2516:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2517:   if (numCoveredPoints) *numCoveredPoints = 0;
2518:   return(0);
2519: }

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

2524:   Not Collective

2526:   Input Parameters:
2527: + dm - The DMPlex object
2528: . numPoints - The number of input points for the meet
2529: - points - The input points

2531:   Output Parameters:
2532: + numCoveredPoints - The number of points in the meet
2533: - coveredPoints - The points in the meet

2535:   Level: intermediate

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

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

2543: .keywords: mesh
2544: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2545: @*/
2546: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2547: {
2548:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2549:   PetscInt      *offsets, **closures;
2550:   PetscInt      *meet[2];
2551:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2552:   PetscInt       p, h, c, m, mc;


2561:   DMPlexGetDepth(dm, &height);
2562:   PetscMalloc1(numPoints, &closures);
2563:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2564:   mc      = mesh->maxConeSize;
2565:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2566:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
2567:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

2569:   for (p = 0; p < numPoints; ++p) {
2570:     PetscInt closureSize;

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

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

2578:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2579:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2580:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2581:           offsets[p*(height+2)+h+1] = i;
2582:           break;
2583:         }
2584:       }
2585:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2586:     }
2587:     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);
2588:   }
2589:   for (h = 0; h < height+1; ++h) {
2590:     PetscInt dof;

2592:     /* Copy in cone of first point */
2593:     dof = offsets[h+1] - offsets[h];
2594:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2595:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2596:     }
2597:     /* Check each successive cone */
2598:     for (p = 1; p < numPoints && meetSize; ++p) {
2599:       PetscInt newMeetSize = 0;

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

2605:         for (m = 0; m < meetSize; ++m) {
2606:           if (point == meet[i][m]) {
2607:             meet[1-i][newMeetSize++] = point;
2608:             break;
2609:           }
2610:         }
2611:       }
2612:       meetSize = newMeetSize;
2613:       i        = 1-i;
2614:     }
2615:     if (meetSize) break;
2616:   }
2617:   *numCoveredPoints = meetSize;
2618:   *coveredPoints    = meet[i];
2619:   for (p = 0; p < numPoints; ++p) {
2620:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2621:   }
2622:   PetscFree(closures);
2623:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2624:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2625:   return(0);
2626: }

2628: /*@C
2629:   DMPlexEqual - Determine if two DMs have the same topology

2631:   Not Collective

2633:   Input Parameters:
2634: + dmA - A DMPlex object
2635: - dmB - A DMPlex object

2637:   Output Parameters:
2638: . equal - PETSC_TRUE if the topologies are identical

2640:   Level: intermediate

2642:   Notes:
2643:   We are not solving graph isomorphism, so we do not permutation.

2645: .keywords: mesh
2646: .seealso: DMPlexGetCone()
2647: @*/
2648: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2649: {
2650:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2658:   *equal = PETSC_FALSE;
2659:   DMPlexGetDepth(dmA, &depth);
2660:   DMPlexGetDepth(dmB, &depthB);
2661:   if (depth != depthB) return(0);
2662:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2663:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2664:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2665:   for (p = pStart; p < pEnd; ++p) {
2666:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2667:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

2669:     DMPlexGetConeSize(dmA, p, &coneSize);
2670:     DMPlexGetCone(dmA, p, &cone);
2671:     DMPlexGetConeOrientation(dmA, p, &ornt);
2672:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2673:     DMPlexGetCone(dmB, p, &coneB);
2674:     DMPlexGetConeOrientation(dmB, p, &orntB);
2675:     if (coneSize != coneSizeB) return(0);
2676:     for (c = 0; c < coneSize; ++c) {
2677:       if (cone[c] != coneB[c]) return(0);
2678:       if (ornt[c] != orntB[c]) return(0);
2679:     }
2680:     DMPlexGetSupportSize(dmA, p, &supportSize);
2681:     DMPlexGetSupport(dmA, p, &support);
2682:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2683:     DMPlexGetSupport(dmB, p, &supportB);
2684:     if (supportSize != supportSizeB) return(0);
2685:     for (s = 0; s < supportSize; ++s) {
2686:       if (support[s] != supportB[s]) return(0);
2687:     }
2688:   }
2689:   *equal = PETSC_TRUE;
2690:   return(0);
2691: }

2693: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2694: {
2695:   MPI_Comm       comm;

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

2762: /*@
2763:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

2765:   Not Collective

2767:   Input Parameter:
2768: . dm    - The DMPlex object

2770:   Output Parameter:
2771: . depthLabel - The DMLabel recording point depth

2773:   Level: developer

2775: .keywords: mesh, points
2776: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2777: @*/
2778: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2779: {

2785:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
2786:   *depthLabel = dm->depthLabel;
2787:   return(0);
2788: }

2790: /*@
2791:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

2793:   Not Collective

2795:   Input Parameter:
2796: . dm    - The DMPlex object

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

2801:   Level: developer

2803: .keywords: mesh, points
2804: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2805: @*/
2806: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
2807: {
2808:   DMLabel        label;
2809:   PetscInt       d = 0;

2815:   DMPlexGetDepthLabel(dm, &label);
2816:   if (label) {DMLabelGetNumValues(label, &d);}
2817:   *depth = d-1;
2818:   return(0);
2819: }

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

2824:   Not Collective

2826:   Input Parameters:
2827: + dm           - The DMPlex object
2828: - stratumValue - The requested depth

2830:   Output Parameters:
2831: + start - The first point at this depth
2832: - end   - One beyond the last point at this depth

2834:   Level: developer

2836: .keywords: mesh, points
2837: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
2838: @*/
2839: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2840: {
2841:   DMLabel        label;
2842:   PetscInt       pStart, pEnd;

2849:   DMPlexGetChart(dm, &pStart, &pEnd);
2850:   if (pStart == pEnd) return(0);
2851:   if (stratumValue < 0) {
2852:     if (start) *start = pStart;
2853:     if (end)   *end   = pEnd;
2854:     return(0);
2855:   }
2856:   DMPlexGetDepthLabel(dm, &label);
2857:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2858:   DMLabelGetStratumBounds(label, stratumValue, start, end);
2859:   return(0);
2860: }

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

2865:   Not Collective

2867:   Input Parameters:
2868: + dm           - The DMPlex object
2869: - stratumValue - The requested height

2871:   Output Parameters:
2872: + start - The first point at this height
2873: - end   - One beyond the last point at this height

2875:   Level: developer

2877: .keywords: mesh, points
2878: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
2879: @*/
2880: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2881: {
2882:   DMLabel        label;
2883:   PetscInt       depth, pStart, pEnd;

2890:   DMPlexGetChart(dm, &pStart, &pEnd);
2891:   if (pStart == pEnd) return(0);
2892:   if (stratumValue < 0) {
2893:     if (start) *start = pStart;
2894:     if (end)   *end   = pEnd;
2895:     return(0);
2896:   }
2897:   DMPlexGetDepthLabel(dm, &label);
2898:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2899:   DMLabelGetNumValues(label, &depth);
2900:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
2901:   return(0);
2902: }

2904: /* Set the number of dof on each point and separate by fields */
2905: PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
2906: {
2907:   PetscInt      *pMax;
2908:   PetscInt       depth, pStart = 0, pEnd = 0;
2909:   PetscInt       Nf, p, d, dep, f;
2910:   PetscBool     *isFE;

2914:   PetscMalloc1(numFields, &isFE);
2915:   DMGetNumFields(dm, &Nf);
2916:   for (f = 0; f < numFields; ++f) {
2917:     PetscObject  obj;
2918:     PetscClassId id;

2920:     isFE[f] = PETSC_FALSE;
2921:     if (f >= Nf) continue;
2922:     DMGetField(dm, f, &obj);
2923:     PetscObjectGetClassId(obj, &id);
2924:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2925:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2926:   }
2927:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
2928:   if (numFields > 0) {
2929:     PetscSectionSetNumFields(*section, numFields);
2930:     if (numComp) {
2931:       for (f = 0; f < numFields; ++f) {
2932:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
2933:         if (isFE[f]) {
2934:           PetscFE           fe;
2935:           PetscDualSpace    dspace;
2936:           const PetscInt    ***perms;
2937:           const PetscScalar ***flips;
2938:           const PetscInt    *numDof;

2940:           DMGetField(dm,f,(PetscObject *) &fe);
2941:           PetscFEGetDualSpace(fe,&dspace);
2942:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
2943:           PetscDualSpaceGetNumDof(dspace,&numDof);
2944:           if (perms || flips) {
2945:             DM               K;
2946:             DMLabel          depthLabel;
2947:             PetscInt         depth, h;
2948:             PetscSectionSym  sym;

2950:             PetscDualSpaceGetDM(dspace,&K);
2951:             DMPlexGetDepthLabel(dm,&depthLabel);
2952:             DMPlexGetDepth(dm,&depth);
2953:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
2954:             for (h = 0; h <= depth; h++) {
2955:               PetscDualSpace    hspace;
2956:               PetscInt          kStart, kEnd;
2957:               PetscInt          kConeSize;
2958:               const PetscInt    **perms0 = NULL;
2959:               const PetscScalar **flips0 = NULL;

2961:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
2962:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
2963:               if (!hspace) continue;
2964:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
2965:               if (perms) perms0 = perms[0];
2966:               if (flips) flips0 = flips[0];
2967:               if (!(perms0 || flips0)) continue;
2968:               DMPlexGetConeSize(K,kStart,&kConeSize);
2969:               if (numComp[f] == 1) {
2970:                 PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
2971:               } else {
2972:                 PetscInt    **fieldPerms = NULL, o;
2973:                 PetscScalar **fieldFlips = NULL;

2975:                 PetscCalloc1(2 * kConeSize,&fieldPerms);
2976:                 PetscCalloc1(2 * kConeSize,&fieldFlips);
2977:                 for (o = -kConeSize; o < kConeSize; o++) {
2978:                   if (perms0 && perms0[o]) {
2979:                     PetscInt r, s;

2981:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldPerms[o+kConeSize]);
2982:                     for (r = 0; r < numDof[depth - h]; r++) {
2983:                       for (s = 0; s < numComp[f]; s++) {
2984:                         fieldPerms[o+kConeSize][r * numComp[f] + s] = numComp[f] * perms0[o][r] + s;
2985:                       }
2986:                     }
2987:                   }
2988:                   if (flips0 && flips0[o]) {
2989:                     PetscInt r, s;

2991:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldFlips[o+kConeSize]);
2992:                     for (r = 0; r < numDof[depth - h]; r++) {
2993:                       for (s = 0; s < numComp[f]; s++) {
2994:                         fieldFlips[o+kConeSize][r * numComp[f] + s] = flips0[o][r];
2995:                       }
2996:                     }
2997:                   }
2998:                 }
2999:                 PetscSectionSymLabelSetStratum(sym,depth - h,numComp[f] * numDof[depth - h],-kConeSize,kConeSize,PETSC_OWN_POINTER,(const PetscInt **) fieldPerms,(const PetscScalar **)fieldFlips);
3000:               }
3001:             }
3002:             PetscSectionSetFieldSym(*section,f,sym);
3003:             PetscSectionSymDestroy(&sym);
3004:           }
3005:         }
3006:       }
3007:     }
3008:   }
3009:   DMPlexGetChart(dm, &pStart, &pEnd);
3010:   PetscSectionSetChart(*section, pStart, pEnd);
3011:   DMPlexGetDepth(dm, &depth);
3012:   PetscMalloc1(depth+1,&pMax);
3013:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3014:   for (dep = 0; dep <= depth; ++dep) {
3015:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3016:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3017:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3018:     for (p = pStart; p < pEnd; ++p) {
3019:       PetscInt tot = 0;

3021:       for (f = 0; f < numFields; ++f) {
3022:         if (isFE[f] && p >= pMax[dep]) continue;
3023:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3024:         tot += numDof[f*(dim+1)+d];
3025:       }
3026:       PetscSectionSetDof(*section, p, tot);
3027:     }
3028:   }
3029:   PetscFree(pMax);
3030:   PetscFree(isFE);
3031:   return(0);
3032: }

3034: /* Set the number of dof on each point and separate by fields
3035:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3036: */
3037: PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3038: {
3039:   PetscInt       numFields;
3040:   PetscInt       bc;
3041:   PetscSection   aSec;

3045:   PetscSectionGetNumFields(section, &numFields);
3046:   for (bc = 0; bc < numBC; ++bc) {
3047:     PetscInt        field = 0;
3048:     const PetscInt *comp;
3049:     const PetscInt *idx;
3050:     PetscInt        Nc = -1, n, i;

3052:     if (numFields) field = bcField[bc];
3053:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3054:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3055:     ISGetLocalSize(bcPoints[bc], &n);
3056:     ISGetIndices(bcPoints[bc], &idx);
3057:     for (i = 0; i < n; ++i) {
3058:       const PetscInt p = idx[i];
3059:       PetscInt       numConst;

3061:       if (numFields) {
3062:         PetscSectionGetFieldDof(section, p, field, &numConst);
3063:       } else {
3064:         PetscSectionGetDof(section, p, &numConst);
3065:       }
3066:       /* If Nc < 0, constrain every dof on the point */
3067:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3068:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3069:       PetscSectionAddConstraintDof(section, p, numConst);
3070:     }
3071:     ISRestoreIndices(bcPoints[bc], &idx);
3072:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3073:   }
3074:   DMPlexGetAnchors(dm, &aSec, NULL);
3075:   if (aSec) {
3076:     PetscInt aStart, aEnd, a;

3078:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3079:     for (a = aStart; a < aEnd; a++) {
3080:       PetscInt dof, f;

3082:       PetscSectionGetDof(aSec, a, &dof);
3083:       if (dof) {
3084:         /* if there are point-to-point constraints, then all dofs are constrained */
3085:         PetscSectionGetDof(section, a, &dof);
3086:         PetscSectionSetConstraintDof(section, a, dof);
3087:         for (f = 0; f < numFields; f++) {
3088:           PetscSectionGetFieldDof(section, a, f, &dof);
3089:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3090:         }
3091:       }
3092:     }
3093:   }
3094:   return(0);
3095: }

3097: /* Set the constrained field indices on each point
3098:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3099: */
3100: PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3101: {
3102:   PetscSection   aSec;
3103:   PetscInt      *indices;
3104:   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;

3108:   PetscSectionGetNumFields(section, &numFields);
3109:   if (!numFields) return(0);
3110:   /* Initialize all field indices to -1 */
3111:   PetscSectionGetChart(section, &pStart, &pEnd);
3112:   PetscSectionGetMaxDof(section, &maxDof);
3113:   PetscMalloc1(maxDof, &indices);
3114:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3115:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3116:   /* Handle BC constraints */
3117:   for (bc = 0; bc < numBC; ++bc) {
3118:     const PetscInt  field = bcField[bc];
3119:     const PetscInt *comp, *idx;
3120:     PetscInt        Nc = -1, n, i;

3122:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3123:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3124:     ISGetLocalSize(bcPoints[bc], &n);
3125:     ISGetIndices(bcPoints[bc], &idx);
3126:     for (i = 0; i < n; ++i) {
3127:       const PetscInt  p = idx[i];
3128:       const PetscInt *find;
3129:       PetscInt        fcdof, c;

3131:       PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3132:       if (Nc < 0) {
3133:         for (d = 0; d < fcdof; ++d) indices[d] = d;
3134:       } else {
3135:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3136:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3137:         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
3138:         PetscSortInt(d+Nc, indices);
3139:         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3140:       }
3141:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3142:     }
3143:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3144:     ISRestoreIndices(bcPoints[bc], &idx);
3145:   }
3146:   /* Handle anchors */
3147:   DMPlexGetAnchors(dm, &aSec, NULL);
3148:   if (aSec) {
3149:     PetscInt aStart, aEnd, a;

3151:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3152:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3153:     for (a = aStart; a < aEnd; a++) {
3154:       PetscInt dof, fdof, f;

3156:       PetscSectionGetDof(aSec, a, &dof);
3157:       if (dof) {
3158:         /* if there are point-to-point constraints, then all dofs are constrained */
3159:         for (f = 0; f < numFields; f++) {
3160:           PetscSectionGetFieldDof(section, a, f, &fdof);
3161:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3162:         }
3163:       }
3164:     }
3165:   }
3166:   PetscFree(indices);
3167:   return(0);
3168: }

3170: /* Set the constrained indices on each point */
3171: PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3172: {
3173:   PetscInt      *indices;
3174:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3178:   PetscSectionGetNumFields(section, &numFields);
3179:   PetscSectionGetMaxDof(section, &maxDof);
3180:   PetscSectionGetChart(section, &pStart, &pEnd);
3181:   PetscMalloc1(maxDof, &indices);
3182:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3183:   for (p = pStart; p < pEnd; ++p) {
3184:     PetscInt cdof, d;

3186:     PetscSectionGetConstraintDof(section, p, &cdof);
3187:     if (cdof) {
3188:       if (numFields) {
3189:         PetscInt numConst = 0, foff = 0;

3191:         for (f = 0; f < numFields; ++f) {
3192:           const PetscInt *find;
3193:           PetscInt        fcdof, fdof;

3195:           PetscSectionGetFieldDof(section, p, f, &fdof);
3196:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3197:           /* Change constraint numbering from field component to local dof number */
3198:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3199:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3200:           numConst += fcdof;
3201:           foff     += fdof;
3202:         }
3203:         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
3204:       } else {
3205:         for (d = 0; d < cdof; ++d) indices[d] = d;
3206:       }
3207:       PetscSectionSetConstraintIndices(section, p, indices);
3208:     }
3209:   }
3210:   PetscFree(indices);
3211:   return(0);
3212: }

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

3217:   Not Collective

3219:   Input Parameters:
3220: + dm        - The DMPlex object
3221: . dim       - The spatial dimension of the problem
3222: . numFields - The number of fields in the problem
3223: . numComp   - An array of size numFields that holds the number of components for each field
3224: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3225: . numBC     - The number of boundary conditions
3226: . bcField   - An array of size numBC giving the field number for each boundry condition
3227: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3228: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3229: - perm      - Optional permutation of the chart, or NULL

3231:   Output Parameter:
3232: . section - The PetscSection object

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

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

3239:   Level: developer

3241:   Fortran Notes:
3242:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3244: .keywords: mesh, elements
3245: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3246: @*/
3247: 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)
3248: {
3249:   PetscSection   aSec;

3253:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3254:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3255:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3256:   PetscSectionSetUp(*section);
3257:   DMPlexGetAnchors(dm,&aSec,NULL);
3258:   if (numBC || aSec) {
3259:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3260:     DMPlexCreateSectionBCIndices(dm, *section);
3261:   }
3262:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3263:   return(0);
3264: }

3266: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3267: {
3268:   PetscSection   section, s;
3269:   Mat            m;
3270:   PetscInt       maxHeight;

3274:   DMClone(dm, cdm);
3275:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3276:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3277:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3278:   DMSetDefaultSection(*cdm, section);
3279:   PetscSectionDestroy(&section);
3280:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3281:   MatCreate(PETSC_COMM_SELF, &m);
3282:   DMSetDefaultConstraints(*cdm, s, m);
3283:   PetscSectionDestroy(&s);
3284:   MatDestroy(&m);
3285:   return(0);
3286: }

3288: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3289: {
3290:   DM_Plex *mesh = (DM_Plex*) dm->data;

3294:   if (section) *section = mesh->coneSection;
3295:   return(0);
3296: }

3298: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3299: {
3300:   DM_Plex *mesh = (DM_Plex*) dm->data;

3304:   if (section) *section = mesh->supportSection;
3305:   return(0);
3306: }

3308: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3309: {
3310:   DM_Plex *mesh = (DM_Plex*) dm->data;

3314:   if (cones) *cones = mesh->cones;
3315:   return(0);
3316: }

3318: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3319: {
3320:   DM_Plex *mesh = (DM_Plex*) dm->data;

3324:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3325:   return(0);
3326: }

3328: /******************************** FEM Support **********************************/

3330: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3331: {
3332:   PetscInt      *perm;
3333:   PetscInt       dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3337:   if (!section) {DMGetDefaultSection(dm, &section);}
3338:   DMGetDimension(dm, &dim);
3339:   PetscSectionGetNumFields(section, &Nf);
3340:   if (dim <= 1) return(0);
3341:   for (f = 0; f < Nf; ++f) {
3342:     /* An order k SEM disc has k-1 dofs on an edge */
3343:     DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3344:     PetscSectionGetFieldDof(section, eStart, f, &k);
3345:     PetscSectionGetFieldComponents(section, f, &Nc);
3346:     k = k/Nc + 1;
3347:     size += PetscPowInt(k+1, dim)*Nc;
3348:   }
3349:   PetscMalloc1(size, &perm);
3350:   for (f = 0; f < Nf; ++f) {
3351:     switch (dim) {
3352:     case 2:
3353:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3354:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3355:       PetscSectionGetFieldDof(section, eStart, f, &k);
3356:       PetscSectionGetFieldComponents(section, f, &Nc);
3357:       k = k/Nc + 1;
3358:       /* The SEM order is

3360:          v_lb, {e_b}, v_rb,
3361:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3362:          v_lt, reverse {e_t}, v_rt
3363:       */
3364:       {
3365:         const PetscInt of   = 0;
3366:         const PetscInt oeb  = of   + PetscSqr(k-1);
3367:         const PetscInt oer  = oeb  + (k-1);
3368:         const PetscInt oet  = oer  + (k-1);
3369:         const PetscInt oel  = oet  + (k-1);
3370:         const PetscInt ovlb = oel  + (k-1);
3371:         const PetscInt ovrb = ovlb + 1;
3372:         const PetscInt ovrt = ovrb + 1;
3373:         const PetscInt ovlt = ovrt + 1;
3374:         PetscInt       o;

3376:         /* bottom */
3377:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3378:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3379:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3380:         /* middle */
3381:         for (i = 0; i < k-1; ++i) {
3382:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3383:           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;
3384:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3385:         }
3386:         /* top */
3387:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3388:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3389:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3390:         foffset = offset;
3391:       }
3392:       break;
3393:     case 3:
3394:       /* The original hex closure is

3396:          {c,
3397:           f_b, f_t, f_f, f_b, f_r, f_l,
3398:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3399:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3400:       */
3401:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3402:       PetscSectionGetFieldDof(section, eStart, f, &k);
3403:       PetscSectionGetFieldComponents(section, f, &Nc);
3404:       k = k/Nc + 1;
3405:       /* The SEM order is
3406:          Bottom Slice
3407:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3408:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3409:          v_blb, {e_bb}, v_brb,

3411:          Middle Slice (j)
3412:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3413:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3414:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3416:          Top Slice
3417:          v_tlf, {e_tf}, v_trf,
3418:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3419:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3420:       */
3421:       {
3422:         const PetscInt oc    = 0;
3423:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3424:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3425:         const PetscInt off   = oft   + PetscSqr(k-1);
3426:         const PetscInt ofk   = off   + PetscSqr(k-1);
3427:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3428:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3429:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3430:         const PetscInt oebb  = oebl  + (k-1);
3431:         const PetscInt oebr  = oebb  + (k-1);
3432:         const PetscInt oebf  = oebr  + (k-1);
3433:         const PetscInt oetf  = oebf  + (k-1);
3434:         const PetscInt oetr  = oetf  + (k-1);
3435:         const PetscInt oetb  = oetr  + (k-1);
3436:         const PetscInt oetl  = oetb  + (k-1);
3437:         const PetscInt oerf  = oetl  + (k-1);
3438:         const PetscInt oelf  = oerf  + (k-1);
3439:         const PetscInt oelb  = oelf  + (k-1);
3440:         const PetscInt oerb  = oelb  + (k-1);
3441:         const PetscInt ovblf = oerb  + (k-1);
3442:         const PetscInt ovblb = ovblf + 1;
3443:         const PetscInt ovbrb = ovblb + 1;
3444:         const PetscInt ovbrf = ovbrb + 1;
3445:         const PetscInt ovtlf = ovbrf + 1;
3446:         const PetscInt ovtrf = ovtlf + 1;
3447:         const PetscInt ovtrb = ovtrf + 1;
3448:         const PetscInt ovtlb = ovtrb + 1;
3449:         PetscInt       o, n;

3451:         /* Bottom Slice */
3452:         /*   bottom */
3453:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3454:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3455:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3456:         /*   middle */
3457:         for (i = 0; i < k-1; ++i) {
3458:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3459:           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;}
3460:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3461:         }
3462:         /*   top */
3463:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3464:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3465:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3467:         /* Middle Slice */
3468:         for (j = 0; j < k-1; ++j) {
3469:           /*   bottom */
3470:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3471:           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;
3472:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3473:           /*   middle */
3474:           for (i = 0; i < k-1; ++i) {
3475:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3476:             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;
3477:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3478:           }
3479:           /*   top */
3480:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3481:           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;
3482:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3483:         }

3485:         /* Top Slice */
3486:         /*   bottom */
3487:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3488:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3489:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3490:         /*   middle */
3491:         for (i = 0; i < k-1; ++i) {
3492:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3493:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3494:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3495:         }
3496:         /*   top */
3497:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3498:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3499:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3501:         foffset = offset;
3502:       }
3503:       break;
3504:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3505:     }
3506:   }
3507:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3508:   /* Check permutation */
3509:   {
3510:     PetscInt *check;

3512:     PetscMalloc1(size, &check);
3513:     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]);}
3514:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3515:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3516:     PetscFree(check);
3517:   }
3518:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3519:   return(0);
3520: }

3522: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3523: {
3524:   PetscDS        prob;
3525:   PetscInt       depth, Nf, h;
3526:   DMLabel        label;

3530:   prob    = dm->prob;
3531:   Nf      = prob->Nf;
3532:   label   = dm->depthLabel;
3533:   *dspace = NULL;
3534:   if (field < Nf) {
3535:     PetscObject disc = prob->disc[field];

3537:     if (disc->classid == PETSCFE_CLASSID) {
3538:       PetscDualSpace dsp;

3540:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3541:       DMLabelGetNumValues(label,&depth);
3542:       DMLabelGetValue(label,point,&h);
3543:       h    = depth - 1 - h;
3544:       if (h) {
3545:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3546:       } else {
3547:         *dspace = dsp;
3548:       }
3549:     }
3550:   }
3551:   return(0);
3552: }


3555: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3556: {
3557:   PetscScalar    *array, *vArray;
3558:   const PetscInt *cone, *coneO;
3559:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3560:   PetscErrorCode  ierr;

3563:   PetscSectionGetChart(section, &pStart, &pEnd);
3564:   DMPlexGetConeSize(dm, point, &numPoints);
3565:   DMPlexGetCone(dm, point, &cone);
3566:   DMPlexGetConeOrientation(dm, point, &coneO);
3567:   if (!values || !*values) {
3568:     if ((point >= pStart) && (point < pEnd)) {
3569:       PetscInt dof;

3571:       PetscSectionGetDof(section, point, &dof);
3572:       size += dof;
3573:     }
3574:     for (p = 0; p < numPoints; ++p) {
3575:       const PetscInt cp = cone[p];
3576:       PetscInt       dof;

3578:       if ((cp < pStart) || (cp >= pEnd)) continue;
3579:       PetscSectionGetDof(section, cp, &dof);
3580:       size += dof;
3581:     }
3582:     if (!values) {
3583:       if (csize) *csize = size;
3584:       return(0);
3585:     }
3586:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
3587:   } else {
3588:     array = *values;
3589:   }
3590:   size = 0;
3591:   VecGetArray(v, &vArray);
3592:   if ((point >= pStart) && (point < pEnd)) {
3593:     PetscInt     dof, off, d;
3594:     PetscScalar *varr;

3596:     PetscSectionGetDof(section, point, &dof);
3597:     PetscSectionGetOffset(section, point, &off);
3598:     varr = &vArray[off];
3599:     for (d = 0; d < dof; ++d, ++offset) {
3600:       array[offset] = varr[d];
3601:     }
3602:     size += dof;
3603:   }
3604:   for (p = 0; p < numPoints; ++p) {
3605:     const PetscInt cp = cone[p];
3606:     PetscInt       o  = coneO[p];
3607:     PetscInt       dof, off, d;
3608:     PetscScalar   *varr;

3610:     if ((cp < pStart) || (cp >= pEnd)) continue;
3611:     PetscSectionGetDof(section, cp, &dof);
3612:     PetscSectionGetOffset(section, cp, &off);
3613:     varr = &vArray[off];
3614:     if (o >= 0) {
3615:       for (d = 0; d < dof; ++d, ++offset) {
3616:         array[offset] = varr[d];
3617:       }
3618:     } else {
3619:       for (d = dof-1; d >= 0; --d, ++offset) {
3620:         array[offset] = varr[d];
3621:       }
3622:     }
3623:     size += dof;
3624:   }
3625:   VecRestoreArray(v, &vArray);
3626:   if (!*values) {
3627:     if (csize) *csize = size;
3628:     *values = array;
3629:   } else {
3630:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3631:     *csize = size;
3632:   }
3633:   return(0);
3634: }

3636: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3637: {
3638:   const PetscInt *cla;
3639:   PetscInt       np, *pts = NULL;

3643:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3644:   if (!*clPoints) {
3645:     PetscInt pStart, pEnd, p, q;

3647:     PetscSectionGetChart(section, &pStart, &pEnd);
3648:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3649:     /* Compress out points not in the section */
3650:     for (p = 0, q = 0; p < np; p++) {
3651:       PetscInt r = pts[2*p];
3652:       if ((r >= pStart) && (r < pEnd)) {
3653:         pts[q*2]   = r;
3654:         pts[q*2+1] = pts[2*p+1];
3655:         ++q;
3656:       }
3657:     }
3658:     np = q;
3659:     cla = NULL;
3660:   } else {
3661:     PetscInt dof, off;

3663:     PetscSectionGetDof(*clSec, point, &dof);
3664:     PetscSectionGetOffset(*clSec, point, &off);
3665:     ISGetIndices(*clPoints, &cla);
3666:     np   = dof/2;
3667:     pts  = (PetscInt *) &cla[off];
3668:   }
3669:   *numPoints = np;
3670:   *points    = pts;
3671:   *clp       = cla;

3673:   return(0);
3674: }

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

3681:   if (!*clPoints) {
3682:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3683:   } else {
3684:     ISRestoreIndices(*clPoints, clp);
3685:   }
3686:   *numPoints = 0;
3687:   *points    = NULL;
3688:   *clSec     = NULL;
3689:   *clPoints  = NULL;
3690:   *clp       = NULL;
3691:   return(0);
3692: }

3694: 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[])
3695: {
3696:   PetscInt          offset = 0, p;
3697:   const PetscInt    **perms = NULL;
3698:   const PetscScalar **flips = NULL;
3699:   PetscErrorCode    ierr;

3702:   *size = 0;
3703:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3704:   for (p = 0; p < numPoints; p++) {
3705:     const PetscInt    point = points[2*p];
3706:     const PetscInt    *perm = perms ? perms[p] : NULL;
3707:     const PetscScalar *flip = flips ? flips[p] : NULL;
3708:     PetscInt          dof, off, d;
3709:     const PetscScalar *varr;

3711:     PetscSectionGetDof(section, point, &dof);
3712:     PetscSectionGetOffset(section, point, &off);
3713:     varr = &vArray[off];
3714:     if (clperm) {
3715:       if (perm) {
3716:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3717:       } else {
3718:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3719:       }
3720:       if (flip) {
3721:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3722:       }
3723:     } else {
3724:       if (perm) {
3725:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3726:       } else {
3727:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3728:       }
3729:       if (flip) {
3730:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3731:       }
3732:     }
3733:     offset += dof;
3734:   }
3735:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3736:   *size = offset;
3737:   return(0);
3738: }

3740: 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[])
3741: {
3742:   PetscInt          offset = 0, f;
3743:   PetscErrorCode    ierr;

3746:   *size = 0;
3747:   for (f = 0; f < numFields; ++f) {
3748:     PetscInt          p;
3749:     const PetscInt    **perms = NULL;
3750:     const PetscScalar **flips = NULL;

3752:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3753:     for (p = 0; p < numPoints; p++) {
3754:       const PetscInt    point = points[2*p];
3755:       PetscInt          fdof, foff, b;
3756:       const PetscScalar *varr;
3757:       const PetscInt    *perm = perms ? perms[p] : NULL;
3758:       const PetscScalar *flip = flips ? flips[p] : NULL;

3760:       PetscSectionGetFieldDof(section, point, f, &fdof);
3761:       PetscSectionGetFieldOffset(section, point, f, &foff);
3762:       varr = &vArray[foff];
3763:       if (clperm) {
3764:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
3765:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
3766:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
3767:       } else {
3768:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
3769:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
3770:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
3771:       }
3772:       offset += fdof;
3773:     }
3774:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3775:   }
3776:   *size = offset;
3777:   return(0);
3778: }

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

3783:   Not collective

3785:   Input Parameters:
3786: + dm - The DM
3787: . section - The section describing the layout in v, or NULL to use the default section
3788: . v - The local vector
3789: - point - The sieve point in the DM

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

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

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

3801:   Level: intermediate

3803: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3804: @*/
3805: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3806: {
3807:   PetscSection       clSection;
3808:   IS                 clPoints;
3809:   PetscScalar       *array;
3810:   const PetscScalar *vArray;
3811:   PetscInt          *points = NULL;
3812:   const PetscInt    *clp, *perm;
3813:   PetscInt           depth, numFields, numPoints, size;
3814:   PetscErrorCode     ierr;

3818:   if (!section) {DMGetDefaultSection(dm, &section);}
3821:   DMPlexGetDepth(dm, &depth);
3822:   PetscSectionGetNumFields(section, &numFields);
3823:   if (depth == 1 && numFields < 2) {
3824:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
3825:     return(0);
3826:   }
3827:   /* Get points */
3828:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3829:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
3830:   /* Get array */
3831:   if (!values || !*values) {
3832:     PetscInt asize = 0, dof, p;

3834:     for (p = 0; p < numPoints*2; p += 2) {
3835:       PetscSectionGetDof(section, points[p], &dof);
3836:       asize += dof;
3837:     }
3838:     if (!values) {
3839:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3840:       if (csize) *csize = asize;
3841:       return(0);
3842:     }
3843:     DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
3844:   } else {
3845:     array = *values;
3846:   }
3847:   VecGetArrayRead(v, &vArray);
3848:   /* Get values */
3849:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
3850:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
3851:   /* Cleanup points */
3852:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3853:   /* Cleanup array */
3854:   VecRestoreArrayRead(v, &vArray);
3855:   if (!*values) {
3856:     if (csize) *csize = size;
3857:     *values = array;
3858:   } else {
3859:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3860:     *csize = size;
3861:   }
3862:   return(0);
3863: }

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

3868:   Not collective

3870:   Input Parameters:
3871: + dm - The DM
3872: . section - The section describing the layout in v, or NULL to use the default section
3873: . v - The local vector
3874: . point - The sieve point in the DM
3875: . csize - The number of values in the closure, or NULL
3876: - values - The array of values, which is a borrowed array and should not be freed

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

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

3884:   Level: intermediate

3886: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3887: @*/
3888: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3889: {
3890:   PetscInt       size = 0;

3894:   /* Should work without recalculating size */
3895:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
3896:   return(0);
3897: }

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

3902: 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[])
3903: {
3904:   PetscInt        cdof;   /* The number of constraints on this point */
3905:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3906:   PetscScalar    *a;
3907:   PetscInt        off, cind = 0, k;
3908:   PetscErrorCode  ierr;

3911:   PetscSectionGetConstraintDof(section, point, &cdof);
3912:   PetscSectionGetOffset(section, point, &off);
3913:   a    = &array[off];
3914:   if (!cdof || setBC) {
3915:     if (clperm) {
3916:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
3917:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
3918:     } else {
3919:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
3920:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
3921:     }
3922:   } else {
3923:     PetscSectionGetConstraintIndices(section, point, &cdofs);
3924:     if (clperm) {
3925:       if (perm) {for (k = 0; k < dof; ++k) {
3926:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3927:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
3928:         }
3929:       } else {
3930:         for (k = 0; k < dof; ++k) {
3931:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3932:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
3933:         }
3934:       }
3935:     } else {
3936:       if (perm) {
3937:         for (k = 0; k < dof; ++k) {
3938:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3939:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
3940:         }
3941:       } else {
3942:         for (k = 0; k < dof; ++k) {
3943:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3944:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
3945:         }
3946:       }
3947:     }
3948:   }
3949:   return(0);
3950: }

3952: 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[])
3953: {
3954:   PetscInt        cdof;   /* The number of constraints on this point */
3955:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3956:   PetscScalar    *a;
3957:   PetscInt        off, cind = 0, k;
3958:   PetscErrorCode  ierr;

3961:   PetscSectionGetConstraintDof(section, point, &cdof);
3962:   PetscSectionGetOffset(section, point, &off);
3963:   a    = &array[off];
3964:   if (cdof) {
3965:     PetscSectionGetConstraintIndices(section, point, &cdofs);
3966:     if (clperm) {
3967:       if (perm) {
3968:         for (k = 0; k < dof; ++k) {
3969:           if ((cind < cdof) && (k == cdofs[cind])) {
3970:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
3971:             cind++;
3972:           }
3973:         }
3974:       } else {
3975:         for (k = 0; k < dof; ++k) {
3976:           if ((cind < cdof) && (k == cdofs[cind])) {
3977:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
3978:             cind++;
3979:           }
3980:         }
3981:       }
3982:     } else {
3983:       if (perm) {
3984:         for (k = 0; k < dof; ++k) {
3985:           if ((cind < cdof) && (k == cdofs[cind])) {
3986:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
3987:             cind++;
3988:           }
3989:         }
3990:       } else {
3991:         for (k = 0; k < dof; ++k) {
3992:           if ((cind < cdof) && (k == cdofs[cind])) {
3993:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
3994:             cind++;
3995:           }
3996:         }
3997:       }
3998:     }
3999:   }
4000:   return(0);
4001: }

4003: 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[])
4004: {
4005:   PetscScalar    *a;
4006:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4007:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4008:   PetscInt        cind = 0, b;
4009:   PetscErrorCode  ierr;

4012:   PetscSectionGetFieldDof(section, point, f, &fdof);
4013:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4014:   PetscSectionGetFieldOffset(section, point, f, &foff);
4015:   a    = &array[foff];
4016:   if (!fcdof || setBC) {
4017:     if (clperm) {
4018:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4019:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4020:     } else {
4021:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4022:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4023:     }
4024:   } else {
4025:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4026:     if (clperm) {
4027:       if (perm) {
4028:         for (b = 0; b < fdof; b++) {
4029:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4030:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4031:         }
4032:       } else {
4033:         for (b = 0; b < fdof; b++) {
4034:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4035:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4036:         }
4037:       }
4038:     } else {
4039:       if (perm) {
4040:         for (b = 0; b < fdof; b++) {
4041:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4042:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4043:         }
4044:       } else {
4045:         for (b = 0; b < fdof; b++) {
4046:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4047:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4048:         }
4049:       }
4050:     }
4051:   }
4052:   *offset += fdof;
4053:   return(0);
4054: }

4056: 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[])
4057: {
4058:   PetscScalar    *a;
4059:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4060:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4061:   PetscInt        cind = 0, b;
4062:   PetscErrorCode  ierr;

4065:   PetscSectionGetFieldDof(section, point, f, &fdof);
4066:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4067:   PetscSectionGetFieldOffset(section, point, f, &foff);
4068:   a    = &array[foff];
4069:   if (fcdof) {
4070:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4071:     if (clperm) {
4072:       if (perm) {
4073:         for (b = 0; b < fdof; b++) {
4074:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4075:             fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4076:             ++cind;
4077:           }
4078:         }
4079:       } else {
4080:         for (b = 0; b < fdof; b++) {
4081:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4082:             fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4083:             ++cind;
4084:           }
4085:         }
4086:       }
4087:     } else {
4088:       if (perm) {
4089:         for (b = 0; b < fdof; b++) {
4090:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4091:             fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4092:             ++cind;
4093:           }
4094:         }
4095:       } else {
4096:         for (b = 0; b < fdof; b++) {
4097:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4098:             fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4099:             ++cind;
4100:           }
4101:         }
4102:       }
4103:     }
4104:   }
4105:   *offset += fdof;
4106:   return(0);
4107: }

4109: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4110: {
4111:   PetscScalar    *array;
4112:   const PetscInt *cone, *coneO;
4113:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4114:   PetscErrorCode  ierr;

4117:   PetscSectionGetChart(section, &pStart, &pEnd);
4118:   DMPlexGetConeSize(dm, point, &numPoints);
4119:   DMPlexGetCone(dm, point, &cone);
4120:   DMPlexGetConeOrientation(dm, point, &coneO);
4121:   VecGetArray(v, &array);
4122:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4123:     const PetscInt cp = !p ? point : cone[p-1];
4124:     const PetscInt o  = !p ? 0     : coneO[p-1];

4126:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4127:     PetscSectionGetDof(section, cp, &dof);
4128:     /* ADD_VALUES */
4129:     {
4130:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4131:       PetscScalar    *a;
4132:       PetscInt        cdof, coff, cind = 0, k;

4134:       PetscSectionGetConstraintDof(section, cp, &cdof);
4135:       PetscSectionGetOffset(section, cp, &coff);
4136:       a    = &array[coff];
4137:       if (!cdof) {
4138:         if (o >= 0) {
4139:           for (k = 0; k < dof; ++k) {
4140:             a[k] += values[off+k];
4141:           }
4142:         } else {
4143:           for (k = 0; k < dof; ++k) {
4144:             a[k] += values[off+dof-k-1];
4145:           }
4146:         }
4147:       } else {
4148:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4149:         if (o >= 0) {
4150:           for (k = 0; k < dof; ++k) {
4151:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4152:             a[k] += values[off+k];
4153:           }
4154:         } else {
4155:           for (k = 0; k < dof; ++k) {
4156:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4157:             a[k] += values[off+dof-k-1];
4158:           }
4159:         }
4160:       }
4161:     }
4162:   }
4163:   VecRestoreArray(v, &array);
4164:   return(0);
4165: }

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

4170:   Not collective

4172:   Input Parameters:
4173: + dm - The DM
4174: . section - The section describing the layout in v, or NULL to use the default section
4175: . v - The local vector
4176: . point - The sieve point in the DM
4177: . values - The array of values
4178: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

4183:   Level: intermediate

4185: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4186: @*/
4187: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4188: {
4189:   PetscSection    clSection;
4190:   IS              clPoints;
4191:   PetscScalar    *array;
4192:   PetscInt       *points = NULL;
4193:   const PetscInt *clp, *clperm;
4194:   PetscInt        depth, numFields, numPoints, p;
4195:   PetscErrorCode  ierr;

4199:   if (!section) {DMGetDefaultSection(dm, &section);}
4202:   DMPlexGetDepth(dm, &depth);
4203:   PetscSectionGetNumFields(section, &numFields);
4204:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4205:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4206:     return(0);
4207:   }
4208:   /* Get points */
4209:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4210:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4211:   /* Get array */
4212:   VecGetArray(v, &array);
4213:   /* Get values */
4214:   if (numFields > 0) {
4215:     PetscInt offset = 0, f;
4216:     for (f = 0; f < numFields; ++f) {
4217:       const PetscInt    **perms = NULL;
4218:       const PetscScalar **flips = NULL;

4220:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4221:       switch (mode) {
4222:       case INSERT_VALUES:
4223:         for (p = 0; p < numPoints; p++) {
4224:           const PetscInt    point = points[2*p];
4225:           const PetscInt    *perm = perms ? perms[p] : NULL;
4226:           const PetscScalar *flip = flips ? flips[p] : NULL;
4227:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4228:         } break;
4229:       case INSERT_ALL_VALUES:
4230:         for (p = 0; p < numPoints; p++) {
4231:           const PetscInt    point = points[2*p];
4232:           const PetscInt    *perm = perms ? perms[p] : NULL;
4233:           const PetscScalar *flip = flips ? flips[p] : NULL;
4234:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4235:         } break;
4236:       case INSERT_BC_VALUES:
4237:         for (p = 0; p < numPoints; p++) {
4238:           const PetscInt    point = points[2*p];
4239:           const PetscInt    *perm = perms ? perms[p] : NULL;
4240:           const PetscScalar *flip = flips ? flips[p] : NULL;
4241:           updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4242:         } break;
4243:       case ADD_VALUES:
4244:         for (p = 0; p < numPoints; p++) {
4245:           const PetscInt    point = points[2*p];
4246:           const PetscInt    *perm = perms ? perms[p] : NULL;
4247:           const PetscScalar *flip = flips ? flips[p] : NULL;
4248:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4249:         } break;
4250:       case ADD_ALL_VALUES:
4251:         for (p = 0; p < numPoints; p++) {
4252:           const PetscInt    point = points[2*p];
4253:           const PetscInt    *perm = perms ? perms[p] : NULL;
4254:           const PetscScalar *flip = flips ? flips[p] : NULL;
4255:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4256:         } break;
4257:       case ADD_BC_VALUES:
4258:         for (p = 0; p < numPoints; p++) {
4259:           const PetscInt    point = points[2*p];
4260:           const PetscInt    *perm = perms ? perms[p] : NULL;
4261:           const PetscScalar *flip = flips ? flips[p] : NULL;
4262:           updatePointFieldsBC_private(section, point, perm, flip, f, add, clperm, values, &offset, array);
4263:         } break;
4264:       default:
4265:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4266:       }
4267:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4268:     }
4269:   } else {
4270:     PetscInt dof, off;
4271:     const PetscInt    **perms = NULL;
4272:     const PetscScalar **flips = NULL;

4274:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4275:     switch (mode) {
4276:     case INSERT_VALUES:
4277:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4278:         const PetscInt    point = points[2*p];
4279:         const PetscInt    *perm = perms ? perms[p] : NULL;
4280:         const PetscScalar *flip = flips ? flips[p] : NULL;
4281:         PetscSectionGetDof(section, point, &dof);
4282:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4283:       } break;
4284:     case INSERT_ALL_VALUES:
4285:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4286:         const PetscInt    point = points[2*p];
4287:         const PetscInt    *perm = perms ? perms[p] : NULL;
4288:         const PetscScalar *flip = flips ? flips[p] : NULL;
4289:         PetscSectionGetDof(section, point, &dof);
4290:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4291:       } break;
4292:     case INSERT_BC_VALUES:
4293:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4294:         const PetscInt    point = points[2*p];
4295:         const PetscInt    *perm = perms ? perms[p] : NULL;
4296:         const PetscScalar *flip = flips ? flips[p] : NULL;
4297:         PetscSectionGetDof(section, point, &dof);
4298:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4299:       } break;
4300:     case ADD_VALUES:
4301:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4302:         const PetscInt    point = points[2*p];
4303:         const PetscInt    *perm = perms ? perms[p] : NULL;
4304:         const PetscScalar *flip = flips ? flips[p] : NULL;
4305:         PetscSectionGetDof(section, point, &dof);
4306:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4307:       } break;
4308:     case ADD_ALL_VALUES:
4309:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4310:         const PetscInt    point = points[2*p];
4311:         const PetscInt    *perm = perms ? perms[p] : NULL;
4312:         const PetscScalar *flip = flips ? flips[p] : NULL;
4313:         PetscSectionGetDof(section, point, &dof);
4314:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4315:       } break;
4316:     case ADD_BC_VALUES:
4317:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4318:         const PetscInt    point = points[2*p];
4319:         const PetscInt    *perm = perms ? perms[p] : NULL;
4320:         const PetscScalar *flip = flips ? flips[p] : NULL;
4321:         PetscSectionGetDof(section, point, &dof);
4322:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4323:       } break;
4324:     default:
4325:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4326:     }
4327:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4328:   }
4329:   /* Cleanup points */
4330:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4331:   /* Cleanup array */
4332:   VecRestoreArray(v, &array);
4333:   return(0);
4334: }

4336: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4337: {
4338:   PetscSection      clSection;
4339:   IS                clPoints;
4340:   PetscScalar       *array;
4341:   PetscInt          *points = NULL;
4342:   const PetscInt    *clp, *clperm;
4343:   PetscInt          numFields, numPoints, p;
4344:   PetscInt          offset = 0, f;
4345:   PetscErrorCode    ierr;

4349:   if (!section) {DMGetDefaultSection(dm, &section);}
4352:   PetscSectionGetNumFields(section, &numFields);
4353:   /* Get points */
4354:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4355:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4356:   /* Get array */
4357:   VecGetArray(v, &array);
4358:   /* Get values */
4359:   for (f = 0; f < numFields; ++f) {
4360:     const PetscInt    **perms = NULL;
4361:     const PetscScalar **flips = NULL;

4363:     if (!fieldActive[f]) {
4364:       for (p = 0; p < numPoints*2; p += 2) {
4365:         PetscInt fdof;
4366:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4367:         offset += fdof;
4368:       }
4369:       continue;
4370:     }
4371:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4372:     switch (mode) {
4373:     case INSERT_VALUES:
4374:       for (p = 0; p < numPoints; p++) {
4375:         const PetscInt    point = points[2*p];
4376:         const PetscInt    *perm = perms ? perms[p] : NULL;
4377:         const PetscScalar *flip = flips ? flips[p] : NULL;
4378:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4379:       } break;
4380:     case INSERT_ALL_VALUES:
4381:       for (p = 0; p < numPoints; p++) {
4382:         const PetscInt    point = points[2*p];
4383:         const PetscInt    *perm = perms ? perms[p] : NULL;
4384:         const PetscScalar *flip = flips ? flips[p] : NULL;
4385:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4386:         } break;
4387:     case INSERT_BC_VALUES:
4388:       for (p = 0; p < numPoints; p++) {
4389:         const PetscInt    point = points[2*p];
4390:         const PetscInt    *perm = perms ? perms[p] : NULL;
4391:         const PetscScalar *flip = flips ? flips[p] : NULL;
4392:         updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4393:       } break;
4394:     case ADD_VALUES:
4395:       for (p = 0; p < numPoints; p++) {
4396:         const PetscInt    point = points[2*p];
4397:         const PetscInt    *perm = perms ? perms[p] : NULL;
4398:         const PetscScalar *flip = flips ? flips[p] : NULL;
4399:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4400:       } break;
4401:     case ADD_ALL_VALUES:
4402:       for (p = 0; p < numPoints; p++) {
4403:         const PetscInt    point = points[2*p];
4404:         const PetscInt    *perm = perms ? perms[p] : NULL;
4405:         const PetscScalar *flip = flips ? flips[p] : NULL;
4406:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4407:       } break;
4408:     default:
4409:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4410:     }
4411:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4412:   }
4413:   /* Cleanup points */
4414:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4415:   /* Cleanup array */
4416:   VecRestoreArray(v, &array);
4417:   return(0);
4418: }

4420: PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4421: {
4422:   PetscMPIInt    rank;
4423:   PetscInt       i, j;

4427:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4428:   PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);
4429:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4430:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4431:   numCIndices = numCIndices ? numCIndices : numRIndices;
4432:   for (i = 0; i < numRIndices; i++) {
4433:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4434:     for (j = 0; j < numCIndices; j++) {
4435: #if defined(PETSC_USE_COMPLEX)
4436:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4437: #else
4438:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4439: #endif
4440:     }
4441:     PetscViewerASCIIPrintf(viewer, "\n");
4442:   }
4443:   return(0);
4444: }

4446: /* . off - The global offset of this point */
4447: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4448: {
4449:   PetscInt        dof;    /* The number of unknowns on this point */
4450:   PetscInt        cdof;   /* The number of constraints on this point */
4451:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4452:   PetscInt        cind = 0, k;
4453:   PetscErrorCode  ierr;

4456:   PetscSectionGetDof(section, point, &dof);
4457:   PetscSectionGetConstraintDof(section, point, &cdof);
4458:   if (!cdof || setBC) {
4459:     if (perm) {
4460:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4461:     } else {
4462:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4463:     }
4464:   } else {
4465:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4466:     if (perm) {
4467:       for (k = 0; k < dof; ++k) {
4468:         if ((cind < cdof) && (k == cdofs[cind])) {
4469:           /* Insert check for returning constrained indices */
4470:           indices[*loff+perm[k]] = -(off+k+1);
4471:           ++cind;
4472:         } else {
4473:           indices[*loff+perm[k]] = off+k-cind;
4474:         }
4475:       }
4476:     } else {
4477:       for (k = 0; k < dof; ++k) {
4478:         if ((cind < cdof) && (k == cdofs[cind])) {
4479:           /* Insert check for returning constrained indices */
4480:           indices[*loff+k] = -(off+k+1);
4481:           ++cind;
4482:         } else {
4483:           indices[*loff+k] = off+k-cind;
4484:         }
4485:       }
4486:     }
4487:   }
4488:   *loff += dof;
4489:   return(0);
4490: }

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

4499:   PetscSectionGetNumFields(section, &numFields);
4500:   for (f = 0, foff = 0; f < numFields; ++f) {
4501:     PetscInt        fdof, cfdof;
4502:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4503:     PetscInt        cind = 0, b;
4504:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4506:     PetscSectionGetFieldDof(section, point, f, &fdof);
4507:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4508:     if (!cfdof || setBC) {
4509:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4510:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4511:     } else {
4512:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4513:       if (perm) {
4514:         for (b = 0; b < fdof; b++) {
4515:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4516:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4517:             ++cind;
4518:           } else {
4519:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4520:           }
4521:         }
4522:       } else {
4523:         for (b = 0; b < fdof; b++) {
4524:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4525:             indices[foffs[f]+b] = -(off+foff+b+1);
4526:             ++cind;
4527:           } else {
4528:             indices[foffs[f]+b] = off+foff+b-cind;
4529:           }
4530:         }
4531:       }
4532:     }
4533:     foff     += (setBC ? fdof : (fdof - cfdof));
4534:     foffs[f] += fdof;
4535:   }
4536:   return(0);
4537: }

4539: 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)
4540: {
4541:   Mat             cMat;
4542:   PetscSection    aSec, cSec;
4543:   IS              aIS;
4544:   PetscInt        aStart = -1, aEnd = -1;
4545:   const PetscInt  *anchors;
4546:   PetscInt        numFields, f, p, q, newP = 0;
4547:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4548:   PetscInt        *newPoints, *indices, *newIndices;
4549:   PetscInt        maxAnchor, maxDof;
4550:   PetscInt        newOffsets[32];
4551:   PetscInt        *pointMatOffsets[32];
4552:   PetscInt        *newPointOffsets[32];
4553:   PetscScalar     *pointMat[32];
4554:   PetscScalar     *newValues=NULL,*tmpValues;
4555:   PetscBool       anyConstrained = PETSC_FALSE;
4556:   PetscErrorCode  ierr;

4561:   PetscSectionGetNumFields(section, &numFields);

4563:   DMPlexGetAnchors(dm,&aSec,&aIS);
4564:   /* if there are point-to-point constraints */
4565:   if (aSec) {
4566:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4567:     ISGetIndices(aIS,&anchors);
4568:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4569:     /* figure out how many points are going to be in the new element matrix
4570:      * (we allow double counting, because it's all just going to be summed
4571:      * into the global matrix anyway) */
4572:     for (p = 0; p < 2*numPoints; p+=2) {
4573:       PetscInt b    = points[p];
4574:       PetscInt bDof = 0, bSecDof;

4576:       PetscSectionGetDof(section,b,&bSecDof);
4577:       if (!bSecDof) {
4578:         continue;
4579:       }
4580:       if (b >= aStart && b < aEnd) {
4581:         PetscSectionGetDof(aSec,b,&bDof);
4582:       }
4583:       if (bDof) {
4584:         /* this point is constrained */
4585:         /* it is going to be replaced by its anchors */
4586:         PetscInt bOff, q;

4588:         anyConstrained = PETSC_TRUE;
4589:         newNumPoints  += bDof;
4590:         PetscSectionGetOffset(aSec,b,&bOff);
4591:         for (q = 0; q < bDof; q++) {
4592:           PetscInt a = anchors[bOff + q];
4593:           PetscInt aDof;

4595:           PetscSectionGetDof(section,a,&aDof);
4596:           newNumIndices += aDof;
4597:           for (f = 0; f < numFields; ++f) {
4598:             PetscInt fDof;

4600:             PetscSectionGetFieldDof(section, a, f, &fDof);
4601:             newOffsets[f+1] += fDof;
4602:           }
4603:         }
4604:       }
4605:       else {
4606:         /* this point is not constrained */
4607:         newNumPoints++;
4608:         newNumIndices += bSecDof;
4609:         for (f = 0; f < numFields; ++f) {
4610:           PetscInt fDof;

4612:           PetscSectionGetFieldDof(section, b, f, &fDof);
4613:           newOffsets[f+1] += fDof;
4614:         }
4615:       }
4616:     }
4617:   }
4618:   if (!anyConstrained) {
4619:     if (outNumPoints)  *outNumPoints  = 0;
4620:     if (outNumIndices) *outNumIndices = 0;
4621:     if (outPoints)     *outPoints     = NULL;
4622:     if (outValues)     *outValues     = NULL;
4623:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4624:     return(0);
4625:   }

4627:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4628:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4632:   if (!outPoints && !outValues) {
4633:     if (offsets) {
4634:       for (f = 0; f <= numFields; f++) {
4635:         offsets[f] = newOffsets[f];
4636:       }
4637:     }
4638:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4639:     return(0);
4640:   }

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

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

4646:   /* workspaces */
4647:   if (numFields) {
4648:     for (f = 0; f < numFields; f++) {
4649:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4650:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4651:     }
4652:   }
4653:   else {
4654:     DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4655:     DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
4656:   }

4658:   /* get workspaces for the point-to-point matrices */
4659:   if (numFields) {
4660:     PetscInt totalOffset, totalMatOffset;

4662:     for (p = 0; p < numPoints; p++) {
4663:       PetscInt b    = points[2*p];
4664:       PetscInt bDof = 0, bSecDof;

4666:       PetscSectionGetDof(section,b,&bSecDof);
4667:       if (!bSecDof) {
4668:         for (f = 0; f < numFields; f++) {
4669:           newPointOffsets[f][p + 1] = 0;
4670:           pointMatOffsets[f][p + 1] = 0;
4671:         }
4672:         continue;
4673:       }
4674:       if (b >= aStart && b < aEnd) {
4675:         PetscSectionGetDof(aSec, b, &bDof);
4676:       }
4677:       if (bDof) {
4678:         for (f = 0; f < numFields; f++) {
4679:           PetscInt fDof, q, bOff, allFDof = 0;

4681:           PetscSectionGetFieldDof(section, b, f, &fDof);
4682:           PetscSectionGetOffset(aSec, b, &bOff);
4683:           for (q = 0; q < bDof; q++) {
4684:             PetscInt a = anchors[bOff + q];
4685:             PetscInt aFDof;

4687:             PetscSectionGetFieldDof(section, a, f, &aFDof);
4688:             allFDof += aFDof;
4689:           }
4690:           newPointOffsets[f][p+1] = allFDof;
4691:           pointMatOffsets[f][p+1] = fDof * allFDof;
4692:         }
4693:       }
4694:       else {
4695:         for (f = 0; f < numFields; f++) {
4696:           PetscInt fDof;

4698:           PetscSectionGetFieldDof(section, b, f, &fDof);
4699:           newPointOffsets[f][p+1] = fDof;
4700:           pointMatOffsets[f][p+1] = 0;
4701:         }
4702:       }
4703:     }
4704:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4705:       newPointOffsets[f][0] = totalOffset;
4706:       pointMatOffsets[f][0] = totalMatOffset;
4707:       for (p = 0; p < numPoints; p++) {
4708:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4709:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4710:       }
4711:       totalOffset    = newPointOffsets[f][numPoints];
4712:       totalMatOffset = pointMatOffsets[f][numPoints];
4713:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4714:     }
4715:   }
4716:   else {
4717:     for (p = 0; p < numPoints; p++) {
4718:       PetscInt b    = points[2*p];
4719:       PetscInt bDof = 0, bSecDof;

4721:       PetscSectionGetDof(section,b,&bSecDof);
4722:       if (!bSecDof) {
4723:         newPointOffsets[0][p + 1] = 0;
4724:         pointMatOffsets[0][p + 1] = 0;
4725:         continue;
4726:       }
4727:       if (b >= aStart && b < aEnd) {
4728:         PetscSectionGetDof(aSec, b, &bDof);
4729:       }
4730:       if (bDof) {
4731:         PetscInt bOff, q, allDof = 0;

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

4737:           PetscSectionGetDof(section, a, &aDof);
4738:           allDof += aDof;
4739:         }
4740:         newPointOffsets[0][p+1] = allDof;
4741:         pointMatOffsets[0][p+1] = bSecDof * allDof;
4742:       }
4743:       else {
4744:         newPointOffsets[0][p+1] = bSecDof;
4745:         pointMatOffsets[0][p+1] = 0;
4746:       }
4747:     }
4748:     newPointOffsets[0][0] = 0;
4749:     pointMatOffsets[0][0] = 0;
4750:     for (p = 0; p < numPoints; p++) {
4751:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4752:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4753:     }
4754:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4755:   }

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

4760:   /* get the point-to-point matrices; construct newPoints */
4761:   PetscSectionGetMaxDof(aSec, &maxAnchor);
4762:   PetscSectionGetMaxDof(section, &maxDof);
4763:   DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
4764:   DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
4765:   if (numFields) {
4766:     for (p = 0, newP = 0; p < numPoints; p++) {
4767:       PetscInt b    = points[2*p];
4768:       PetscInt o    = points[2*p+1];
4769:       PetscInt bDof = 0, bSecDof;

4771:       PetscSectionGetDof(section, b, &bSecDof);
4772:       if (!bSecDof) {
4773:         continue;
4774:       }
4775:       if (b >= aStart && b < aEnd) {
4776:         PetscSectionGetDof(aSec, b, &bDof);
4777:       }
4778:       if (bDof) {
4779:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

4781:         fStart[0] = 0;
4782:         fEnd[0]   = 0;
4783:         for (f = 0; f < numFields; f++) {
4784:           PetscInt fDof;

4786:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
4787:           fStart[f+1] = fStart[f] + fDof;
4788:           fEnd[f+1]   = fStart[f+1];
4789:         }
4790:         PetscSectionGetOffset(cSec, b, &bOff);
4791:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

4793:         fAnchorStart[0] = 0;
4794:         fAnchorEnd[0]   = 0;
4795:         for (f = 0; f < numFields; f++) {
4796:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

4798:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4799:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4800:         }
4801:         PetscSectionGetOffset(aSec, b, &bOff);
4802:         for (q = 0; q < bDof; q++) {
4803:           PetscInt a = anchors[bOff + q], aOff;

4805:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4806:           newPoints[2*(newP + q)]     = a;
4807:           newPoints[2*(newP + q) + 1] = 0;
4808:           PetscSectionGetOffset(section, a, &aOff);
4809:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
4810:         }
4811:         newP += bDof;

4813:         if (outValues) {
4814:           /* get the point-to-point submatrix */
4815:           for (f = 0; f < numFields; f++) {
4816:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
4817:           }
4818:         }
4819:       }
4820:       else {
4821:         newPoints[2 * newP]     = b;
4822:         newPoints[2 * newP + 1] = o;
4823:         newP++;
4824:       }
4825:     }
4826:   } else {
4827:     for (p = 0; p < numPoints; p++) {
4828:       PetscInt b    = points[2*p];
4829:       PetscInt o    = points[2*p+1];
4830:       PetscInt bDof = 0, bSecDof;

4832:       PetscSectionGetDof(section, b, &bSecDof);
4833:       if (!bSecDof) {
4834:         continue;
4835:       }
4836:       if (b >= aStart && b < aEnd) {
4837:         PetscSectionGetDof(aSec, b, &bDof);
4838:       }
4839:       if (bDof) {
4840:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

4851:           newPoints[2*(newP + q)]     = a;
4852:           newPoints[2*(newP + q) + 1] = 0;
4853:           PetscSectionGetOffset(section, a, &aOff);
4854:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
4855:         }
4856:         newP += bDof;

4858:         /* get the point-to-point submatrix */
4859:         if (outValues) {
4860:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
4861:         }
4862:       }
4863:       else {
4864:         newPoints[2 * newP]     = b;
4865:         newPoints[2 * newP + 1] = o;
4866:         newP++;
4867:       }
4868:     }
4869:   }

4871:   if (outValues) {
4872:     DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
4873:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
4874:     /* multiply constraints on the right */
4875:     if (numFields) {
4876:       for (f = 0; f < numFields; f++) {
4877:         PetscInt oldOff = offsets[f];

4879:         for (p = 0; p < numPoints; p++) {
4880:           PetscInt cStart = newPointOffsets[f][p];
4881:           PetscInt b      = points[2 * p];
4882:           PetscInt c, r, k;
4883:           PetscInt dof;

4885:           PetscSectionGetFieldDof(section,b,f,&dof);
4886:           if (!dof) {
4887:             continue;
4888:           }
4889:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4890:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
4891:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

4893:             for (r = 0; r < numIndices; r++) {
4894:               for (c = 0; c < nCols; c++) {
4895:                 for (k = 0; k < dof; k++) {
4896:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
4897:                 }
4898:               }
4899:             }
4900:           }
4901:           else {
4902:             /* copy this column as is */
4903:             for (r = 0; r < numIndices; r++) {
4904:               for (c = 0; c < dof; c++) {
4905:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4906:               }
4907:             }
4908:           }
4909:           oldOff += dof;
4910:         }
4911:       }
4912:     }
4913:     else {
4914:       PetscInt oldOff = 0;
4915:       for (p = 0; p < numPoints; p++) {
4916:         PetscInt cStart = newPointOffsets[0][p];
4917:         PetscInt b      = points[2 * p];
4918:         PetscInt c, r, k;
4919:         PetscInt dof;

4921:         PetscSectionGetDof(section,b,&dof);
4922:         if (!dof) {
4923:           continue;
4924:         }
4925:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4926:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
4927:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

4929:           for (r = 0; r < numIndices; r++) {
4930:             for (c = 0; c < nCols; c++) {
4931:               for (k = 0; k < dof; k++) {
4932:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
4933:               }
4934:             }
4935:           }
4936:         }
4937:         else {
4938:           /* copy this column as is */
4939:           for (r = 0; r < numIndices; r++) {
4940:             for (c = 0; c < dof; c++) {
4941:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4942:             }
4943:           }
4944:         }
4945:         oldOff += dof;
4946:       }
4947:     }

4949:     if (multiplyLeft) {
4950:       DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
4951:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
4952:       /* multiply constraints transpose on the left */
4953:       if (numFields) {
4954:         for (f = 0; f < numFields; f++) {
4955:           PetscInt oldOff = offsets[f];

4957:           for (p = 0; p < numPoints; p++) {
4958:             PetscInt rStart = newPointOffsets[f][p];
4959:             PetscInt b      = points[2 * p];
4960:             PetscInt c, r, k;
4961:             PetscInt dof;

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

4968:               for (r = 0; r < nRows; r++) {
4969:                 for (c = 0; c < newNumIndices; c++) {
4970:                   for (k = 0; k < dof; k++) {
4971:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
4972:                   }
4973:                 }
4974:               }
4975:             }
4976:             else {
4977:               /* copy this row as is */
4978:               for (r = 0; r < dof; r++) {
4979:                 for (c = 0; c < newNumIndices; c++) {
4980:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
4981:                 }
4982:               }
4983:             }
4984:             oldOff += dof;
4985:           }
4986:         }
4987:       }
4988:       else {
4989:         PetscInt oldOff = 0;

4991:         for (p = 0; p < numPoints; p++) {
4992:           PetscInt rStart = newPointOffsets[0][p];
4993:           PetscInt b      = points[2 * p];
4994:           PetscInt c, r, k;
4995:           PetscInt dof;

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

5002:             for (r = 0; r < nRows; r++) {
5003:               for (c = 0; c < newNumIndices; c++) {
5004:                 for (k = 0; k < dof; k++) {
5005:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5006:                 }
5007:               }
5008:             }
5009:           }
5010:           else {
5011:             /* copy this row as is */
5012:             for (r = 0; r < dof; r++) {
5013:               for (c = 0; c < newNumIndices; c++) {
5014:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5015:               }
5016:             }
5017:           }
5018:           oldOff += dof;
5019:         }
5020:       }

5022:       DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5023:     }
5024:     else {
5025:       newValues = tmpValues;
5026:     }
5027:   }

5029:   /* clean up */
5030:   DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
5031:   DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);

5033:   if (numFields) {
5034:     for (f = 0; f < numFields; f++) {
5035:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
5036:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
5037:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
5038:     }
5039:   }
5040:   else {
5041:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
5042:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
5043:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
5044:   }
5045:   ISRestoreIndices(aIS,&anchors);

5047:   /* output */
5048:   if (outPoints) {
5049:     *outPoints = newPoints;
5050:   }
5051:   else {
5052:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5053:   }
5054:   if (outValues) {
5055:     *outValues = newValues;
5056:   }
5057:   for (f = 0; f <= numFields; f++) {
5058:     offsets[f] = newOffsets[f];
5059:   }
5060:   return(0);
5061: }

5063: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5064: {
5065:   PetscSection    clSection;
5066:   IS              clPoints;
5067:   const PetscInt *clp;
5068:   const PetscInt  **perms[32] = {NULL};
5069:   PetscInt       *points = NULL, *pointsNew;
5070:   PetscInt        numPoints, numPointsNew;
5071:   PetscInt        offsets[32];
5072:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5073:   PetscErrorCode  ierr;

5081:   PetscSectionGetNumFields(section, &Nf);
5082:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5083:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5084:   /* Get points in closure */
5085:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5086:   /* Get number of indices and indices per field */
5087:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5088:     PetscInt dof, fdof;

5090:     PetscSectionGetDof(section, points[p], &dof);
5091:     for (f = 0; f < Nf; ++f) {
5092:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5093:       offsets[f+1] += fdof;
5094:     }
5095:     Nind += dof;
5096:   }
5097:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5098:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5099:   if (!Nf) offsets[1] = Nind;
5100:   /* Get dual space symmetries */
5101:   for (f = 0; f < PetscMax(1,Nf); f++) {
5102:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5103:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5104:   }
5105:   /* Correct for hanging node constraints */
5106:   {
5107:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5108:     if (numPointsNew) {
5109:       for (f = 0; f < PetscMax(1,Nf); f++) {
5110:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5111:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5112:       }
5113:       for (f = 0; f < PetscMax(1,Nf); f++) {
5114:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5115:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5116:       }
5117:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5118:       numPoints = numPointsNew;
5119:       Nind      = NindNew;
5120:       points    = pointsNew;
5121:     }
5122:   }
5123:   /* Calculate indices */
5124:   DMGetWorkArray(dm, Nind, PETSC_INT, indices);
5125:   if (Nf) {
5126:     if (outOffsets) {
5127:       PetscInt f;

5129:       for (f = 0; f <= Nf; f++) {
5130:         outOffsets[f] = offsets[f];
5131:       }
5132:     }
5133:     for (p = 0; p < numPoints; p++) {
5134:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5135:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5136:     }
5137:   } else {
5138:     for (p = 0, off = 0; p < numPoints; p++) {
5139:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5141:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5142:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5143:     }
5144:   }
5145:   /* Cleanup points */
5146:   for (f = 0; f < PetscMax(1,Nf); f++) {
5147:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5148:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5149:   }
5150:   if (numPointsNew) {
5151:     DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);
5152:   } else {
5153:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5154:   }
5155:   if (numIndices) *numIndices = Nind;
5156:   return(0);
5157: }

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

5166:   DMRestoreWorkArray(dm, 0, PETSC_INT, indices);
5167:   return(0);
5168: }

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

5173:   Not collective

5175:   Input Parameters:
5176: + dm - The DM
5177: . section - The section describing the layout in v, or NULL to use the default section
5178: . globalSection - The section describing the layout in v, or NULL to use the default global section
5179: . A - The matrix
5180: . point - The sieve point in the DM
5181: . values - The array of values
5182: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5187:   Level: intermediate

5189: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5190: @*/
5191: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5192: {
5193:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5194:   PetscSection        clSection;
5195:   IS                  clPoints;
5196:   PetscInt           *points = NULL, *newPoints;
5197:   const PetscInt     *clp;
5198:   PetscInt           *indices;
5199:   PetscInt            offsets[32];
5200:   const PetscInt    **perms[32] = {NULL};
5201:   const PetscScalar **flips[32] = {NULL};
5202:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5203:   PetscScalar        *valCopy = NULL;
5204:   PetscScalar        *newValues;
5205:   PetscErrorCode      ierr;

5209:   if (!section) {DMGetDefaultSection(dm, &section);}
5211:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5214:   PetscSectionGetNumFields(section, &numFields);
5215:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5216:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5217:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5218:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5219:     PetscInt fdof;

5221:     PetscSectionGetDof(section, points[p], &dof);
5222:     for (f = 0; f < numFields; ++f) {
5223:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5224:       offsets[f+1] += fdof;
5225:     }
5226:     numIndices += dof;
5227:   }
5228:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5242:         if (!numFields) {
5243:           PetscSectionGetDof(section,point,&fdof);
5244:         } else {
5245:           PetscSectionGetFieldDof(section,point,f,&fdof);
5246:         }
5247:         if (flip) {
5248:           PetscInt i, j, k;

5250:           if (!valCopy) {
5251:             DMGetWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5252:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5253:             values = valCopy;
5254:           }
5255:           for (i = 0; i < fdof; i++) {
5256:             PetscScalar fval = flip[i];

5258:             for (k = 0; k < numIndices; k++) {
5259:               valCopy[numIndices * (foffset + i) + k] *= fval;
5260:               valCopy[numIndices * k + (foffset + i)] *= fval;
5261:             }
5262:           }
5263:         }
5264:         foffset += fdof;
5265:       }
5266:     }
5267:   }
5268:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5269:   if (newNumPoints) {
5270:     if (valCopy) {
5271:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5272:     }
5273:     for (f = 0; f < PetscMax(1,numFields); f++) {
5274:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5275:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5276:     }
5277:     for (f = 0; f < PetscMax(1,numFields); f++) {
5278:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5279:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5280:     }
5281:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5282:     numPoints  = newNumPoints;
5283:     numIndices = newNumIndices;
5284:     points     = newPoints;
5285:     values     = newValues;
5286:   }
5287:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5288:   if (numFields) {
5289:     for (p = 0; p < numPoints; p++) {
5290:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5291:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5292:     }
5293:   } else {
5294:     for (p = 0, off = 0; p < numPoints; p++) {
5295:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5296:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5297:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5298:     }
5299:   }
5300:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5301:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5302:   if (mesh->printFEM > 1) {
5303:     PetscInt i;
5304:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5305:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5306:     PetscPrintf(PETSC_COMM_SELF, "\n");
5307:   }
5308:   if (ierr) {
5309:     PetscMPIInt    rank;
5310:     PetscErrorCode ierr2;

5312:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5313:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5314:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5315:     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5316: 
5317:   }
5318:   for (f = 0; f < PetscMax(1,numFields); f++) {
5319:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5320:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5321:   }
5322:   if (newNumPoints) {
5323:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5324:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5325:   }
5326:   else {
5327:     if (valCopy) {
5328:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5329:     }
5330:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5331:   }
5332:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5333:   return(0);
5334: }

5336: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5337: {
5338:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5339:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5340:   PetscInt       *cpoints = NULL;
5341:   PetscInt       *findices, *cindices;
5342:   PetscInt        foffsets[32], coffsets[32];
5343:   CellRefiner     cellRefiner;
5344:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5345:   PetscErrorCode  ierr;

5350:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5352:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5354:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5356:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5359:   PetscSectionGetNumFields(fsection, &numFields);
5360:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5361:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5362:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5363:   /* Column indices */
5364:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5365:   maxFPoints = numCPoints;
5366:   /* Compress out points not in the section */
5367:   /*   TODO: Squeeze out points with 0 dof as well */
5368:   PetscSectionGetChart(csection, &pStart, &pEnd);
5369:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5370:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5371:       cpoints[q*2]   = cpoints[p];
5372:       cpoints[q*2+1] = cpoints[p+1];
5373:       ++q;
5374:     }
5375:   }
5376:   numCPoints = q;
5377:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5378:     PetscInt fdof;

5380:     PetscSectionGetDof(csection, cpoints[p], &dof);
5381:     if (!dof) continue;
5382:     for (f = 0; f < numFields; ++f) {
5383:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5384:       coffsets[f+1] += fdof;
5385:     }
5386:     numCIndices += dof;
5387:   }
5388:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5389:   /* Row indices */
5390:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5391:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5392:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5393:   for (r = 0, q = 0; r < numSubcells; ++r) {
5394:     /* TODO Map from coarse to fine cells */
5395:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5396:     /* Compress out points not in the section */
5397:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5398:     for (p = 0; p < numFPoints*2; p += 2) {
5399:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5400:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5401:         if (!dof) continue;
5402:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5403:         if (s < q) continue;
5404:         ftotpoints[q*2]   = fpoints[p];
5405:         ftotpoints[q*2+1] = fpoints[p+1];
5406:         ++q;
5407:       }
5408:     }
5409:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5410:   }
5411:   numFPoints = q;
5412:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5413:     PetscInt fdof;

5415:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5416:     if (!dof) continue;
5417:     for (f = 0; f < numFields; ++f) {
5418:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5419:       foffsets[f+1] += fdof;
5420:     }
5421:     numFIndices += dof;
5422:   }
5423:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5425:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5426:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5427:   DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5428:   DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5429:   if (numFields) {
5430:     const PetscInt **permsF[32] = {NULL};
5431:     const PetscInt **permsC[32] = {NULL};

5433:     for (f = 0; f < numFields; f++) {
5434:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5435:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5436:     }
5437:     for (p = 0; p < numFPoints; p++) {
5438:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5439:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5440:     }
5441:     for (p = 0; p < numCPoints; p++) {
5442:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5443:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5444:     }
5445:     for (f = 0; f < numFields; f++) {
5446:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5447:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5448:     }
5449:   } else {
5450:     const PetscInt **permsF = NULL;
5451:     const PetscInt **permsC = NULL;

5453:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5454:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5455:     for (p = 0, off = 0; p < numFPoints; p++) {
5456:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5458:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5459:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5460:     }
5461:     for (p = 0, off = 0; p < numCPoints; p++) {
5462:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5464:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5465:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5466:     }
5467:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5468:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5469:   }
5470:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5471:   /* TODO: flips */
5472:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5473:   if (ierr) {
5474:     PetscMPIInt    rank;
5475:     PetscErrorCode ierr2;

5477:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5478:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5479:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5480:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5481:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5482: 
5483:   }
5484:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5485:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5486:   DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5487:   DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5488:   return(0);
5489: }

5491: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5492: {
5493:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5494:   PetscInt      *cpoints = NULL;
5495:   PetscInt       foffsets[32], coffsets[32];
5496:   CellRefiner    cellRefiner;
5497:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

5503:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5505:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5507:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5509:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5511:   PetscSectionGetNumFields(fsection, &numFields);
5512:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5513:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5514:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5515:   /* Column indices */
5516:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5517:   maxFPoints = numCPoints;
5518:   /* Compress out points not in the section */
5519:   /*   TODO: Squeeze out points with 0 dof as well */
5520:   PetscSectionGetChart(csection, &pStart, &pEnd);
5521:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5522:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5523:       cpoints[q*2]   = cpoints[p];
5524:       cpoints[q*2+1] = cpoints[p+1];
5525:       ++q;
5526:     }
5527:   }
5528:   numCPoints = q;
5529:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5530:     PetscInt fdof;

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

5567:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5568:     if (!dof) continue;
5569:     for (f = 0; f < numFields; ++f) {
5570:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5571:       foffsets[f+1] += fdof;
5572:     }
5573:     numFIndices += dof;
5574:   }
5575:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

5583:     for (f = 0; f < numFields; f++) {
5584:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5585:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5586:     }
5587:     for (p = 0; p < numFPoints; p++) {
5588:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5589:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5590:     }
5591:     for (p = 0; p < numCPoints; p++) {
5592:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5593:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5594:     }
5595:     for (f = 0; f < numFields; f++) {
5596:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5597:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5598:     }
5599:   } else {
5600:     const PetscInt **permsF = NULL;
5601:     const PetscInt **permsC = NULL;

5603:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5604:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5605:     for (p = 0, off = 0; p < numFPoints; p++) {
5606:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5608:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5609:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5610:     }
5611:     for (p = 0, off = 0; p < numCPoints; p++) {
5612:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5614:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5615:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5616:     }
5617:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5618:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5619:   }
5620:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5621:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5622:   return(0);
5623: }

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

5628:   Input Parameter:
5629: . dm - The DMPlex object

5631:   Output Parameters:
5632: + cMax - The first hybrid cell
5633: . fMax - The first hybrid face
5634: . eMax - The first hybrid edge
5635: - vMax - The first hybrid vertex

5637:   Level: developer

5639: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5640: @*/
5641: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5642: {
5643:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5644:   PetscInt       dim;

5649:   DMGetDimension(dm, &dim);
5650:   if (cMax) *cMax = mesh->hybridPointMax[dim];
5651:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5652:   if (eMax) *eMax = mesh->hybridPointMax[1];
5653:   if (vMax) *vMax = mesh->hybridPointMax[0];
5654:   return(0);
5655: }

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

5660:   Input Parameters:
5661: . dm   - The DMPlex object
5662: . cMax - The first hybrid cell
5663: . fMax - The first hybrid face
5664: . eMax - The first hybrid edge
5665: - vMax - The first hybrid vertex

5667:   Level: developer

5669: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5670: @*/
5671: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5672: {
5673:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5674:   PetscInt       dim;

5679:   DMGetDimension(dm, &dim);
5680:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5681:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5682:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5683:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5684:   return(0);
5685: }

5687: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5688: {
5689:   DM_Plex *mesh = (DM_Plex*) dm->data;

5694:   *cellHeight = mesh->vtkCellHeight;
5695:   return(0);
5696: }

5698: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5699: {
5700:   DM_Plex *mesh = (DM_Plex*) dm->data;

5704:   mesh->vtkCellHeight = cellHeight;
5705:   return(0);
5706: }

5708: /* We can easily have a form that takes an IS instead */
5709: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5710: {
5711:   PetscSection   section, globalSection;
5712:   PetscInt      *numbers, p;

5716:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
5717:   PetscSectionSetChart(section, pStart, pEnd);
5718:   for (p = pStart; p < pEnd; ++p) {
5719:     PetscSectionSetDof(section, p, 1);
5720:   }
5721:   PetscSectionSetUp(section);
5722:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
5723:   PetscMalloc1(pEnd - pStart, &numbers);
5724:   for (p = pStart; p < pEnd; ++p) {
5725:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5726:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5727:     else                       numbers[p-pStart] += shift;
5728:   }
5729:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5730:   if (globalSize) {
5731:     PetscLayout layout;
5732:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
5733:     PetscLayoutGetSize(layout, globalSize);
5734:     PetscLayoutDestroy(&layout);
5735:   }
5736:   PetscSectionDestroy(&section);
5737:   PetscSectionDestroy(&globalSection);
5738:   return(0);
5739: }

5741: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5742: {
5743:   PetscInt       cellHeight, cStart, cEnd, cMax;

5747:   DMPlexGetVTKCellHeight(dm, &cellHeight);
5748:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5749:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5750:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5751:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
5752:   return(0);
5753: }

5755: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5756: {
5757:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5762:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
5763:   *globalCellNumbers = mesh->globalCellNumbers;
5764:   return(0);
5765: }

5767: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
5768: {
5769:   PetscInt       vStart, vEnd, vMax;

5774:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5775:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
5776:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
5777:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
5778:   return(0);
5779: }

5781: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5782: {
5783:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5788:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
5789:   *globalVertexNumbers = mesh->globalVertexNumbers;
5790:   return(0);
5791: }

5793: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
5794: {
5795:   IS             nums[4];
5796:   PetscInt       depths[4];
5797:   PetscInt       depth, d, shift = 0;

5802:   DMPlexGetDepth(dm, &depth);
5803:   /* For unstratified meshes use dim instead of depth */
5804:   if (depth < 0) {DMGetDimension(dm, &depth);}
5805:   depths[0] = depth; depths[1] = 0;
5806:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
5807:   for (d = 0; d <= depth; ++d) {
5808:     PetscInt pStart, pEnd, gsize;

5810:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
5811:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
5812:     shift += gsize;
5813:   }
5814:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
5815:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
5816:   return(0);
5817: }

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

5822:   Input Parameters:
5823:   + dm - The DMPlex object

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

5827:   Level: developer

5829: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5830: @*/
5831: PetscErrorCode DMPlexCheckSymmetry(DM dm)
5832: {
5833:   PetscSection    coneSection, supportSection;
5834:   const PetscInt *cone, *support;
5835:   PetscInt        coneSize, c, supportSize, s;
5836:   PetscInt        pStart, pEnd, p, csize, ssize;
5837:   PetscErrorCode  ierr;

5841:   DMPlexGetConeSection(dm, &coneSection);
5842:   DMPlexGetSupportSection(dm, &supportSection);
5843:   /* Check that point p is found in the support of its cone points, and vice versa */
5844:   DMPlexGetChart(dm, &pStart, &pEnd);
5845:   for (p = pStart; p < pEnd; ++p) {
5846:     DMPlexGetConeSize(dm, p, &coneSize);
5847:     DMPlexGetCone(dm, p, &cone);
5848:     for (c = 0; c < coneSize; ++c) {
5849:       PetscBool dup = PETSC_FALSE;
5850:       PetscInt  d;
5851:       for (d = c-1; d >= 0; --d) {
5852:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5853:       }
5854:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
5855:       DMPlexGetSupport(dm, cone[c], &support);
5856:       for (s = 0; s < supportSize; ++s) {
5857:         if (support[s] == p) break;
5858:       }
5859:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5860:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
5861:         for (s = 0; s < coneSize; ++s) {
5862:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
5863:         }
5864:         PetscPrintf(PETSC_COMM_SELF, "\n");
5865:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
5866:         for (s = 0; s < supportSize; ++s) {
5867:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
5868:         }
5869:         PetscPrintf(PETSC_COMM_SELF, "\n");
5870:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
5871:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
5872:       }
5873:     }
5874:     DMPlexGetSupportSize(dm, p, &supportSize);
5875:     DMPlexGetSupport(dm, p, &support);
5876:     for (s = 0; s < supportSize; ++s) {
5877:       DMPlexGetConeSize(dm, support[s], &coneSize);
5878:       DMPlexGetCone(dm, support[s], &cone);
5879:       for (c = 0; c < coneSize; ++c) {
5880:         if (cone[c] == p) break;
5881:       }
5882:       if (c >= coneSize) {
5883:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
5884:         for (c = 0; c < supportSize; ++c) {
5885:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
5886:         }
5887:         PetscPrintf(PETSC_COMM_SELF, "\n");
5888:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
5889:         for (c = 0; c < coneSize; ++c) {
5890:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
5891:         }
5892:         PetscPrintf(PETSC_COMM_SELF, "\n");
5893:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
5894:       }
5895:     }
5896:   }
5897:   PetscSectionGetStorageSize(coneSection, &csize);
5898:   PetscSectionGetStorageSize(supportSection, &ssize);
5899:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
5900:   return(0);
5901: }

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

5906:   Input Parameters:
5907: + dm - The DMPlex object
5908: . isSimplex - Are the cells simplices or tensor products
5909: - cellHeight - Normally 0

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

5913:   Level: developer

5915: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
5916: @*/
5917: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5918: {
5919:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

5924:   DMGetDimension(dm, &dim);
5925:   switch (dim) {
5926:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
5927:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
5928:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
5929:   default:
5930:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
5931:   }
5932:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5933:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5934:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5935:   cMax = cMax >= 0 ? cMax : cEnd;
5936:   for (c = cStart; c < cMax; ++c) {
5937:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

5939:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5940:     for (cl = 0; cl < closureSize*2; cl += 2) {
5941:       const PetscInt p = closure[cl];
5942:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5943:     }
5944:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5945:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
5946:   }
5947:   for (c = cMax; c < cEnd; ++c) {
5948:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

5950:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5951:     for (cl = 0; cl < closureSize*2; cl += 2) {
5952:       const PetscInt p = closure[cl];
5953:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5954:     }
5955:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5956:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
5957:   }
5958:   return(0);
5959: }

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

5964:   Input Parameters:
5965: + dm - The DMPlex object
5966: . isSimplex - Are the cells simplices or tensor products
5967: - cellHeight - Normally 0

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

5971:   Level: developer

5973: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
5974: @*/
5975: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5976: {
5977:   PetscInt       pMax[4];
5978:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

5983:   DMGetDimension(dm, &dim);
5984:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5985:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
5986:   for (h = cellHeight; h < dim; ++h) {
5987:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
5988:     for (c = cStart; c < cEnd; ++c) {
5989:       const PetscInt *cone, *ornt, *faces;
5990:       PetscInt        numFaces, faceSize, coneSize,f;
5991:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

5993:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
5994:       DMPlexGetConeSize(dm, c, &coneSize);
5995:       DMPlexGetCone(dm, c, &cone);
5996:       DMPlexGetConeOrientation(dm, c, &ornt);
5997:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5998:       for (cl = 0; cl < closureSize*2; cl += 2) {
5999:         const PetscInt p = closure[cl];
6000:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6001:       }
6002:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6003:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6004:       for (f = 0; f < numFaces; ++f) {
6005:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6007:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6008:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6009:           const PetscInt p = fclosure[cl];
6010:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6011:         }
6012:         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);
6013:         for (v = 0; v < fnumCorners; ++v) {
6014:           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]);
6015:         }
6016:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6017:       }
6018:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6019:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6020:     }
6021:   }
6022:   return(0);
6023: }

6025: /* Pointwise interpolation
6026:      Just code FEM for now
6027:      u^f = I u^c
6028:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6029:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6030:      I_{ij} = psi^f_i phi^c_j
6031: */
6032: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6033: {
6034:   PetscSection   gsc, gsf;
6035:   PetscInt       m, n;
6036:   void          *ctx;
6037:   DM             cdm;
6038:   PetscBool      regular;

6042:   DMGetDefaultGlobalSection(dmFine, &gsf);
6043:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6044:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6045:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6047:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6048:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6049:   MatSetType(*interpolation, dmCoarse->mattype);
6050:   DMGetApplicationContext(dmFine, &ctx);

6052:   DMGetCoarseDM(dmFine, &cdm);
6053:   DMPlexGetRegularRefinement(dmFine, &regular);
6054:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6055:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6056:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6057:   /* Use naive scaling */
6058:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6059:   return(0);
6060: }

6062: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6063: {
6065:   VecScatter     ctx;

6068:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6069:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6070:   VecScatterDestroy(&ctx);
6071:   return(0);
6072: }

6074: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6075: {
6076:   PetscSection   section;
6077:   IS            *bcPoints, *bcComps;
6078:   PetscBool     *isFE;
6079:   PetscInt      *bcFields, *numComp, *numDof;
6080:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6081:   PetscInt       cStart, cEnd, cEndInterior;

6085:   DMGetNumFields(dm, &numFields);
6086:   if (!numFields) return(0);
6087:   /* FE and FV boundary conditions are handled slightly differently */
6088:   PetscMalloc1(numFields, &isFE);
6089:   for (f = 0; f < numFields; ++f) {
6090:     PetscObject  obj;
6091:     PetscClassId id;

6093:     DMGetField(dm, f, &obj);
6094:     PetscObjectGetClassId(obj, &id);
6095:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6096:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6097:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6098:   }
6099:   /* Allocate boundary point storage for FEM boundaries */
6100:   DMPlexGetDepth(dm, &depth);
6101:   DMGetDimension(dm, &dim);
6102:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6103:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6104:   PetscDSGetNumBoundary(dm->prob, &numBd);
6105:   for (bd = 0; bd < numBd; ++bd) {
6106:     PetscInt                field;
6107:     DMBoundaryConditionType type;
6108:     const char             *labelName;
6109:     DMLabel                 label;

6111:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6112:     DMGetLabel(dm,labelName,&label);
6113:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6114:   }
6115:   /* Add ghost cell boundaries for FVM */
6116:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6117:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6118:   /* Constrain ghost cells for FV */
6119:   for (f = 0; f < numFields; ++f) {
6120:     PetscInt *newidx, c;

6122:     if (isFE[f] || cEndInterior < 0) continue;
6123:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6124:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6125:     bcFields[bc] = f;
6126:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6127:   }
6128:   /* Handle FEM Dirichlet boundaries */
6129:   for (bd = 0; bd < numBd; ++bd) {
6130:     const char             *bdLabel;
6131:     DMLabel                 label;
6132:     const PetscInt         *comps;
6133:     const PetscInt         *values;
6134:     PetscInt                bd2, field, numComps, numValues;
6135:     DMBoundaryConditionType type;
6136:     PetscBool               duplicate = PETSC_FALSE;

6138:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6139:     DMGetLabel(dm, bdLabel, &label);
6140:     if (!isFE[field] || !label) continue;
6141:     /* Only want to modify label once */
6142:     for (bd2 = 0; bd2 < bd; ++bd2) {
6143:       const char *bdname;
6144:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6145:       PetscStrcmp(bdname, bdLabel, &duplicate);
6146:       if (duplicate) break;
6147:     }
6148:     if (!duplicate && (isFE[field])) {
6149:       /* don't complete cells, which are just present to give orientation to the boundary */
6150:       DMPlexLabelComplete(dm, label);
6151:     }
6152:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6153:     if (type & DM_BC_ESSENTIAL) {
6154:       PetscInt       *newidx;
6155:       PetscInt        n, newn = 0, p, v;

6157:       bcFields[bc] = field;
6158:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6159:       for (v = 0; v < numValues; ++v) {
6160:         IS              tmp;
6161:         const PetscInt *idx;

6163:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6164:         if (!tmp) continue;
6165:         ISGetLocalSize(tmp, &n);
6166:         ISGetIndices(tmp, &idx);
6167:         if (isFE[field]) {
6168:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6169:         } else {
6170:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6171:         }
6172:         ISRestoreIndices(tmp, &idx);
6173:         ISDestroy(&tmp);
6174:       }
6175:       PetscMalloc1(newn,&newidx);
6176:       newn = 0;
6177:       for (v = 0; v < numValues; ++v) {
6178:         IS              tmp;
6179:         const PetscInt *idx;

6181:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6182:         if (!tmp) continue;
6183:         ISGetLocalSize(tmp, &n);
6184:         ISGetIndices(tmp, &idx);
6185:         if (isFE[field]) {
6186:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6187:         } else {
6188:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6189:         }
6190:         ISRestoreIndices(tmp, &idx);
6191:         ISDestroy(&tmp);
6192:       }
6193:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6194:     }
6195:   }
6196:   /* Handle discretization */
6197:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6198:   for (f = 0; f < numFields; ++f) {
6199:     PetscObject obj;

6201:     DMGetField(dm, f, &obj);
6202:     if (isFE[f]) {
6203:       PetscFE         fe = (PetscFE) obj;
6204:       const PetscInt *numFieldDof;
6205:       PetscInt        d;

6207:       PetscFEGetNumComponents(fe, &numComp[f]);
6208:       PetscFEGetNumDof(fe, &numFieldDof);
6209:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6210:     } else {
6211:       PetscFV fv = (PetscFV) obj;

6213:       PetscFVGetNumComponents(fv, &numComp[f]);
6214:       numDof[f*(dim+1)+dim] = numComp[f];
6215:     }
6216:   }
6217:   for (f = 0; f < numFields; ++f) {
6218:     PetscInt d;
6219:     for (d = 1; d < dim; ++d) {
6220:       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.");
6221:     }
6222:   }
6223:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6224:   for (f = 0; f < numFields; ++f) {
6225:     PetscFE     fe;
6226:     const char *name;

6228:     DMGetField(dm, f, (PetscObject *) &fe);
6229:     PetscObjectGetName((PetscObject) fe, &name);
6230:     PetscSectionSetFieldName(section, f, name);
6231:   }
6232:   DMSetDefaultSection(dm, section);
6233:   PetscSectionDestroy(&section);
6234:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6235:   PetscFree3(bcFields,bcPoints,bcComps);
6236:   PetscFree2(numComp,numDof);
6237:   PetscFree(isFE);
6238:   return(0);
6239: }

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

6244:   Input Parameter:
6245: . dm - The DMPlex object

6247:   Output Parameter:
6248: . regular - The flag

6250:   Level: intermediate

6252: .seealso: DMPlexSetRegularRefinement()
6253: @*/
6254: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6255: {
6259:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6260:   return(0);
6261: }

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

6266:   Input Parameters:
6267: + dm - The DMPlex object
6268: - regular - The flag

6270:   Level: intermediate

6272: .seealso: DMPlexGetRegularRefinement()
6273: @*/
6274: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6275: {
6278:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6279:   return(0);
6280: }

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

6287:   not collective

6289:   Input Parameters:
6290: . dm - The DMPlex object

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


6297:   Level: intermediate

6299: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6300: @*/
6301: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6302: {
6303:   DM_Plex *plex = (DM_Plex *)dm->data;

6308:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6309:   if (anchorSection) *anchorSection = plex->anchorSection;
6310:   if (anchorIS) *anchorIS = plex->anchorIS;
6311:   return(0);
6312: }

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

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

6322:   collective on dm

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

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

6331:   Level: intermediate

6333: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6334: @*/
6335: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6336: {
6337:   DM_Plex        *plex = (DM_Plex *)dm->data;
6338:   PetscMPIInt    result;

6343:   if (anchorSection) {
6345:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6346:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6347:   }
6348:   if (anchorIS) {
6350:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6351:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6352:   }

6354:   PetscObjectReference((PetscObject)anchorSection);
6355:   PetscSectionDestroy(&plex->anchorSection);
6356:   plex->anchorSection = anchorSection;

6358:   PetscObjectReference((PetscObject)anchorIS);
6359:   ISDestroy(&plex->anchorIS);
6360:   plex->anchorIS = anchorIS;

6362: #if defined(PETSC_USE_DEBUG)
6363:   if (anchorIS && anchorSection) {
6364:     PetscInt size, a, pStart, pEnd;
6365:     const PetscInt *anchors;

6367:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6368:     ISGetLocalSize(anchorIS,&size);
6369:     ISGetIndices(anchorIS,&anchors);
6370:     for (a = 0; a < size; a++) {
6371:       PetscInt p;

6373:       p = anchors[a];
6374:       if (p >= pStart && p < pEnd) {
6375:         PetscInt dof;

6377:         PetscSectionGetDof(anchorSection,p,&dof);
6378:         if (dof) {
6379:           PetscErrorCode ierr2;

6381:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6382:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6383:         }
6384:       }
6385:     }
6386:     ISRestoreIndices(anchorIS,&anchors);
6387:   }
6388: #endif
6389:   /* reset the generic constraints */
6390:   DMSetDefaultConstraints(dm,NULL,NULL);
6391:   return(0);
6392: }

6394: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6395: {
6396:   PetscSection anchorSection;
6397:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6402:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6403:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6404:   PetscSectionGetNumFields(section,&numFields);
6405:   if (numFields) {
6406:     PetscInt f;
6407:     PetscSectionSetNumFields(*cSec,numFields);

6409:     for (f = 0; f < numFields; f++) {
6410:       PetscInt numComp;

6412:       PetscSectionGetFieldComponents(section,f,&numComp);
6413:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6414:     }
6415:   }
6416:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6417:   PetscSectionGetChart(section,&sStart,&sEnd);
6418:   pStart = PetscMax(pStart,sStart);
6419:   pEnd   = PetscMin(pEnd,sEnd);
6420:   pEnd   = PetscMax(pStart,pEnd);
6421:   PetscSectionSetChart(*cSec,pStart,pEnd);
6422:   for (p = pStart; p < pEnd; p++) {
6423:     PetscSectionGetDof(anchorSection,p,&dof);
6424:     if (dof) {
6425:       PetscSectionGetDof(section,p,&dof);
6426:       PetscSectionSetDof(*cSec,p,dof);
6427:       for (f = 0; f < numFields; f++) {
6428:         PetscSectionGetFieldDof(section,p,f,&dof);
6429:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6430:       }
6431:     }
6432:   }
6433:   PetscSectionSetUp(*cSec);
6434:   return(0);
6435: }

6437: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6438: {
6439:   PetscSection aSec;
6440:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6441:   const PetscInt *anchors;
6442:   PetscInt numFields, f;
6443:   IS aIS;

6448:   PetscSectionGetStorageSize(cSec, &m);
6449:   PetscSectionGetStorageSize(section, &n);
6450:   MatCreate(PETSC_COMM_SELF,cMat);
6451:   MatSetSizes(*cMat,m,n,m,n);
6452:   MatSetType(*cMat,MATSEQAIJ);
6453:   DMPlexGetAnchors(dm,&aSec,&aIS);
6454:   ISGetIndices(aIS,&anchors);
6455:   /* cSec will be a subset of aSec and section */
6456:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6457:   PetscMalloc1(m+1,&i);
6458:   i[0] = 0;
6459:   PetscSectionGetNumFields(section,&numFields);
6460:   for (p = pStart; p < pEnd; p++) {
6461:     PetscInt rDof, rOff, r;

6463:     PetscSectionGetDof(aSec,p,&rDof);
6464:     if (!rDof) continue;
6465:     PetscSectionGetOffset(aSec,p,&rOff);
6466:     if (numFields) {
6467:       for (f = 0; f < numFields; f++) {
6468:         annz = 0;
6469:         for (r = 0; r < rDof; r++) {
6470:           a = anchors[rOff + r];
6471:           PetscSectionGetFieldDof(section,a,f,&aDof);
6472:           annz += aDof;
6473:         }
6474:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6475:         PetscSectionGetFieldOffset(cSec,p,f,&off);
6476:         for (q = 0; q < dof; q++) {
6477:           i[off + q + 1] = i[off + q] + annz;
6478:         }
6479:       }
6480:     }
6481:     else {
6482:       annz = 0;
6483:       for (q = 0; q < dof; q++) {
6484:         a = anchors[off + q];
6485:         PetscSectionGetDof(section,a,&aDof);
6486:         annz += aDof;
6487:       }
6488:       PetscSectionGetDof(cSec,p,&dof);
6489:       PetscSectionGetOffset(cSec,p,&off);
6490:       for (q = 0; q < dof; q++) {
6491:         i[off + q + 1] = i[off + q] + annz;
6492:       }
6493:     }
6494:   }
6495:   nnz = i[m];
6496:   PetscMalloc1(nnz,&j);
6497:   offset = 0;
6498:   for (p = pStart; p < pEnd; p++) {
6499:     if (numFields) {
6500:       for (f = 0; f < numFields; f++) {
6501:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6502:         for (q = 0; q < dof; q++) {
6503:           PetscInt rDof, rOff, r;
6504:           PetscSectionGetDof(aSec,p,&rDof);
6505:           PetscSectionGetOffset(aSec,p,&rOff);
6506:           for (r = 0; r < rDof; r++) {
6507:             PetscInt s;

6509:             a = anchors[rOff + r];
6510:             PetscSectionGetFieldDof(section,a,f,&aDof);
6511:             PetscSectionGetFieldOffset(section,a,f,&aOff);
6512:             for (s = 0; s < aDof; s++) {
6513:               j[offset++] = aOff + s;
6514:             }
6515:           }
6516:         }
6517:       }
6518:     }
6519:     else {
6520:       PetscSectionGetDof(cSec,p,&dof);
6521:       for (q = 0; q < dof; q++) {
6522:         PetscInt rDof, rOff, r;
6523:         PetscSectionGetDof(aSec,p,&rDof);
6524:         PetscSectionGetOffset(aSec,p,&rOff);
6525:         for (r = 0; r < rDof; r++) {
6526:           PetscInt s;

6528:           a = anchors[rOff + r];
6529:           PetscSectionGetDof(section,a,&aDof);
6530:           PetscSectionGetOffset(section,a,&aOff);
6531:           for (s = 0; s < aDof; s++) {
6532:             j[offset++] = aOff + s;
6533:           }
6534:         }
6535:       }
6536:     }
6537:   }
6538:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
6539:   PetscFree(i);
6540:   PetscFree(j);
6541:   ISRestoreIndices(aIS,&anchors);
6542:   return(0);
6543: }

6545: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6546: {
6547:   DM_Plex        *plex = (DM_Plex *)dm->data;
6548:   PetscSection   anchorSection, section, cSec;
6549:   Mat            cMat;

6554:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6555:   if (anchorSection) {
6556:     PetscDS  ds;
6557:     PetscInt nf;

6559:     DMGetDefaultSection(dm,&section);
6560:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
6561:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
6562:     DMGetDS(dm,&ds);
6563:     PetscDSGetNumFields(ds,&nf);
6564:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
6565:     DMSetDefaultConstraints(dm,cSec,cMat);
6566:     PetscSectionDestroy(&cSec);
6567:     MatDestroy(&cMat);
6568:   }
6569:   return(0);
6570: }