Actual source code: plex.c

petsc-master 2019-12-13
Report Typos and Errors
  1:  #include <petsc/private/dmpleximpl.h>
  2:  #include <petsc/private/isimpl.h>
  3:  #include <petsc/private/vecimpl.h>
  4:  #include <petsc/private/glvisvecimpl.h>
  5:  #include <petscsf.h>
  6:  #include <petscds.h>
  7:  #include <petscdraw.h>
  8:  #include <petscdmfield.h>

 10: /* Logging support */
 11: PetscLogEvent DMPLEX_Interpolate, DMPLEX_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_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF;

 13: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

 15: /*@
 16:   DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells.
 17:   3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D.

 19:   Collective

 21:   Input Parameters:
 22: . dm - The DMPlex object

 24:   Output Parameters:
 25: . dmRefined - The refined DMPlex object

 27:   Note: Returns NULL if the mesh is already a tensor product mesh.

 29:   Level: intermediate

 31: .seealso: DMPlexCreate(), DMPlexSetRefinementUniform()
 32: @*/
 33: PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined)
 34: {
 35:   PetscInt         dim, cMax, fMax, cStart, cEnd, coneSize;
 36:   CellRefiner      cellRefiner;
 37:   PetscBool        lop, allnoop, localized;
 38:   PetscErrorCode   ierr;

 43:   DMGetDimension(dm, &dim);
 44:   DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
 45:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
 46:   if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
 47:   else {
 48:     DMPlexGetConeSize(dm,cStart,&coneSize);
 49:     switch (dim) {
 50:     case 1:
 51:       cellRefiner = REFINER_NOOP;
 52:     break;
 53:     case 2:
 54:       switch (coneSize) {
 55:       case 3:
 56:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
 57:         else cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
 58:       break;
 59:       case 4:
 60:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
 61:         else cellRefiner = REFINER_NOOP;
 62:       break;
 63:       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
 64:       }
 65:     break;
 66:     case 3:
 67:       switch (coneSize) {
 68:       case 4:
 69:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
 70:         else cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
 71:       break;
 72:       case 5:
 73:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
 74:         else cellRefiner = REFINER_NOOP;
 75:       break;
 76:       case 6:
 77:         if (cMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Simplex2Tensor in 3D with Hybrid mesh not yet done");
 78:         cellRefiner = REFINER_NOOP;
 79:       break;
 80:       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
 81:       }
 82:     break;
 83:     default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
 84:     }
 85:   }
 86:   /* return if we don't need to refine */
 87:   lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
 88:   MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
 89:   if (allnoop) {
 90:     *dmRefined = NULL;
 91:     return(0);
 92:   }
 93:   DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
 94:   DMCopyBoundary(dm, *dmRefined);
 95:   DMGetCoordinatesLocalized(dm, &localized);
 96:   if (localized) {
 97:     DMLocalizeCoordinates(*dmRefined);
 98:   }
 99:   return(0);
100: }

102: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
103: {
104:   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cMax;
105:   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];

109:   *ft  = PETSC_VTK_INVALID;
110:   DMGetDimension(dm, &dim);
111:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
112:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
113:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
114:   cEnd = cMax < 0 ? cEnd : cMax;
115:   PetscSectionGetChart(section, &pStart, &pEnd);
116:   if (field >= 0) {
117:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);}
118:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);}
119:   } else {
120:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vcdof[0]);}
121:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &vcdof[1]);}
122:   }
123:   MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
124:   if (globalvcdof[0]) {
125:     *sStart = vStart;
126:     *sEnd   = vEnd;
127:     if (globalvcdof[0] == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
128:     else                       *ft = PETSC_VTK_POINT_FIELD;
129:   } else if (globalvcdof[1]) {
130:     *sStart = cStart;
131:     *sEnd   = cEnd;
132:     if (globalvcdof[1] == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
133:     else                       *ft = PETSC_VTK_CELL_FIELD;
134:   } else {
135:     if (field >= 0) {
136:       const char *fieldname;

138:       PetscSectionGetFieldName(section, field, &fieldname);
139:       PetscInfo2((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname);
140:     } else {
141:       PetscInfo((PetscObject) dm, "Could not classify VTK output typp of section\"%s\"\n");
142:     }
143:   }
144:   return(0);
145: }

147: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
148: {
149:   DM                 dm;
150:   PetscSection       s;
151:   PetscDraw          draw, popup;
152:   DM                 cdm;
153:   PetscSection       coordSection;
154:   Vec                coordinates;
155:   const PetscScalar *coords, *array;
156:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
157:   PetscReal          vbound[2], time;
158:   PetscBool          isnull, flg;
159:   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
160:   const char        *name;
161:   char               title[PETSC_MAX_PATH_LEN];
162:   PetscErrorCode     ierr;

165:   PetscViewerDrawGetDraw(viewer, 0, &draw);
166:   PetscDrawIsNull(draw, &isnull);
167:   if (isnull) return(0);

169:   VecGetDM(v, &dm);
170:   DMGetCoordinateDim(dm, &dim);
171:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
172:   DMGetLocalSection(dm, &s);
173:   PetscSectionGetNumFields(s, &Nf);
174:   DMGetCoarsenLevel(dm, &level);
175:   DMGetCoordinateDM(dm, &cdm);
176:   DMGetLocalSection(cdm, &coordSection);
177:   DMGetCoordinatesLocal(dm, &coordinates);
178:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
179:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

181:   PetscObjectGetName((PetscObject) v, &name);
182:   DMGetOutputSequenceNumber(dm, &step, &time);

184:   VecGetLocalSize(coordinates, &N);
185:   VecGetArrayRead(coordinates, &coords);
186:   for (c = 0; c < N; c += dim) {
187:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
188:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
189:   }
190:   VecRestoreArrayRead(coordinates, &coords);
191:   PetscDrawClear(draw);

193:   /* Could implement something like DMDASelectFields() */
194:   for (f = 0; f < Nf; ++f) {
195:     DM   fdm = dm;
196:     Vec  fv  = v;
197:     IS   fis;
198:     char prefix[PETSC_MAX_PATH_LEN];
199:     const char *fname;

201:     PetscSectionGetFieldComponents(s, f, &Nc);
202:     PetscSectionGetFieldName(s, f, &fname);

204:     if (v->hdr.prefix) {PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));}
205:     else               {prefix[0] = '\0';}
206:     if (Nf > 1) {
207:       DMCreateSubDM(dm, 1, &f, &fis, &fdm);
208:       VecGetSubVector(v, fis, &fv);
209:       PetscStrlcat(prefix, fname,sizeof(prefix));
210:       PetscStrlcat(prefix, "_",sizeof(prefix));
211:     }
212:     for (comp = 0; comp < Nc; ++comp, ++w) {
213:       PetscInt nmax = 2;

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

220:       /* TODO Get max and min only for this component */
221:       PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
222:       if (!flg) {
223:         VecMin(fv, NULL, &vbound[0]);
224:         VecMax(fv, NULL, &vbound[1]);
225:         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
226:       }
227:       PetscDrawGetPopup(draw, &popup);
228:       PetscDrawScalePopup(popup, vbound[0], vbound[1]);
229:       PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);

231:       VecGetArrayRead(fv, &array);
232:       for (c = cStart; c < cEnd; ++c) {
233:         PetscScalar *coords = NULL, *a = NULL;
234:         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};

236:         DMPlexPointLocalRead(fdm, c, array, &a);
237:         if (a) {
238:           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
239:           color[1] = color[2] = color[3] = color[0];
240:         } else {
241:           PetscScalar *vals = NULL;
242:           PetscInt     numVals, va;

244:           DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
245:           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);
246:           switch (numVals/Nc) {
247:           case 3: /* P1 Triangle */
248:           case 4: /* P1 Quadrangle */
249:             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
250:             break;
251:           case 6: /* P2 Triangle */
252:           case 8: /* P2 Quadrangle */
253:             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
254:             break;
255:           default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
256:           }
257:           DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
258:         }
259:         DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
260:         switch (numCoords) {
261:         case 6:
262:           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]);
263:           break;
264:         case 8:
265:           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]);
266:           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]);
267:           break;
268:         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
269:         }
270:         DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
271:       }
272:       VecRestoreArrayRead(fv, &array);
273:       PetscDrawFlush(draw);
274:       PetscDrawPause(draw);
275:       PetscDrawSave(draw);
276:     }
277:     if (Nf > 1) {
278:       VecRestoreSubVector(v, fis, &fv);
279:       ISDestroy(&fis);
280:       DMDestroy(&fdm);
281:     }
282:   }
283:   return(0);
284: }

286: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
287: {
288:   DM                      dm;
289:   Vec                     locv;
290:   const char              *name;
291:   PetscSection            section;
292:   PetscInt                pStart, pEnd;
293:   PetscInt                numFields;
294:   PetscViewerVTKFieldType ft;
295:   PetscErrorCode          ierr;

298:   VecGetDM(v, &dm);
299:   DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
300:   PetscObjectGetName((PetscObject) v, &name);
301:   PetscObjectSetName((PetscObject) locv, name);
302:   VecCopy(v, locv);
303:   DMGetLocalSection(dm, &section);
304:   PetscSectionGetNumFields(section, &numFields);
305:   if (!numFields) {
306:     DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
307:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv);
308:   } else {
309:     PetscInt f;

311:     for (f = 0; f < numFields; f++) {
312:       DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft);
313:       if (ft == PETSC_VTK_INVALID) continue;
314:       PetscObjectReference((PetscObject)locv);
315:       PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv);
316:     }
317:     VecDestroy(&locv);
318:   }
319:   return(0);
320: }

322: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
323: {
324:   DM             dm;
325:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

329:   VecGetDM(v, &dm);
330:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
331:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
332:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
333:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
334:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
335:   if (isvtk || ishdf5 || isdraw || isglvis) {
336:     PetscInt    i,numFields;
337:     PetscObject fe;
338:     PetscBool   fem = PETSC_FALSE;
339:     Vec         locv = v;
340:     const char  *name;
341:     PetscInt    step;
342:     PetscReal   time;

344:     DMGetNumFields(dm, &numFields);
345:     for (i=0; i<numFields; i++) {
346:       DMGetField(dm, i, NULL, &fe);
347:       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
348:     }
349:     if (fem) {
350:       DMGetLocalVector(dm, &locv);
351:       PetscObjectGetName((PetscObject) v, &name);
352:       PetscObjectSetName((PetscObject) locv, name);
353:       VecCopy(v, locv);
354:       DMGetOutputSequenceNumber(dm, NULL, &time);
355:       DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
356:     }
357:     if (isvtk) {
358:       VecView_Plex_Local_VTK(locv, viewer);
359:     } else if (ishdf5) {
360: #if defined(PETSC_HAVE_HDF5)
361:       VecView_Plex_Local_HDF5_Internal(locv, viewer);
362: #else
363:       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
364: #endif
365:     } else if (isdraw) {
366:       VecView_Plex_Local_Draw(locv, viewer);
367:     } else if (isglvis) {
368:       DMGetOutputSequenceNumber(dm, &step, NULL);
369:       PetscViewerGLVisSetSnapId(viewer, step);
370:       VecView_GLVis(locv, viewer);
371:     }
372:     if (fem) {DMRestoreLocalVector(dm, &locv);}
373:   } else {
374:     PetscBool isseq;

376:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
377:     if (isseq) {VecView_Seq(v, viewer);}
378:     else       {VecView_MPI(v, viewer);}
379:   }
380:   return(0);
381: }

383: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
384: {
385:   DM             dm;
386:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

390:   VecGetDM(v, &dm);
391:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
392:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
393:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
394:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
395:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
396:   if (isvtk || isdraw || isglvis) {
397:     Vec         locv;
398:     const char *name;

400:     DMGetLocalVector(dm, &locv);
401:     PetscObjectGetName((PetscObject) v, &name);
402:     PetscObjectSetName((PetscObject) locv, name);
403:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
404:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
405:     VecView_Plex_Local(locv, viewer);
406:     DMRestoreLocalVector(dm, &locv);
407:   } else if (ishdf5) {
408: #if defined(PETSC_HAVE_HDF5)
409:     VecView_Plex_HDF5_Internal(v, viewer);
410: #else
411:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
412: #endif
413:   } else {
414:     PetscBool isseq;

416:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
417:     if (isseq) {VecView_Seq(v, viewer);}
418:     else       {VecView_MPI(v, viewer);}
419:   }
420:   return(0);
421: }

423: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
424: {
425:   DM                dm;
426:   MPI_Comm          comm;
427:   PetscViewerFormat format;
428:   Vec               v;
429:   PetscBool         isvtk, ishdf5;
430:   PetscErrorCode    ierr;

433:   VecGetDM(originalv, &dm);
434:   PetscObjectGetComm((PetscObject) originalv, &comm);
435:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
436:   PetscViewerGetFormat(viewer, &format);
437:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
438:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
439:   if (format == PETSC_VIEWER_NATIVE) {
440:     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
441:     /* this need a better fix */
442:     if (dm->useNatural) {
443:       if (dm->sfNatural) {
444:         const char *vecname;
445:         PetscInt    n, nroots;

447:         VecGetLocalSize(originalv, &n);
448:         PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
449:         if (n == nroots) {
450:           DMGetGlobalVector(dm, &v);
451:           DMPlexGlobalToNaturalBegin(dm, originalv, v);
452:           DMPlexGlobalToNaturalEnd(dm, originalv, v);
453:           PetscObjectGetName((PetscObject) originalv, &vecname);
454:           PetscObjectSetName((PetscObject) v, vecname);
455:         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
456:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
457:     } else v = originalv;
458:   } else v = originalv;

460:   if (ishdf5) {
461: #if defined(PETSC_HAVE_HDF5)
462:     VecView_Plex_HDF5_Native_Internal(v, viewer);
463: #else
464:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
465: #endif
466:   } else if (isvtk) {
467:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
468:   } else {
469:     PetscBool isseq;

471:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
472:     if (isseq) {VecView_Seq(v, viewer);}
473:     else       {VecView_MPI(v, viewer);}
474:   }
475:   if (v != originalv) {DMRestoreGlobalVector(dm, &v);}
476:   return(0);
477: }

479: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
480: {
481:   DM             dm;
482:   PetscBool      ishdf5;

486:   VecGetDM(v, &dm);
487:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
488:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
489:   if (ishdf5) {
490:     DM          dmBC;
491:     Vec         gv;
492:     const char *name;

494:     DMGetOutputDM(dm, &dmBC);
495:     DMGetGlobalVector(dmBC, &gv);
496:     PetscObjectGetName((PetscObject) v, &name);
497:     PetscObjectSetName((PetscObject) gv, name);
498:     VecLoad_Default(gv, viewer);
499:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
500:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
501:     DMRestoreGlobalVector(dmBC, &gv);
502:   } else {
503:     VecLoad_Default(v, viewer);
504:   }
505:   return(0);
506: }

508: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
509: {
510:   DM             dm;
511:   PetscBool      ishdf5;

515:   VecGetDM(v, &dm);
516:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
517:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
518:   if (ishdf5) {
519: #if defined(PETSC_HAVE_HDF5)
520:     VecLoad_Plex_HDF5_Internal(v, viewer);
521: #else
522:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
523: #endif
524:   } else {
525:     VecLoad_Default(v, viewer);
526:   }
527:   return(0);
528: }

530: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
531: {
532:   DM                dm;
533:   PetscViewerFormat format;
534:   PetscBool         ishdf5;
535:   PetscErrorCode    ierr;

538:   VecGetDM(originalv, &dm);
539:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
540:   PetscViewerGetFormat(viewer, &format);
541:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
542:   if (format == PETSC_VIEWER_NATIVE) {
543:     if (dm->useNatural) {
544:       if (dm->sfNatural) {
545:         if (ishdf5) {
546: #if defined(PETSC_HAVE_HDF5)
547:           Vec         v;
548:           const char *vecname;

550:           DMGetGlobalVector(dm, &v);
551:           PetscObjectGetName((PetscObject) originalv, &vecname);
552:           PetscObjectSetName((PetscObject) v, vecname);
553:           VecLoad_Plex_HDF5_Native_Internal(v, viewer);
554:           DMPlexNaturalToGlobalBegin(dm, v, originalv);
555:           DMPlexNaturalToGlobalEnd(dm, v, originalv);
556:           DMRestoreGlobalVector(dm, &v);
557: #else
558:           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
559: #endif
560:         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
561:       }
562:     } else {
563:       VecLoad_Default(originalv, viewer);
564:     }
565:   }
566:   return(0);
567: }

569: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
570: {
571:   PetscSection       coordSection;
572:   Vec                coordinates;
573:   DMLabel            depthLabel;
574:   const char        *name[4];
575:   const PetscScalar *a;
576:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
577:   PetscErrorCode     ierr;

580:   DMGetDimension(dm, &dim);
581:   DMGetCoordinatesLocal(dm, &coordinates);
582:   DMGetCoordinateSection(dm, &coordSection);
583:   DMPlexGetDepthLabel(dm, &depthLabel);
584:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
585:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
586:   VecGetArrayRead(coordinates, &a);
587:   name[0]     = "vertex";
588:   name[1]     = "edge";
589:   name[dim-1] = "face";
590:   name[dim]   = "cell";
591:   for (c = cStart; c < cEnd; ++c) {
592:     PetscInt *closure = NULL;
593:     PetscInt  closureSize, cl;

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

601:       if ((point < pStart) || (point >= pEnd)) continue;
602:       PetscSectionGetDof(coordSection, point, &dof);
603:       if (!dof) continue;
604:       DMLabelGetValue(depthLabel, point, &depth);
605:       PetscSectionGetOffset(coordSection, point, &off);
606:       PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
607:       for (p = 0; p < dof/dim; ++p) {
608:         PetscViewerASCIIPrintf(viewer, " (");
609:         for (d = 0; d < dim; ++d) {
610:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
611:           PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));
612:         }
613:         PetscViewerASCIIPrintf(viewer, ")");
614:       }
615:       PetscViewerASCIIPrintf(viewer, "\n");
616:     }
617:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
618:     PetscViewerASCIIPopTab(viewer);
619:   }
620:   VecRestoreArrayRead(coordinates, &a);
621:   return(0);
622: }

624: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
625: {
626:   DM_Plex          *mesh = (DM_Plex*) dm->data;
627:   DM                cdm;
628:   DMLabel           markers;
629:   PetscSection      coordSection;
630:   Vec               coordinates;
631:   PetscViewerFormat format;
632:   PetscErrorCode    ierr;

635:   DMGetCoordinateDM(dm, &cdm);
636:   DMGetLocalSection(cdm, &coordSection);
637:   DMGetCoordinatesLocal(dm, &coordinates);
638:   PetscViewerGetFormat(viewer, &format);
639:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
640:     const char *name;
641:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
642:     PetscInt    pStart, pEnd, p;
643:     PetscMPIInt rank, size;

645:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
646:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
647:     PetscObjectGetName((PetscObject) dm, &name);
648:     DMPlexGetChart(dm, &pStart, &pEnd);
649:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
650:     DMGetDimension(dm, &dim);
651:     DMPlexGetVTKCellHeight(dm, &cellHeight);
652:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
653:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
654:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
655:     PetscViewerASCIIPrintf(viewer, "Supports:\n", name);
656:     PetscViewerASCIIPushSynchronized(viewer);
657:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);
658:     for (p = pStart; p < pEnd; ++p) {
659:       PetscInt dof, off, s;

661:       PetscSectionGetDof(mesh->supportSection, p, &dof);
662:       PetscSectionGetOffset(mesh->supportSection, p, &off);
663:       for (s = off; s < off+dof; ++s) {
664:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
665:       }
666:     }
667:     PetscViewerFlush(viewer);
668:     PetscViewerASCIIPrintf(viewer, "Cones:\n", name);
669:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);
670:     for (p = pStart; p < pEnd; ++p) {
671:       PetscInt dof, off, c;

673:       PetscSectionGetDof(mesh->coneSection, p, &dof);
674:       PetscSectionGetOffset(mesh->coneSection, p, &off);
675:       for (c = off; c < off+dof; ++c) {
676:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
677:       }
678:     }
679:     PetscViewerFlush(viewer);
680:     PetscViewerASCIIPopSynchronized(viewer);
681:     if (coordSection && coordinates) {
682:       PetscSectionVecView(coordSection, coordinates, viewer);
683:     }
684:     DMGetLabel(dm, "marker", &markers);
685:     if (markers) {DMLabelView(markers,viewer);}
686:     if (size > 1) {
687:       PetscSF sf;

689:       DMGetPointSF(dm, &sf);
690:       PetscSFView(sf, viewer);
691:     }
692:     PetscViewerFlush(viewer);
693:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
694:     const char  *name, *color;
695:     const char  *defcolors[3]  = {"gray", "orange", "green"};
696:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
697:     char         lname[PETSC_MAX_PATH_LEN];
698:     PetscReal    scale         = 2.0;
699:     PetscReal    tikzscale     = 1.0;
700:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
701:     double       tcoords[3];
702:     PetscScalar *coords;
703:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
704:     PetscMPIInt  rank, size;
705:     char         **names, **colors, **lcolors;
706:     PetscBool    plotEdges, flg, lflg;
707:     PetscBT      wp = NULL;
708:     PetscInt     pEnd, pStart;

710:     DMGetDimension(dm, &dim);
711:     DMPlexGetDepth(dm, &depth);
712:     DMGetNumLabels(dm, &numLabels);
713:     numLabels  = PetscMax(numLabels, 10);
714:     numColors  = 10;
715:     numLColors = 10;
716:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
717:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
718:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);
719:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
720:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
721:     if (!useLabels) numLabels = 0;
722:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
723:     if (!useColors) {
724:       numColors = 3;
725:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
726:     }
727:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
728:     if (!useColors) {
729:       numLColors = 4;
730:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
731:     }
732:     PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, PETSC_MAX_PATH_LEN, &lflg);
733:     plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
734:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);
735:     if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
736:     if (depth < dim) plotEdges = PETSC_FALSE;

738:     /* filter points with labelvalue != labeldefaultvalue */
739:     DMPlexGetChart(dm, &pStart, &pEnd);
740:     if (lflg) {
741:       DMLabel lbl;

743:       DMGetLabel(dm, lname, &lbl);
744:       if (lbl) {
745:         PetscInt val, defval;

747:         DMLabelGetDefaultValue(lbl, &defval);
748:         PetscBTCreate(pEnd-pStart, &wp);
749:         for (c = pStart;  c < pEnd; c++) {
750:           PetscInt *closure = NULL;
751:           PetscInt  closureSize;

753:           DMLabelGetValue(lbl, c, &val);
754:           if (val == defval) continue;

756:           DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
757:           for (p = 0; p < closureSize*2; p += 2) {
758:             PetscBTSet(wp, closure[p] - pStart);
759:           }
760:           DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
761:         }
762:       }
763:     }

765:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
766:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
767:     PetscObjectGetName((PetscObject) dm, &name);
768:     PetscViewerASCIIPrintf(viewer, "\
769: \\documentclass[tikz]{standalone}\n\n\
770: \\usepackage{pgflibraryshapes}\n\
771: \\usetikzlibrary{backgrounds}\n\
772: \\usetikzlibrary{arrows}\n\
773: \\begin{document}\n");
774:     if (size > 1) {
775:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
776:       for (p = 0; p < size; ++p) {
777:         if (p > 0 && p == size-1) {
778:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
779:         } else if (p > 0) {
780:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
781:         }
782:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
783:       }
784:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
785:     }
786:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);

788:     /* Plot vertices */
789:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
790:     VecGetArray(coordinates, &coords);
791:     PetscViewerASCIIPushSynchronized(viewer);
792:     for (v = vStart; v < vEnd; ++v) {
793:       PetscInt  off, dof, d;
794:       PetscBool isLabeled = PETSC_FALSE;

796:       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
797:       PetscSectionGetDof(coordSection, v, &dof);
798:       PetscSectionGetOffset(coordSection, v, &off);
799:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
800:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
801:       for (d = 0; d < dof; ++d) {
802:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
803:         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
804:       }
805:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
806:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
807:       for (d = 0; d < dof; ++d) {
808:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
809:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);
810:       }
811:       color = colors[rank%numColors];
812:       for (l = 0; l < numLabels; ++l) {
813:         PetscInt val;
814:         DMGetLabelValue(dm, names[l], v, &val);
815:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
816:       }
817:       if (useNumbers) {
818:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
819:       } else {
820:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
821:       }
822:     }
823:     VecRestoreArray(coordinates, &coords);
824:     PetscViewerFlush(viewer);
825:     /* Plot cells */
826:     DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
827:     DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
828:     if (dim == 3 || !useNumbers) {
829:       for (e = eStart; e < eEnd; ++e) {
830:         const PetscInt *cone;

832:         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
833:         color = colors[rank%numColors];
834:         for (l = 0; l < numLabels; ++l) {
835:           PetscInt val;
836:           DMGetLabelValue(dm, names[l], e, &val);
837:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
838:         }
839:         DMPlexGetCone(dm, e, &cone);
840:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
841:       }
842:     } else {
843:       for (c = cStart; c < cEnd; ++c) {
844:         PetscInt *closure = NULL;
845:         PetscInt  closureSize, firstPoint = -1;

847:         if (wp && !PetscBTLookup(wp,c - pStart)) continue;
848:         DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
849:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
850:         for (p = 0; p < closureSize*2; p += 2) {
851:           const PetscInt point = closure[p];

853:           if ((point < vStart) || (point >= vEnd)) continue;
854:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
855:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
856:           if (firstPoint < 0) firstPoint = point;
857:         }
858:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
859:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
860:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
861:       }
862:     }
863:     VecGetArray(coordinates, &coords);
864:     for (c = cStart; c < cEnd; ++c) {
865:       double    ccoords[3] = {0.0, 0.0, 0.0};
866:       PetscBool isLabeled  = PETSC_FALSE;
867:       PetscInt *closure    = NULL;
868:       PetscInt  closureSize, dof, d, n = 0;

870:       if (wp && !PetscBTLookup(wp,c - pStart)) continue;
871:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
872:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
873:       for (p = 0; p < closureSize*2; p += 2) {
874:         const PetscInt point = closure[p];
875:         PetscInt       off;

877:         if ((point < vStart) || (point >= vEnd)) continue;
878:         PetscSectionGetDof(coordSection, point, &dof);
879:         PetscSectionGetOffset(coordSection, point, &off);
880:         for (d = 0; d < dof; ++d) {
881:           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
882:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
883:         }
884:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
885:         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
886:         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
887:         ++n;
888:       }
889:       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
890:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
891:       for (d = 0; d < dof; ++d) {
892:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
893:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);
894:       }
895:       color = colors[rank%numColors];
896:       for (l = 0; l < numLabels; ++l) {
897:         PetscInt val;
898:         DMGetLabelValue(dm, names[l], c, &val);
899:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
900:       }
901:       if (useNumbers) {
902:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);
903:       } else {
904:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);
905:       }
906:     }
907:     VecRestoreArray(coordinates, &coords);
908:     /* Plot edges */
909:     if (plotEdges) {
910:       VecGetArray(coordinates, &coords);
911:       PetscViewerASCIIPrintf(viewer, "\\path\n");
912:       for (e = eStart; e < eEnd; ++e) {
913:         const PetscInt *cone;
914:         PetscInt        coneSize, offA, offB, dof, d;

916:         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
917:         DMPlexGetConeSize(dm, e, &coneSize);
918:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
919:         DMPlexGetCone(dm, e, &cone);
920:         PetscSectionGetDof(coordSection, cone[0], &dof);
921:         PetscSectionGetOffset(coordSection, cone[0], &offA);
922:         PetscSectionGetOffset(coordSection, cone[1], &offB);
923:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
924:         for (d = 0; d < dof; ++d) {
925:           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
926:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
927:         }
928:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
929:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
930:         for (d = 0; d < dof; ++d) {
931:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
932:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
933:         }
934:         color = colors[rank%numColors];
935:         for (l = 0; l < numLabels; ++l) {
936:           PetscInt val;
937:           DMGetLabelValue(dm, names[l], v, &val);
938:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
939:         }
940:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
941:       }
942:       VecRestoreArray(coordinates, &coords);
943:       PetscViewerFlush(viewer);
944:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
945:     }
946:     PetscViewerFlush(viewer);
947:     PetscViewerASCIIPopSynchronized(viewer);
948:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
949:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
950:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
951:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
952:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
953:     PetscFree3(names, colors, lcolors);
954:     PetscBTDestroy(&wp);
955:   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
956:     Vec                    cown,acown;
957:     VecScatter             sct;
958:     ISLocalToGlobalMapping g2l;
959:     IS                     gid,acis;
960:     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
961:     MPI_Group              ggroup,ngroup;
962:     PetscScalar            *array,nid;
963:     const PetscInt         *idxs;
964:     PetscInt               *idxs2,*start,*adjacency,*work;
965:     PetscInt64             lm[3],gm[3];
966:     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
967:     PetscMPIInt            d1,d2,rank;

969:     PetscObjectGetComm((PetscObject)dm,&comm);
970:     MPI_Comm_rank(comm,&rank);
971: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
972:     MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);
973: #endif
974:     if (ncomm != MPI_COMM_NULL) {
975:       MPI_Comm_group(comm,&ggroup);
976:       MPI_Comm_group(ncomm,&ngroup);
977:       d1   = 0;
978:       MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);
979:       nid  = d2;
980:       MPI_Group_free(&ggroup);
981:       MPI_Group_free(&ngroup);
982:       MPI_Comm_free(&ncomm);
983:     } else nid = 0.0;

985:     /* Get connectivity */
986:     DMPlexGetVTKCellHeight(dm,&cellHeight);
987:     DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);

989:     /* filter overlapped local cells */
990:     DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);
991:     ISGetIndices(gid,&idxs);
992:     ISGetLocalSize(gid,&cum);
993:     PetscMalloc1(cum,&idxs2);
994:     for (c = cStart, cum = 0; c < cEnd; c++) {
995:       if (idxs[c-cStart] < 0) continue;
996:       idxs2[cum++] = idxs[c-cStart];
997:     }
998:     ISRestoreIndices(gid,&idxs);
999:     if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
1000:     ISDestroy(&gid);
1001:     ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);

1003:     /* support for node-aware cell locality */
1004:     ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);
1005:     VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);
1006:     VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);
1007:     VecGetArray(cown,&array);
1008:     for (c = 0; c < numVertices; c++) array[c] = nid;
1009:     VecRestoreArray(cown,&array);
1010:     VecScatterCreate(cown,acis,acown,NULL,&sct);
1011:     VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
1012:     VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
1013:     ISDestroy(&acis);
1014:     VecScatterDestroy(&sct);
1015:     VecDestroy(&cown);

1017:     /* compute edgeCut */
1018:     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
1019:     PetscMalloc1(cum,&work);
1020:     ISLocalToGlobalMappingCreateIS(gid,&g2l);
1021:     ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);
1022:     ISDestroy(&gid);
1023:     VecGetArray(acown,&array);
1024:     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1025:       PetscInt totl;

1027:       totl = start[c+1]-start[c];
1028:       ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);
1029:       for (i = 0; i < totl; i++) {
1030:         if (work[i] < 0) {
1031:           ect  += 1;
1032:           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1033:         }
1034:       }
1035:     }
1036:     PetscFree(work);
1037:     VecRestoreArray(acown,&array);
1038:     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
1039:     lm[1] = -numVertices;
1040:     MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);
1041:     PetscViewerASCIIPrintf(viewer,"  Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);
1042:     lm[0] = ect; /* edgeCut */
1043:     lm[1] = ectn; /* node-aware edgeCut */
1044:     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1045:     MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);
1046:     PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);
1047: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1048:     PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.);
1049: #else
1050:     PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);
1051: #endif
1052:     ISLocalToGlobalMappingDestroy(&g2l);
1053:     PetscFree(start);
1054:     PetscFree(adjacency);
1055:     VecDestroy(&acown);
1056:   } else {
1057:     MPI_Comm    comm;
1058:     PetscInt   *sizes, *hybsizes, *ghostsizes;
1059:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
1060:     PetscInt    pStart, pEnd, p, gcStart, gcEnd, gcNum;
1061:     PetscInt    numLabels, l;
1062:     const char *name;
1063:     PetscMPIInt size;

1065:     PetscObjectGetComm((PetscObject)dm,&comm);
1066:     MPI_Comm_size(comm, &size);
1067:     DMGetDimension(dm, &dim);
1068:     DMPlexGetVTKCellHeight(dm, &cellHeight);
1069:     PetscObjectGetName((PetscObject) dm, &name);
1070:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
1071:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
1072:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
1073:     DMPlexGetDepth(dm, &locDepth);
1074:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
1075:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);
1076:     DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);
1077:     gcNum = gcEnd - gcStart;
1078:     PetscCalloc3(size,&sizes,size,&hybsizes,size,&ghostsizes);
1079:     if (depth == 1) {
1080:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
1081:       pEnd = pEnd - pStart;
1082:       pMax[0] -= pStart;
1083:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1084:       MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1085:       MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);
1086:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
1087:       for (p = 0; p < size; ++p) {
1088:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1089:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1090:       }
1091:       PetscViewerASCIIPrintf(viewer, "\n");
1092:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
1093:       pEnd = pEnd - pStart;
1094:       pMax[depth] -= pStart;
1095:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1096:       MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1097:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
1098:       for (p = 0; p < size; ++p) {
1099:         PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);
1100:         if (hybsizes[p] >= 0)   {PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);}
1101:         if (ghostsizes[p] > 0) {PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);}
1102:       }
1103:       PetscViewerASCIIPrintf(viewer, "\n");
1104:     } else {
1105:       PetscMPIInt rank;
1106:       MPI_Comm_rank(comm, &rank);
1107:       for (d = 0; d <= dim; d++) {
1108:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
1109:         pEnd    -= pStart;
1110:         pMax[d] -= pStart;
1111:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1112:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1113:         if (d == dim) {MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);}
1114:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
1115:         for (p = 0; p < size; ++p) {
1116:           if (!rank) {
1117:             PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);
1118:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);}
1119:             if (d == dim && ghostsizes[p] > 0) {PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);}
1120:           }
1121:         }
1122:         PetscViewerASCIIPrintf(viewer, "\n");
1123:       }
1124:     }
1125:     PetscFree3(sizes,hybsizes,ghostsizes);
1126:     DMGetNumLabels(dm, &numLabels);
1127:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
1128:     for (l = 0; l < numLabels; ++l) {
1129:       DMLabel         label;
1130:       const char     *name;
1131:       IS              valueIS;
1132:       const PetscInt *values;
1133:       PetscInt        numValues, v;

1135:       DMGetLabelName(dm, l, &name);
1136:       DMGetLabel(dm, name, &label);
1137:       DMLabelGetNumValues(label, &numValues);
1138:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
1139:       DMLabelGetValueIS(label, &valueIS);
1140:       ISGetIndices(valueIS, &values);
1141:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
1142:       for (v = 0; v < numValues; ++v) {
1143:         PetscInt size;

1145:         DMLabelGetStratumSize(label, values[v], &size);
1146:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
1147:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
1148:       }
1149:       PetscViewerASCIIPrintf(viewer, ")\n");
1150:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
1151:       ISRestoreIndices(valueIS, &values);
1152:       ISDestroy(&valueIS);
1153:     }
1154:     /* If no fields are specified, people do not want to see adjacency */
1155:     if (dm->Nf) {
1156:       PetscInt f;

1158:       for (f = 0; f < dm->Nf; ++f) {
1159:         const char *name;

1161:         PetscObjectGetName(dm->fields[f].disc, &name);
1162:         if (numLabels) {PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);}
1163:         PetscViewerASCIIPushTab(viewer);
1164:         if (dm->fields[f].label) {DMLabelView(dm->fields[f].label, viewer);}
1165:         if (dm->fields[f].adjacency[0]) {
1166:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");}
1167:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");}
1168:         } else {
1169:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");}
1170:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");}
1171:         }
1172:         PetscViewerASCIIPopTab(viewer);
1173:       }
1174:     }
1175:     DMGetCoarseDM(dm, &cdm);
1176:     if (cdm) {
1177:       PetscViewerASCIIPushTab(viewer);
1178:       DMPlexView_Ascii(cdm, viewer);
1179:       PetscViewerASCIIPopTab(viewer);
1180:     }
1181:   }
1182:   return(0);
1183: }

1185: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1186: {
1187:   PetscDraw          draw;
1188:   DM                 cdm;
1189:   PetscSection       coordSection;
1190:   Vec                coordinates;
1191:   const PetscScalar *coords;
1192:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1193:   PetscBool          isnull;
1194:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
1195:   PetscMPIInt        rank;
1196:   PetscErrorCode     ierr;

1199:   DMGetCoordinateDim(dm, &dim);
1200:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1201:   DMGetCoordinateDM(dm, &cdm);
1202:   DMGetLocalSection(cdm, &coordSection);
1203:   DMGetCoordinatesLocal(dm, &coordinates);
1204:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1205:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

1207:   PetscViewerDrawGetDraw(viewer, 0, &draw);
1208:   PetscDrawIsNull(draw, &isnull);
1209:   if (isnull) return(0);
1210:   PetscDrawSetTitle(draw, "Mesh");

1212:   VecGetLocalSize(coordinates, &N);
1213:   VecGetArrayRead(coordinates, &coords);
1214:   for (c = 0; c < N; c += dim) {
1215:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1216:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1217:   }
1218:   VecRestoreArrayRead(coordinates, &coords);
1219:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1220:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1221:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1222:   PetscDrawClear(draw);

1224:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1225:   for (c = cStart; c < cEnd; ++c) {
1226:     PetscScalar *coords = NULL;
1227:     PetscInt     numCoords,coneSize;

1229:     DMPlexGetConeSize(dm, c, &coneSize);
1230:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1231:     switch (coneSize) {
1232:     case 3:
1233:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1234:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1235:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1236:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1237:       break;
1238:     case 4:
1239:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1240:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1241:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1242:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1243:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]),
1244:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1245:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1246:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1247:       break;
1248:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1249:     }
1250:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1251:   }
1252:   for (c = cStart; c < cEnd; ++c) {
1253:     PetscScalar *coords = NULL;
1254:     PetscInt     numCoords,coneSize;

1256:     DMPlexGetConeSize(dm, c, &coneSize);
1257:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1258:     switch (coneSize) {
1259:     case 3:
1260:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1261:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1262:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1263:       break;
1264:     case 4:
1265:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1266:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1267:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
1268:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1269:       break;
1270:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1271:     }
1272:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1273:   }
1274:   PetscDrawFlush(draw);
1275:   PetscDrawPause(draw);
1276:   PetscDrawSave(draw);
1277:   return(0);
1278: }

1280: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1281: {
1282:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1283:   char           name[PETSC_MAX_PATH_LEN];

1289:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
1290:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
1291:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
1292:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
1293:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
1294:   if (iascii) {
1295:     PetscViewerFormat format;
1296:     PetscViewerGetFormat(viewer, &format);
1297:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1298:       DMPlexView_GLVis(dm, viewer);
1299:     } else {
1300:       DMPlexView_Ascii(dm, viewer);
1301:     }
1302:   } else if (ishdf5) {
1303: #if defined(PETSC_HAVE_HDF5)
1304:     DMPlexView_HDF5_Internal(dm, viewer);
1305: #else
1306:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1307: #endif
1308:   } else if (isvtk) {
1309:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
1310:   } else if (isdraw) {
1311:     DMPlexView_Draw(dm, viewer);
1312:   } else if (isglvis) {
1313:     DMPlexView_GLVis(dm, viewer);
1314:   } else {
1315:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1316:   }
1317:   /* Optionally view the partition */
1318:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1319:   if (flg) {
1320:     Vec ranks;
1321:     DMPlexCreateRankField(dm, &ranks);
1322:     VecView(ranks, viewer);
1323:     VecDestroy(&ranks);
1324:   }
1325:   /* Optionally view a label */
1326:   PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, PETSC_MAX_PATH_LEN, &flg);
1327:   if (flg) {
1328:     DMLabel label;
1329:     Vec     val;

1331:     DMGetLabel(dm, name, &label);
1332:     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1333:     DMPlexCreateLabelField(dm, label, &val);
1334:     VecView(val, viewer);
1335:     VecDestroy(&val);
1336:   }
1337:   return(0);
1338: }

1340: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1341: {
1342:   PetscBool      ishdf5;

1348:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1349:   if (ishdf5) {
1350: #if defined(PETSC_HAVE_HDF5)
1351:     PetscViewerFormat format;
1352:     PetscViewerGetFormat(viewer, &format);
1353:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1354:       DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1355:     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1356:       DMPlexLoad_HDF5_Internal(dm, viewer);
1357:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1358: #else
1359:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1360: #endif
1361:   } else {
1362:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1363:   }
1364:   return(0);
1365: }

1367: PetscErrorCode DMDestroy_Plex(DM dm)
1368: {
1369:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1373:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1374:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1375:   PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);
1376:   if (--mesh->refct > 0) return(0);
1377:   PetscSectionDestroy(&mesh->coneSection);
1378:   PetscFree(mesh->cones);
1379:   PetscFree(mesh->coneOrientations);
1380:   PetscSectionDestroy(&mesh->supportSection);
1381:   PetscSectionDestroy(&mesh->subdomainSection);
1382:   PetscFree(mesh->supports);
1383:   PetscFree(mesh->facesTmp);
1384:   PetscFree(mesh->tetgenOpts);
1385:   PetscFree(mesh->triangleOpts);
1386:   PetscPartitionerDestroy(&mesh->partitioner);
1387:   DMLabelDestroy(&mesh->subpointMap);
1388:   ISDestroy(&mesh->globalVertexNumbers);
1389:   ISDestroy(&mesh->globalCellNumbers);
1390:   PetscSectionDestroy(&mesh->anchorSection);
1391:   ISDestroy(&mesh->anchorIS);
1392:   PetscSectionDestroy(&mesh->parentSection);
1393:   PetscFree(mesh->parents);
1394:   PetscFree(mesh->childIDs);
1395:   PetscSectionDestroy(&mesh->childSection);
1396:   PetscFree(mesh->children);
1397:   DMDestroy(&mesh->referenceTree);
1398:   PetscGridHashDestroy(&mesh->lbox);
1399:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1400:   PetscFree(mesh);
1401:   return(0);
1402: }

1404: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1405: {
1406:   PetscSection           sectionGlobal;
1407:   PetscInt               bs = -1, mbs;
1408:   PetscInt               localSize;
1409:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1410:   PetscErrorCode         ierr;
1411:   MatType                mtype;
1412:   ISLocalToGlobalMapping ltog;

1415:   MatInitializePackage();
1416:   mtype = dm->mattype;
1417:   DMGetGlobalSection(dm, &sectionGlobal);
1418:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1419:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1420:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1421:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1422:   MatSetType(*J, mtype);
1423:   MatSetFromOptions(*J);
1424:   MatGetBlockSize(*J, &mbs);
1425:   if (mbs > 1) bs = mbs;
1426:   PetscStrcmp(mtype, MATSHELL, &isShell);
1427:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1428:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1429:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1430:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1431:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1432:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1433:   PetscStrcmp(mtype, MATIS, &isMatIS);
1434:   if (!isShell) {
1435:     PetscSection subSection;
1436:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1437:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1438:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1445:       DMGetLocalSection(dm, &section);
1446:       PetscSectionGetStorageSize(section, &size);
1447:       PetscMalloc1(size,&ltogidx);
1448:       DMPlexGetSubdomainSection(dm, &subSection);
1449:     } else {
1450:       DMGetLocalToGlobalMapping(dm,&ltog);
1451:     }
1452:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1453:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1454:       PetscInt bdof;

1456:       PetscSectionGetDof(sectionGlobal, p, &dof);
1457:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1458:       dof  = dof < 0 ? -(dof+1) : dof;
1459:       bdof = cdof && (dof-cdof) ? 1 : dof;
1460:       if (dof) {
1461:         if (bs < 0)          {bs = bdof;}
1462:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1463:       }
1464:       if (isMatIS) {
1465:         PetscInt loff,c,off;
1466:         PetscSectionGetOffset(subSection, p, &loff);
1467:         PetscSectionGetOffset(sectionGlobal, p, &off);
1468:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1469:       }
1470:     }
1471:     /* Must have same blocksize on all procs (some might have no points) */
1472:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1473:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1474:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1475:     else                            {bs = bsMinMax[0];}
1476:     bs = PetscMax(1,bs);
1477:     if (isMatIS) { /* Must reduce indices by blocksize */
1478:       PetscInt l;

1480:       lsize = lsize/bs;
1481:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs;
1482:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1483:     }
1484:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1485:     if (isMatIS) {
1486:       ISLocalToGlobalMappingDestroy(&ltog);
1487:     }
1488:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1489:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1490:     PetscFree4(dnz, onz, dnzu, onzu);
1491:   }
1492:   MatSetDM(*J, dm);
1493:   return(0);
1494: }

1496: /*@
1497:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1499:   Not collective

1501:   Input Parameter:
1502: . mesh - The DMPlex

1504:   Output Parameters:
1505: . subsection - The subdomain section

1507:   Level: developer

1509: .seealso:
1510: @*/
1511: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1512: {
1513:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1518:   if (!mesh->subdomainSection) {
1519:     PetscSection section;
1520:     PetscSF      sf;

1522:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1523:     DMGetLocalSection(dm,&section);
1524:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1525:     PetscSFDestroy(&sf);
1526:   }
1527:   *subsection = mesh->subdomainSection;
1528:   return(0);
1529: }

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

1534:   Not collective

1536:   Input Parameter:
1537: . mesh - The DMPlex

1539:   Output Parameters:
1540: + pStart - The first mesh point
1541: - pEnd   - The upper bound for mesh points

1543:   Level: beginner

1545: .seealso: DMPlexCreate(), DMPlexSetChart()
1546: @*/
1547: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1548: {
1549:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1554:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1555:   return(0);
1556: }

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

1561:   Not collective

1563:   Input Parameters:
1564: + mesh - The DMPlex
1565: . pStart - The first mesh point
1566: - pEnd   - The upper bound for mesh points

1568:   Output Parameters:

1570:   Level: beginner

1572: .seealso: DMPlexCreate(), DMPlexGetChart()
1573: @*/
1574: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1575: {
1576:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1581:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1582:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1583:   return(0);
1584: }

1586: /*@
1587:   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG

1589:   Not collective

1591:   Input Parameters:
1592: + mesh - The DMPlex
1593: - p - The point, which must lie in the chart set with DMPlexSetChart()

1595:   Output Parameter:
1596: . size - The cone size for point p

1598:   Level: beginner

1600: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1601: @*/
1602: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1603: {
1604:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1610:   PetscSectionGetDof(mesh->coneSection, p, size);
1611:   return(0);
1612: }

1614: /*@
1615:   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG

1617:   Not collective

1619:   Input Parameters:
1620: + mesh - The DMPlex
1621: . p - The point, which must lie in the chart set with DMPlexSetChart()
1622: - size - The cone size for point p

1624:   Output Parameter:

1626:   Note:
1627:   This should be called after DMPlexSetChart().

1629:   Level: beginner

1631: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1632: @*/
1633: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1634: {
1635:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1642:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1643:   return(0);
1644: }

1646: /*@
1647:   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG

1649:   Not collective

1651:   Input Parameters:
1652: + mesh - The DMPlex
1653: . p - The point, which must lie in the chart set with DMPlexSetChart()
1654: - size - The additional cone size for point p

1656:   Output Parameter:

1658:   Note:
1659:   This should be called after DMPlexSetChart().

1661:   Level: beginner

1663: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1664: @*/
1665: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1666: {
1667:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1668:   PetscInt       csize;

1673:   PetscSectionAddDof(mesh->coneSection, p, size);
1674:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1676:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1677:   return(0);
1678: }

1680: /*@C
1681:   DMPlexGetCone - Return the points on the in-edges for this point in the DAG

1683:   Not collective

1685:   Input Parameters:
1686: + dm - The DMPlex
1687: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1692:   Level: beginner

1694:   Fortran Notes:
1695:   Since it returns an array, this routine is only available in Fortran 90, and you must
1696:   include petsc.h90 in your code.
1697:   You must also call DMPlexRestoreCone() after you finish using the returned array.
1698:   DMPlexRestoreCone() is not needed/available in C.

1700: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1701: @*/
1702: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1703: {
1704:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1705:   PetscInt       off;

1711:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1712:   *cone = &mesh->cones[off];
1713:   return(0);
1714: }

1716: /*@C
1717:   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG

1719:   Not collective

1721:   Input Parameters:
1722: + dm - The DMPlex
1723: - p - The IS of points, which must lie in the chart set with DMPlexSetChart()

1725:   Output Parameter:
1726: + pConesSection - PetscSection describing the layout of pCones
1727: - pCones - An array of points which are on the in-edges for the point set p

1729:   Level: intermediate

1731: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1732: @*/
1733: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1734: {
1735:   PetscSection        cs, newcs;
1736:   PetscInt            *cones;
1737:   PetscInt            *newarr=NULL;
1738:   PetscInt            n;
1739:   PetscErrorCode      ierr;

1742:   DMPlexGetCones(dm, &cones);
1743:   DMPlexGetConeSection(dm, &cs);
1744:   PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1745:   if (pConesSection) *pConesSection = newcs;
1746:   if (pCones) {
1747:     PetscSectionGetStorageSize(newcs, &n);
1748:     ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1749:   }
1750:   return(0);
1751: }

1753: /*@
1754:   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.

1756:   Not collective

1758:   Input Parameters:
1759: + dm - The DMPlex
1760: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()

1762:   Output Parameter:
1763: . expandedPoints - An array of vertices recursively expanded from input points

1765:   Level: advanced

1767:   Notes:
1768:   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
1769:   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.

1771: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth()
1772: @*/
1773: PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
1774: {
1775:   IS                  *expandedPointsAll;
1776:   PetscInt            depth;
1777:   PetscErrorCode      ierr;

1783:   DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);
1784:   *expandedPoints = expandedPointsAll[0];
1785:   PetscObjectReference((PetscObject)expandedPointsAll[0]);
1786:   DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);
1787:   return(0);
1788: }

1790: /*@
1791:   DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones).

1793:   Not collective

1795:   Input Parameters:
1796: + dm - The DMPlex
1797: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()

1799:   Output Parameter:
1800: + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
1801: . expandedPoints - (optional) An array of index sets with recursively expanded cones
1802: - sections - (optional) An array of sections which describe mappings from points to their cone points

1804:   Level: advanced

1806:   Notes:
1807:   Like DMPlexGetConeTuple() but recursive.

1809:   Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points.
1810:   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.

1812:   Array section has size equal to depth.  Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows:
1813:   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
1814:   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].

1816: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
1817: @*/
1818: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
1819: {
1820:   const PetscInt      *arr0=NULL, *cone=NULL;
1821:   PetscInt            *arr=NULL, *newarr=NULL;
1822:   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
1823:   IS                  *expandedPoints_;
1824:   PetscSection        *sections_;
1825:   PetscErrorCode      ierr;

1833:   ISGetLocalSize(points, &n);
1834:   ISGetIndices(points, &arr0);
1835:   DMPlexGetDepth(dm, &depth_);
1836:   PetscCalloc1(depth_, &expandedPoints_);
1837:   PetscCalloc1(depth_, &sections_);
1838:   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
1839:   for (d=depth_-1; d>=0; d--) {
1840:     PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]);
1841:     PetscSectionSetChart(sections_[d], 0, n);
1842:     for (i=0; i<n; i++) {
1843:       DMPlexGetDepthStratum(dm, d+1, &start, &end);
1844:       if (arr[i] >= start && arr[i] < end) {
1845:         DMPlexGetConeSize(dm, arr[i], &cn);
1846:         PetscSectionSetDof(sections_[d], i, cn);
1847:       } else {
1848:         PetscSectionSetDof(sections_[d], i, 1);
1849:       }
1850:     }
1851:     PetscSectionSetUp(sections_[d]);
1852:     PetscSectionGetStorageSize(sections_[d], &newn);
1853:     PetscMalloc1(newn, &newarr);
1854:     for (i=0; i<n; i++) {
1855:       PetscSectionGetDof(sections_[d], i, &cn);
1856:       PetscSectionGetOffset(sections_[d], i, &co);
1857:       if (cn > 1) {
1858:         DMPlexGetCone(dm, arr[i], &cone);
1859:         PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));
1860:       } else {
1861:         newarr[co] = arr[i];
1862:       }
1863:     }
1864:     ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);
1865:     arr = newarr;
1866:     n = newn;
1867:   }
1868:   *depth = depth_;
1869:   if (expandedPoints) *expandedPoints = expandedPoints_;
1870:   else {
1871:     for (d=0; d<depth_; d++) {ISDestroy(&expandedPoints_[d]);}
1872:     PetscFree(expandedPoints_);
1873:   }
1874:   if (sections) *sections = sections_;
1875:   else {
1876:     for (d=0; d<depth_; d++) {PetscSectionDestroy(&sections_[d]);}
1877:     PetscFree(sections_);
1878:   }
1879:   return(0);
1880: }

1882: /*@
1883:   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive

1885:   Not collective

1887:   Input Parameters:
1888: + dm - The DMPlex
1889: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()

1891:   Output Parameter:
1892: + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
1893: . expandedPoints - (optional) An array of recursively expanded cones
1894: - sections - (optional) An array of sections which describe mappings from points to their cone points

1896:   Level: advanced

1898:   Notes:
1899:   See DMPlexGetConeRecursive() for details.

1901: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
1902: @*/
1903: PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
1904: {
1905:   PetscInt            d, depth_;
1906:   PetscErrorCode      ierr;

1909:   DMPlexGetDepth(dm, &depth_);
1910:   if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
1911:   if (depth) *depth = 0;
1912:   if (expandedPoints) {
1913:     for (d=0; d<depth_; d++) {ISDestroy(&((*expandedPoints)[d]));}
1914:     PetscFree(*expandedPoints);
1915:   }
1916:   if (sections)  {
1917:     for (d=0; d<depth_; d++) {PetscSectionDestroy(&((*sections)[d]));}
1918:     PetscFree(*sections);
1919:   }
1920:   return(0);
1921: }

1923: /*@
1924:   DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point

1926:   Not collective

1928:   Input Parameters:
1929: + mesh - The DMPlex
1930: . p - The point, which must lie in the chart set with DMPlexSetChart()
1931: - cone - An array of points which are on the in-edges for point p

1933:   Output Parameter:

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

1938:   Developer Note: Why not call this DMPlexSetCover()

1940:   Level: beginner

1942: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1943: @*/
1944: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1945: {
1946:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1947:   PetscInt       pStart, pEnd;
1948:   PetscInt       dof, off, c;

1953:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1954:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1956:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1957:   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);
1958:   for (c = 0; c < dof; ++c) {
1959:     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);
1960:     mesh->cones[off+c] = cone[c];
1961:   }
1962:   return(0);
1963: }

1965: /*@C
1966:   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG

1968:   Not collective

1970:   Input Parameters:
1971: + mesh - The DMPlex
1972: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1980:   Level: beginner

1982:   Fortran Notes:
1983:   Since it returns an array, this routine is only available in Fortran 90, and you must
1984:   include petsc.h90 in your code.
1985:   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1986:   DMPlexRestoreConeOrientation() is not needed/available in C.

1988: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1989: @*/
1990: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1991: {
1992:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1993:   PetscInt       off;

1998: #if defined(PETSC_USE_DEBUG)
1999:   {
2000:     PetscInt dof;
2001:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2003:   }
2004: #endif
2005:   PetscSectionGetOffset(mesh->coneSection, p, &off);

2007:   *coneOrientation = &mesh->coneOrientations[off];
2008:   return(0);
2009: }

2011: /*@
2012:   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG

2014:   Not collective

2016:   Input Parameters:
2017: + mesh - The DMPlex
2018: . p - The point, which must lie in the chart set with DMPlexSetChart()
2019: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
2020:                     integer giving the prescription for cone traversal. If it is negative, the cone is
2021:                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
2022:                     the index of the cone point on which to start.

2024:   Output Parameter:

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

2029:   Level: beginner

2031: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2032: @*/
2033: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
2034: {
2035:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2036:   PetscInt       pStart, pEnd;
2037:   PetscInt       dof, off, c;

2042:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2043:   PetscSectionGetDof(mesh->coneSection, p, &dof);
2045:   PetscSectionGetOffset(mesh->coneSection, p, &off);
2046:   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);
2047:   for (c = 0; c < dof; ++c) {
2048:     PetscInt cdof, o = coneOrientation[c];

2050:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
2051:     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);
2052:     mesh->coneOrientations[off+c] = o;
2053:   }
2054:   return(0);
2055: }

2057: /*@
2058:   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG

2060:   Not collective

2062:   Input Parameters:
2063: + mesh - The DMPlex
2064: . p - The point, which must lie in the chart set with DMPlexSetChart()
2065: . conePos - The local index in the cone where the point should be put
2066: - conePoint - The mesh point to insert

2068:   Level: beginner

2070: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2071: @*/
2072: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
2073: {
2074:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2075:   PetscInt       pStart, pEnd;
2076:   PetscInt       dof, off;

2081:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2082:   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);
2083:   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);
2084:   PetscSectionGetDof(mesh->coneSection, p, &dof);
2085:   PetscSectionGetOffset(mesh->coneSection, p, &off);
2086:   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);
2087:   mesh->cones[off+conePos] = conePoint;
2088:   return(0);
2089: }

2091: /*@
2092:   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG

2094:   Not collective

2096:   Input Parameters:
2097: + mesh - The DMPlex
2098: . p - The point, which must lie in the chart set with DMPlexSetChart()
2099: . conePos - The local index in the cone where the point should be put
2100: - coneOrientation - The point orientation to insert

2102:   Level: beginner

2104: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2105: @*/
2106: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
2107: {
2108:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2109:   PetscInt       pStart, pEnd;
2110:   PetscInt       dof, off;

2115:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2116:   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);
2117:   PetscSectionGetDof(mesh->coneSection, p, &dof);
2118:   PetscSectionGetOffset(mesh->coneSection, p, &off);
2119:   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);
2120:   mesh->coneOrientations[off+conePos] = coneOrientation;
2121:   return(0);
2122: }

2124: /*@
2125:   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG

2127:   Not collective

2129:   Input Parameters:
2130: + mesh - The DMPlex
2131: - p - The point, which must lie in the chart set with DMPlexSetChart()

2133:   Output Parameter:
2134: . size - The support size for point p

2136:   Level: beginner

2138: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
2139: @*/
2140: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
2141: {
2142:   DM_Plex       *mesh = (DM_Plex*) dm->data;

2148:   PetscSectionGetDof(mesh->supportSection, p, size);
2149:   return(0);
2150: }

2152: /*@
2153:   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG

2155:   Not collective

2157:   Input Parameters:
2158: + mesh - The DMPlex
2159: . p - The point, which must lie in the chart set with DMPlexSetChart()
2160: - size - The support size for point p

2162:   Output Parameter:

2164:   Note:
2165:   This should be called after DMPlexSetChart().

2167:   Level: beginner

2169: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
2170: @*/
2171: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
2172: {
2173:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

2180:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
2181:   return(0);
2182: }

2184: /*@C
2185:   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG

2187:   Not collective

2189:   Input Parameters:
2190: + mesh - The DMPlex
2191: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

2196:   Level: beginner

2198:   Fortran Notes:
2199:   Since it returns an array, this routine is only available in Fortran 90, and you must
2200:   include petsc.h90 in your code.
2201:   You must also call DMPlexRestoreSupport() after you finish using the returned array.
2202:   DMPlexRestoreSupport() is not needed/available in C.

2204: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2205: @*/
2206: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
2207: {
2208:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2209:   PetscInt       off;

2215:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2216:   *support = &mesh->supports[off];
2217:   return(0);
2218: }

2220: /*@
2221:   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers

2223:   Not collective

2225:   Input Parameters:
2226: + mesh - The DMPlex
2227: . p - The point, which must lie in the chart set with DMPlexSetChart()
2228: - support - An array of points which are on the out-edges for point p

2230:   Output Parameter:

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

2235:   Level: beginner

2237: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
2238: @*/
2239: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
2240: {
2241:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2242:   PetscInt       pStart, pEnd;
2243:   PetscInt       dof, off, c;

2248:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2249:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2251:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2252:   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);
2253:   for (c = 0; c < dof; ++c) {
2254:     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);
2255:     mesh->supports[off+c] = support[c];
2256:   }
2257:   return(0);
2258: }

2260: /*@
2261:   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG

2263:   Not collective

2265:   Input Parameters:
2266: + mesh - The DMPlex
2267: . p - The point, which must lie in the chart set with DMPlexSetChart()
2268: . supportPos - The local index in the cone where the point should be put
2269: - supportPoint - The mesh point to insert

2271:   Level: beginner

2273: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2274: @*/
2275: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
2276: {
2277:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2278:   PetscInt       pStart, pEnd;
2279:   PetscInt       dof, off;

2284:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2285:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2286:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2287:   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);
2288:   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);
2289:   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);
2290:   mesh->supports[off+supportPos] = supportPoint;
2291:   return(0);
2292: }

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

2297:   Not collective

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

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

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

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

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

2318:   Level: beginner

2320: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2321: @*/
2322: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2323: {
2324:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2325:   PetscInt       *closure, *fifo;
2326:   const PetscInt *tmp = NULL, *tmpO = NULL;
2327:   PetscInt        tmpSize, t;
2328:   PetscInt        depth       = 0, maxSize;
2329:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2330:   PetscErrorCode  ierr;

2334:   DMPlexGetDepth(dm, &depth);
2335:   /* This is only 1-level */
2336:   if (useCone) {
2337:     DMPlexGetConeSize(dm, p, &tmpSize);
2338:     DMPlexGetCone(dm, p, &tmp);
2339:     DMPlexGetConeOrientation(dm, p, &tmpO);
2340:   } else {
2341:     DMPlexGetSupportSize(dm, p, &tmpSize);
2342:     DMPlexGetSupport(dm, p, &tmp);
2343:   }
2344:   if (depth == 1) {
2345:     if (*points) {
2346:       closure = *points;
2347:     } else {
2348:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2349:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2350:     }
2351:     closure[0] = p; closure[1] = 0;
2352:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2353:       closure[closureSize]   = tmp[t];
2354:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2355:     }
2356:     if (numPoints) *numPoints = closureSize/2;
2357:     if (points)    *points    = closure;
2358:     return(0);
2359:   }
2360:   {
2361:     PetscInt c, coneSeries, s,supportSeries;

2363:     c = mesh->maxConeSize;
2364:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2365:     s = mesh->maxSupportSize;
2366:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2367:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2368:   }
2369:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2370:   if (*points) {
2371:     closure = *points;
2372:   } else {
2373:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2374:   }
2375:   closure[0] = p; closure[1] = 0;
2376:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2377:     const PetscInt cp = tmp[t];
2378:     const PetscInt co = tmpO ? tmpO[t] : 0;

2380:     closure[closureSize]   = cp;
2381:     closure[closureSize+1] = co;
2382:     fifo[fifoSize]         = cp;
2383:     fifo[fifoSize+1]       = co;
2384:   }
2385:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2386:   while (fifoSize - fifoStart) {
2387:     const PetscInt q   = fifo[fifoStart];
2388:     const PetscInt o   = fifo[fifoStart+1];
2389:     const PetscInt rev = o >= 0 ? 0 : 1;
2390:     const PetscInt off = rev ? -(o+1) : o;

2392:     if (useCone) {
2393:       DMPlexGetConeSize(dm, q, &tmpSize);
2394:       DMPlexGetCone(dm, q, &tmp);
2395:       DMPlexGetConeOrientation(dm, q, &tmpO);
2396:     } else {
2397:       DMPlexGetSupportSize(dm, q, &tmpSize);
2398:       DMPlexGetSupport(dm, q, &tmp);
2399:       tmpO = NULL;
2400:     }
2401:     for (t = 0; t < tmpSize; ++t) {
2402:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2403:       const PetscInt cp = tmp[i];
2404:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2405:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2406:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2407:       PetscInt       co = tmpO ? tmpO[i] : 0;
2408:       PetscInt       c;

2410:       if (rev) {
2411:         PetscInt childSize, coff;
2412:         DMPlexGetConeSize(dm, cp, &childSize);
2413:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2414:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2415:       }
2416:       /* Check for duplicate */
2417:       for (c = 0; c < closureSize; c += 2) {
2418:         if (closure[c] == cp) break;
2419:       }
2420:       if (c == closureSize) {
2421:         closure[closureSize]   = cp;
2422:         closure[closureSize+1] = co;
2423:         fifo[fifoSize]         = cp;
2424:         fifo[fifoSize+1]       = co;
2425:         closureSize           += 2;
2426:         fifoSize              += 2;
2427:       }
2428:     }
2429:     fifoStart += 2;
2430:   }
2431:   if (numPoints) *numPoints = closureSize/2;
2432:   if (points)    *points    = closure;
2433:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2434:   return(0);
2435: }

2437: /*@C
2438:   DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG with a specified initial orientation

2440:   Not collective

2442:   Input Parameters:
2443: + mesh - The DMPlex
2444: . p - The point, which must lie in the chart set with DMPlexSetChart()
2445: . orientation - The orientation of the point
2446: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2447: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

2462:   Level: beginner

2464: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2465: @*/
2466: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2467: {
2468:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2469:   PetscInt       *closure, *fifo;
2470:   const PetscInt *tmp = NULL, *tmpO = NULL;
2471:   PetscInt        tmpSize, t;
2472:   PetscInt        depth       = 0, maxSize;
2473:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2474:   PetscErrorCode  ierr;

2478:   DMPlexGetDepth(dm, &depth);
2479:   /* This is only 1-level */
2480:   if (useCone) {
2481:     DMPlexGetConeSize(dm, p, &tmpSize);
2482:     DMPlexGetCone(dm, p, &tmp);
2483:     DMPlexGetConeOrientation(dm, p, &tmpO);
2484:   } else {
2485:     DMPlexGetSupportSize(dm, p, &tmpSize);
2486:     DMPlexGetSupport(dm, p, &tmp);
2487:   }
2488:   if (depth == 1) {
2489:     if (*points) {
2490:       closure = *points;
2491:     } else {
2492:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2493:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2494:     }
2495:     closure[0] = p; closure[1] = ornt;
2496:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2497:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2498:       closure[closureSize]   = tmp[i];
2499:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2500:     }
2501:     if (numPoints) *numPoints = closureSize/2;
2502:     if (points)    *points    = closure;
2503:     return(0);
2504:   }
2505:   {
2506:     PetscInt c, coneSeries, s,supportSeries;

2508:     c = mesh->maxConeSize;
2509:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2510:     s = mesh->maxSupportSize;
2511:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2512:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2513:   }
2514:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2515:   if (*points) {
2516:     closure = *points;
2517:   } else {
2518:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2519:   }
2520:   closure[0] = p; closure[1] = ornt;
2521:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2522:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2523:     const PetscInt cp = tmp[i];
2524:     PetscInt       co = tmpO ? tmpO[i] : 0;

2526:     if (ornt < 0) {
2527:       PetscInt childSize, coff;
2528:       DMPlexGetConeSize(dm, cp, &childSize);
2529:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2530:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2531:     }
2532:     closure[closureSize]   = cp;
2533:     closure[closureSize+1] = co;
2534:     fifo[fifoSize]         = cp;
2535:     fifo[fifoSize+1]       = co;
2536:   }
2537:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2538:   while (fifoSize - fifoStart) {
2539:     const PetscInt q   = fifo[fifoStart];
2540:     const PetscInt o   = fifo[fifoStart+1];
2541:     const PetscInt rev = o >= 0 ? 0 : 1;
2542:     const PetscInt off = rev ? -(o+1) : o;

2544:     if (useCone) {
2545:       DMPlexGetConeSize(dm, q, &tmpSize);
2546:       DMPlexGetCone(dm, q, &tmp);
2547:       DMPlexGetConeOrientation(dm, q, &tmpO);
2548:     } else {
2549:       DMPlexGetSupportSize(dm, q, &tmpSize);
2550:       DMPlexGetSupport(dm, q, &tmp);
2551:       tmpO = NULL;
2552:     }
2553:     for (t = 0; t < tmpSize; ++t) {
2554:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2555:       const PetscInt cp = tmp[i];
2556:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2557:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2558:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2559:       PetscInt       co = tmpO ? tmpO[i] : 0;
2560:       PetscInt       c;

2562:       if (rev) {
2563:         PetscInt childSize, coff;
2564:         DMPlexGetConeSize(dm, cp, &childSize);
2565:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2566:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2567:       }
2568:       /* Check for duplicate */
2569:       for (c = 0; c < closureSize; c += 2) {
2570:         if (closure[c] == cp) break;
2571:       }
2572:       if (c == closureSize) {
2573:         closure[closureSize]   = cp;
2574:         closure[closureSize+1] = co;
2575:         fifo[fifoSize]         = cp;
2576:         fifo[fifoSize+1]       = co;
2577:         closureSize           += 2;
2578:         fifoSize              += 2;
2579:       }
2580:     }
2581:     fifoStart += 2;
2582:   }
2583:   if (numPoints) *numPoints = closureSize/2;
2584:   if (points)    *points    = closure;
2585:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2586:   return(0);
2587: }

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

2592:   Not collective

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

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

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

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

2610:   Level: beginner

2612: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2613: @*/
2614: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2615: {

2622:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2623:   if (numPoints) *numPoints = 0;
2624:   return(0);
2625: }

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

2630:   Not collective

2632:   Input Parameter:
2633: . mesh - The DMPlex

2635:   Output Parameters:
2636: + maxConeSize - The maximum number of in-edges
2637: - maxSupportSize - The maximum number of out-edges

2639:   Level: beginner

2641: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2642: @*/
2643: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2644: {
2645:   DM_Plex *mesh = (DM_Plex*) dm->data;

2649:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2650:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2651:   return(0);
2652: }

2654: PetscErrorCode DMSetUp_Plex(DM dm)
2655: {
2656:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2657:   PetscInt       size;

2662:   PetscSectionSetUp(mesh->coneSection);
2663:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2664:   PetscMalloc1(size, &mesh->cones);
2665:   PetscCalloc1(size, &mesh->coneOrientations);
2666:   if (mesh->maxSupportSize) {
2667:     PetscSectionSetUp(mesh->supportSection);
2668:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2669:     PetscMalloc1(size, &mesh->supports);
2670:   }
2671:   return(0);
2672: }

2674: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2675: {

2679:   if (subdm) {DMClone(dm, subdm);}
2680:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2681:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2682:   if (dm->useNatural && dm->sfMigration) {
2683:     PetscSF        sfMigrationInv,sfNatural;
2684:     PetscSection   section, sectionSeq;

2686:     (*subdm)->sfMigration = dm->sfMigration;
2687:     PetscObjectReference((PetscObject) dm->sfMigration);
2688:     DMGetLocalSection((*subdm), &section);
2689:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2690:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2691:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2693:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2694:     (*subdm)->sfNatural = sfNatural;
2695:     PetscSectionDestroy(&sectionSeq);
2696:     PetscSFDestroy(&sfMigrationInv);
2697:   }
2698:   return(0);
2699: }

2701: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2702: {
2704:   PetscInt       i = 0;

2707:   DMClone(dms[0], superdm);
2708:   DMCreateSectionSuperDM(dms, len, is, superdm);
2709:   (*superdm)->useNatural = PETSC_FALSE;
2710:   for (i = 0; i < len; i++){
2711:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2712:       PetscSF        sfMigrationInv,sfNatural;
2713:       PetscSection   section, sectionSeq;

2715:       (*superdm)->sfMigration = dms[i]->sfMigration;
2716:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2717:       (*superdm)->useNatural = PETSC_TRUE;
2718:       DMGetLocalSection((*superdm), &section);
2719:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2720:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2721:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2723:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2724:       (*superdm)->sfNatural = sfNatural;
2725:       PetscSectionDestroy(&sectionSeq);
2726:       PetscSFDestroy(&sfMigrationInv);
2727:       break;
2728:     }
2729:   }
2730:   return(0);
2731: }

2733: /*@
2734:   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information

2736:   Not collective

2738:   Input Parameter:
2739: . mesh - The DMPlex

2741:   Output Parameter:

2743:   Note:
2744:   This should be called after all calls to DMPlexSetCone()

2746:   Level: beginner

2748: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2749: @*/
2750: PetscErrorCode DMPlexSymmetrize(DM dm)
2751: {
2752:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2753:   PetscInt      *offsets;
2754:   PetscInt       supportSize;
2755:   PetscInt       pStart, pEnd, p;

2760:   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2761:   PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);
2762:   /* Calculate support sizes */
2763:   DMPlexGetChart(dm, &pStart, &pEnd);
2764:   for (p = pStart; p < pEnd; ++p) {
2765:     PetscInt dof, off, c;

2767:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2768:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2769:     for (c = off; c < off+dof; ++c) {
2770:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2771:     }
2772:   }
2773:   for (p = pStart; p < pEnd; ++p) {
2774:     PetscInt dof;

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

2778:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2779:   }
2780:   PetscSectionSetUp(mesh->supportSection);
2781:   /* Calculate supports */
2782:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2783:   PetscMalloc1(supportSize, &mesh->supports);
2784:   PetscCalloc1(pEnd - pStart, &offsets);
2785:   for (p = pStart; p < pEnd; ++p) {
2786:     PetscInt dof, off, c;

2788:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2789:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2790:     for (c = off; c < off+dof; ++c) {
2791:       const PetscInt q = mesh->cones[c];
2792:       PetscInt       offS;

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

2796:       mesh->supports[offS+offsets[q]] = p;
2797:       ++offsets[q];
2798:     }
2799:   }
2800:   PetscFree(offsets);
2801:   PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);
2802:   return(0);
2803: }

2805: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
2806: {
2807:   IS             stratumIS;

2811:   if (pStart >= pEnd) return(0);
2812: #if defined(PETSC_USE_DEBUG)
2813:   {
2814:     PetscInt  qStart, qEnd, numLevels, level;
2815:     PetscBool overlap = PETSC_FALSE;
2816:     DMLabelGetNumValues(label, &numLevels);
2817:     for (level = 0; level < numLevels; level++) {
2818:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2819:       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
2820:     }
2821:     if (overlap) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %D range [%D,%D) overlaps with depth %D range [%D,%D)", depth, pStart, pEnd, level, qStart, qEnd);
2822:   }
2823: #endif
2824:   ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);
2825:   DMLabelSetStratumIS(label, depth, stratumIS);
2826:   ISDestroy(&stratumIS);
2827:   return(0);
2828: }

2830: static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt);

2832: /*@
2833:   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
2834:   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2835:   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2836:   the DAG.

2838:   Collective on dm

2840:   Input Parameter:
2841: . mesh - The DMPlex

2843:   Output Parameter:

2845:   Notes:
2846:   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
2847:   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
2848:   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2849:   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
2850:   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.

2852:   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
2853:   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
2854:   we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose
2855:   to interpolate only that one (e0), so that
2856: $  cone(c0) = {e0, v2}
2857: $  cone(e0) = {v0, v1}
2858:   If DMPlexStratify() is run on this mesh, it will give depths
2859: $  depth 0 = {v0, v1, v2}
2860: $  depth 1 = {e0, c0}
2861:   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.

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

2865:   Level: beginner

2867: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2868: @*/
2869: PetscErrorCode DMPlexStratify(DM dm)
2870: {
2871:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2872:   DMLabel        label;
2873:   PetscInt       pStart, pEnd, p;
2874:   PetscInt       numRoots = 0, numLeaves = 0;
2875:   PetscInt       cMax, fMax, eMax, vMax;

2880:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);

2882:   /* Create depth label */
2883:   DMPlexGetChart(dm, &pStart, &pEnd);
2884:   DMCreateLabel(dm, "depth");
2885:   DMPlexGetDepthLabel(dm, &label);

2887:   {
2888:     /* Initialize roots and count leaves */
2889:     PetscInt sMin = PETSC_MAX_INT;
2890:     PetscInt sMax = PETSC_MIN_INT;
2891:     PetscInt coneSize, supportSize;

2893:     for (p = pStart; p < pEnd; ++p) {
2894:       DMPlexGetConeSize(dm, p, &coneSize);
2895:       DMPlexGetSupportSize(dm, p, &supportSize);
2896:       if (!coneSize && supportSize) {
2897:         sMin = PetscMin(p, sMin);
2898:         sMax = PetscMax(p, sMax);
2899:         ++numRoots;
2900:       } else if (!supportSize && coneSize) {
2901:         ++numLeaves;
2902:       } else if (!supportSize && !coneSize) {
2903:         /* Isolated points */
2904:         sMin = PetscMin(p, sMin);
2905:         sMax = PetscMax(p, sMax);
2906:       }
2907:     }
2908:     DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);
2909:   }

2911:   if (numRoots + numLeaves == (pEnd - pStart)) {
2912:     PetscInt sMin = PETSC_MAX_INT;
2913:     PetscInt sMax = PETSC_MIN_INT;
2914:     PetscInt coneSize, supportSize;

2916:     for (p = pStart; p < pEnd; ++p) {
2917:       DMPlexGetConeSize(dm, p, &coneSize);
2918:       DMPlexGetSupportSize(dm, p, &supportSize);
2919:       if (!supportSize && coneSize) {
2920:         sMin = PetscMin(p, sMin);
2921:         sMax = PetscMax(p, sMax);
2922:       }
2923:     }
2924:     DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);
2925:   } else {
2926:     PetscInt level = 0;
2927:     PetscInt qStart, qEnd, q;

2929:     DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2930:     while (qEnd > qStart) {
2931:       PetscInt sMin = PETSC_MAX_INT;
2932:       PetscInt sMax = PETSC_MIN_INT;

2934:       for (q = qStart; q < qEnd; ++q) {
2935:         const PetscInt *support;
2936:         PetscInt        supportSize, s;

2938:         DMPlexGetSupportSize(dm, q, &supportSize);
2939:         DMPlexGetSupport(dm, q, &support);
2940:         for (s = 0; s < supportSize; ++s) {
2941:           sMin = PetscMin(support[s], sMin);
2942:           sMax = PetscMax(support[s], sMax);
2943:         }
2944:       }
2945:       DMLabelGetNumValues(label, &level);
2946:       DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);
2947:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2948:     }
2949:   }
2950:   { /* just in case there is an empty process */
2951:     PetscInt numValues, maxValues = 0, v;

2953:     DMLabelGetNumValues(label, &numValues);
2954:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2955:     for (v = numValues; v < maxValues; v++) {
2956:       DMLabelAddStratum(label, v);
2957:     }
2958:   }
2959:   PetscObjectStateGet((PetscObject) label, &mesh->depthState);

2961:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2962:   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2963:     PetscInt dim;
2964:     DMLabel  dimLabel;

2966:     DMGetDimension(dm, &dim);
2967:     DMCreateLabel(dm, "dim");
2968:     DMGetLabel(dm, "dim", &dimLabel);
2969:     if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2970:     if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2971:     if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2972:     if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2973:   }
2974:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2975:   return(0);
2976: }

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

2981:   Not Collective

2983:   Input Parameters:
2984: + dm - The DMPlex object
2985: . numPoints - The number of input points for the join
2986: - points - The input points

2988:   Output Parameters:
2989: + numCoveredPoints - The number of points in the join
2990: - coveredPoints - The points in the join

2992:   Level: intermediate

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

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

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

3002: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
3003: @*/
3004: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3005: {
3006:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3007:   PetscInt      *join[2];
3008:   PetscInt       joinSize, i = 0;
3009:   PetscInt       dof, off, p, c, m;

3017:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
3018:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
3019:   /* Copy in support of first point */
3020:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
3021:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
3022:   for (joinSize = 0; joinSize < dof; ++joinSize) {
3023:     join[i][joinSize] = mesh->supports[off+joinSize];
3024:   }
3025:   /* Check each successive support */
3026:   for (p = 1; p < numPoints; ++p) {
3027:     PetscInt newJoinSize = 0;

3029:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
3030:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
3031:     for (c = 0; c < dof; ++c) {
3032:       const PetscInt point = mesh->supports[off+c];

3034:       for (m = 0; m < joinSize; ++m) {
3035:         if (point == join[i][m]) {
3036:           join[1-i][newJoinSize++] = point;
3037:           break;
3038:         }
3039:       }
3040:     }
3041:     joinSize = newJoinSize;
3042:     i        = 1-i;
3043:   }
3044:   *numCoveredPoints = joinSize;
3045:   *coveredPoints    = join[i];
3046:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3047:   return(0);
3048: }

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

3053:   Not Collective

3055:   Input Parameters:
3056: + dm - The DMPlex object
3057: . numPoints - The number of input points for the join
3058: - points - The input points

3060:   Output Parameters:
3061: + numCoveredPoints - The number of points in the join
3062: - coveredPoints - The points in the join

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

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

3070:   Level: intermediate

3072: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
3073: @*/
3074: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3075: {

3083:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3084:   if (numCoveredPoints) *numCoveredPoints = 0;
3085:   return(0);
3086: }

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

3091:   Not Collective

3093:   Input Parameters:
3094: + dm - The DMPlex object
3095: . numPoints - The number of input points for the join
3096: - points - The input points

3098:   Output Parameters:
3099: + numCoveredPoints - The number of points in the join
3100: - coveredPoints - The points in the join

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

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

3108:   Level: intermediate

3110: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
3111: @*/
3112: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3113: {
3114:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3115:   PetscInt      *offsets, **closures;
3116:   PetscInt      *join[2];
3117:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
3118:   PetscInt       p, d, c, m, ms;


3127:   DMPlexGetDepth(dm, &depth);
3128:   PetscCalloc1(numPoints, &closures);
3129:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3130:   ms      = mesh->maxSupportSize;
3131:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
3132:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
3133:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

3135:   for (p = 0; p < numPoints; ++p) {
3136:     PetscInt closureSize;

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

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

3144:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
3145:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
3146:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3147:           offsets[p*(depth+2)+d+1] = i;
3148:           break;
3149:         }
3150:       }
3151:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
3152:     }
3153:     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);
3154:   }
3155:   for (d = 0; d < depth+1; ++d) {
3156:     PetscInt dof;

3158:     /* Copy in support of first point */
3159:     dof = offsets[d+1] - offsets[d];
3160:     for (joinSize = 0; joinSize < dof; ++joinSize) {
3161:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
3162:     }
3163:     /* Check each successive cone */
3164:     for (p = 1; p < numPoints && joinSize; ++p) {
3165:       PetscInt newJoinSize = 0;

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

3171:         for (m = 0; m < joinSize; ++m) {
3172:           if (point == join[i][m]) {
3173:             join[1-i][newJoinSize++] = point;
3174:             break;
3175:           }
3176:         }
3177:       }
3178:       joinSize = newJoinSize;
3179:       i        = 1-i;
3180:     }
3181:     if (joinSize) break;
3182:   }
3183:   *numCoveredPoints = joinSize;
3184:   *coveredPoints    = join[i];
3185:   for (p = 0; p < numPoints; ++p) {
3186:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
3187:   }
3188:   PetscFree(closures);
3189:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3190:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3191:   return(0);
3192: }

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

3197:   Not Collective

3199:   Input Parameters:
3200: + dm - The DMPlex object
3201: . numPoints - The number of input points for the meet
3202: - points - The input points

3204:   Output Parameters:
3205: + numCoveredPoints - The number of points in the meet
3206: - coveredPoints - The points in the meet

3208:   Level: intermediate

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

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

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

3218: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
3219: @*/
3220: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
3221: {
3222:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3223:   PetscInt      *meet[2];
3224:   PetscInt       meetSize, i = 0;
3225:   PetscInt       dof, off, p, c, m;

3233:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
3234:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
3235:   /* Copy in cone of first point */
3236:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
3237:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
3238:   for (meetSize = 0; meetSize < dof; ++meetSize) {
3239:     meet[i][meetSize] = mesh->cones[off+meetSize];
3240:   }
3241:   /* Check each successive cone */
3242:   for (p = 1; p < numPoints; ++p) {
3243:     PetscInt newMeetSize = 0;

3245:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
3246:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
3247:     for (c = 0; c < dof; ++c) {
3248:       const PetscInt point = mesh->cones[off+c];

3250:       for (m = 0; m < meetSize; ++m) {
3251:         if (point == meet[i][m]) {
3252:           meet[1-i][newMeetSize++] = point;
3253:           break;
3254:         }
3255:       }
3256:     }
3257:     meetSize = newMeetSize;
3258:     i        = 1-i;
3259:   }
3260:   *numCoveringPoints = meetSize;
3261:   *coveringPoints    = meet[i];
3262:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3263:   return(0);
3264: }

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

3269:   Not Collective

3271:   Input Parameters:
3272: + dm - The DMPlex object
3273: . numPoints - The number of input points for the meet
3274: - points - The input points

3276:   Output Parameters:
3277: + numCoveredPoints - The number of points in the meet
3278: - coveredPoints - The points in the meet

3280:   Level: intermediate

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

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

3288: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
3289: @*/
3290: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3291: {

3299:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3300:   if (numCoveredPoints) *numCoveredPoints = 0;
3301:   return(0);
3302: }

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

3307:   Not Collective

3309:   Input Parameters:
3310: + dm - The DMPlex object
3311: . numPoints - The number of input points for the meet
3312: - points - The input points

3314:   Output Parameters:
3315: + numCoveredPoints - The number of points in the meet
3316: - coveredPoints - The points in the meet

3318:   Level: intermediate

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

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

3326: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3327: @*/
3328: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3329: {
3330:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3331:   PetscInt      *offsets, **closures;
3332:   PetscInt      *meet[2];
3333:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
3334:   PetscInt       p, h, c, m, mc;


3343:   DMPlexGetDepth(dm, &height);
3344:   PetscMalloc1(numPoints, &closures);
3345:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3346:   mc      = mesh->maxConeSize;
3347:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3348:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3349:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

3351:   for (p = 0; p < numPoints; ++p) {
3352:     PetscInt closureSize;

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

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

3360:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3361:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3362:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3363:           offsets[p*(height+2)+h+1] = i;
3364:           break;
3365:         }
3366:       }
3367:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3368:     }
3369:     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);
3370:   }
3371:   for (h = 0; h < height+1; ++h) {
3372:     PetscInt dof;

3374:     /* Copy in cone of first point */
3375:     dof = offsets[h+1] - offsets[h];
3376:     for (meetSize = 0; meetSize < dof; ++meetSize) {
3377:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3378:     }
3379:     /* Check each successive cone */
3380:     for (p = 1; p < numPoints && meetSize; ++p) {
3381:       PetscInt newMeetSize = 0;

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

3387:         for (m = 0; m < meetSize; ++m) {
3388:           if (point == meet[i][m]) {
3389:             meet[1-i][newMeetSize++] = point;
3390:             break;
3391:           }
3392:         }
3393:       }
3394:       meetSize = newMeetSize;
3395:       i        = 1-i;
3396:     }
3397:     if (meetSize) break;
3398:   }
3399:   *numCoveredPoints = meetSize;
3400:   *coveredPoints    = meet[i];
3401:   for (p = 0; p < numPoints; ++p) {
3402:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3403:   }
3404:   PetscFree(closures);
3405:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3406:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3407:   return(0);
3408: }

3410: /*@C
3411:   DMPlexEqual - Determine if two DMs have the same topology

3413:   Not Collective

3415:   Input Parameters:
3416: + dmA - A DMPlex object
3417: - dmB - A DMPlex object

3419:   Output Parameters:
3420: . equal - PETSC_TRUE if the topologies are identical

3422:   Level: intermediate

3424:   Notes:
3425:   We are not solving graph isomorphism, so we do not permutation.

3427: .seealso: DMPlexGetCone()
3428: @*/
3429: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3430: {
3431:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


3439:   *equal = PETSC_FALSE;
3440:   DMPlexGetDepth(dmA, &depth);
3441:   DMPlexGetDepth(dmB, &depthB);
3442:   if (depth != depthB) return(0);
3443:   DMPlexGetChart(dmA, &pStart,  &pEnd);
3444:   DMPlexGetChart(dmB, &pStartB, &pEndB);
3445:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3446:   for (p = pStart; p < pEnd; ++p) {
3447:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3448:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

3450:     DMPlexGetConeSize(dmA, p, &coneSize);
3451:     DMPlexGetCone(dmA, p, &cone);
3452:     DMPlexGetConeOrientation(dmA, p, &ornt);
3453:     DMPlexGetConeSize(dmB, p, &coneSizeB);
3454:     DMPlexGetCone(dmB, p, &coneB);
3455:     DMPlexGetConeOrientation(dmB, p, &orntB);
3456:     if (coneSize != coneSizeB) return(0);
3457:     for (c = 0; c < coneSize; ++c) {
3458:       if (cone[c] != coneB[c]) return(0);
3459:       if (ornt[c] != orntB[c]) return(0);
3460:     }
3461:     DMPlexGetSupportSize(dmA, p, &supportSize);
3462:     DMPlexGetSupport(dmA, p, &support);
3463:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
3464:     DMPlexGetSupport(dmB, p, &supportB);
3465:     if (supportSize != supportSizeB) return(0);
3466:     for (s = 0; s < supportSize; ++s) {
3467:       if (support[s] != supportB[s]) return(0);
3468:     }
3469:   }
3470:   *equal = PETSC_TRUE;
3471:   return(0);
3472: }

3474: /*@C
3475:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

3477:   Not Collective

3479:   Input Parameters:
3480: + dm         - The DMPlex
3481: . cellDim    - The cell dimension
3482: - numCorners - The number of vertices on a cell

3484:   Output Parameters:
3485: . numFaceVertices - The number of vertices on a face

3487:   Level: developer

3489:   Notes:
3490:   Of course this can only work for a restricted set of symmetric shapes

3492: .seealso: DMPlexGetCone()
3493: @*/
3494: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3495: {
3496:   MPI_Comm       comm;

3500:   PetscObjectGetComm((PetscObject)dm,&comm);
3502:   switch (cellDim) {
3503:   case 0:
3504:     *numFaceVertices = 0;
3505:     break;
3506:   case 1:
3507:     *numFaceVertices = 1;
3508:     break;
3509:   case 2:
3510:     switch (numCorners) {
3511:     case 3: /* triangle */
3512:       *numFaceVertices = 2; /* Edge has 2 vertices */
3513:       break;
3514:     case 4: /* quadrilateral */
3515:       *numFaceVertices = 2; /* Edge has 2 vertices */
3516:       break;
3517:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3518:       *numFaceVertices = 3; /* Edge has 3 vertices */
3519:       break;
3520:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3521:       *numFaceVertices = 3; /* Edge has 3 vertices */
3522:       break;
3523:     default:
3524:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3525:     }
3526:     break;
3527:   case 3:
3528:     switch (numCorners) {
3529:     case 4: /* tetradehdron */
3530:       *numFaceVertices = 3; /* Face has 3 vertices */
3531:       break;
3532:     case 6: /* tet cohesive cells */
3533:       *numFaceVertices = 4; /* Face has 4 vertices */
3534:       break;
3535:     case 8: /* hexahedron */
3536:       *numFaceVertices = 4; /* Face has 4 vertices */
3537:       break;
3538:     case 9: /* tet cohesive Lagrange cells */
3539:       *numFaceVertices = 6; /* Face has 6 vertices */
3540:       break;
3541:     case 10: /* quadratic tetrahedron */
3542:       *numFaceVertices = 6; /* Face has 6 vertices */
3543:       break;
3544:     case 12: /* hex cohesive Lagrange cells */
3545:       *numFaceVertices = 6; /* Face has 6 vertices */
3546:       break;
3547:     case 18: /* quadratic tet cohesive Lagrange cells */
3548:       *numFaceVertices = 6; /* Face has 6 vertices */
3549:       break;
3550:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3551:       *numFaceVertices = 9; /* Face has 9 vertices */
3552:       break;
3553:     default:
3554:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3555:     }
3556:     break;
3557:   default:
3558:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3559:   }
3560:   return(0);
3561: }

3563: /*@
3564:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3566:   Not Collective

3568:   Input Parameter:
3569: . dm    - The DMPlex object

3571:   Output Parameter:
3572: . depthLabel - The DMLabel recording point depth

3574:   Level: developer

3576: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3577: @*/
3578: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3579: {
3583:   *depthLabel = dm->depthLabel;
3584:   return(0);
3585: }

3587: /*@
3588:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3590:   Not Collective

3592:   Input Parameter:
3593: . dm    - The DMPlex object

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

3598:   Level: developer

3600:   Notes:
3601:   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
3602:   The point depth is described more in detail in DMPlexSymmetrize().

3604: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexSymmetrize()
3605: @*/
3606: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3607: {
3608:   DMLabel        label;
3609:   PetscInt       d = 0;

3615:   DMPlexGetDepthLabel(dm, &label);
3616:   if (label) {DMLabelGetNumValues(label, &d);}
3617:   *depth = d-1;
3618:   return(0);
3619: }

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

3624:   Not Collective

3626:   Input Parameters:
3627: + dm           - The DMPlex object
3628: - stratumValue - The requested depth

3630:   Output Parameters:
3631: + start - The first point at this depth
3632: - end   - One beyond the last point at this depth

3634:   Notes:
3635:   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
3636:   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
3637:   higher dimension, e.g., "edges".

3639:   Level: developer

3641: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3642: @*/
3643: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3644: {
3645:   DMLabel        label;
3646:   PetscInt       pStart, pEnd;

3653:   DMPlexGetChart(dm, &pStart, &pEnd);
3654:   if (pStart == pEnd) return(0);
3655:   if (stratumValue < 0) {
3656:     if (start) *start = pStart;
3657:     if (end)   *end   = pEnd;
3658:     return(0);
3659:   }
3660:   DMPlexGetDepthLabel(dm, &label);
3661:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3662:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3663:   return(0);
3664: }

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

3669:   Not Collective

3671:   Input Parameters:
3672: + dm           - The DMPlex object
3673: - stratumValue - The requested height

3675:   Output Parameters:
3676: + start - The first point at this height
3677: - end   - One beyond the last point at this height

3679:   Notes:
3680:   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
3681:   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
3682:   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".

3684:   Level: developer

3686: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3687: @*/
3688: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3689: {
3690:   DMLabel        label;
3691:   PetscInt       depth, pStart, pEnd;

3698:   DMPlexGetChart(dm, &pStart, &pEnd);
3699:   if (pStart == pEnd) return(0);
3700:   if (stratumValue < 0) {
3701:     if (start) *start = pStart;
3702:     if (end)   *end   = pEnd;
3703:     return(0);
3704:   }
3705:   DMPlexGetDepthLabel(dm, &label);
3706:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3707:   DMLabelGetNumValues(label, &depth);
3708:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3709:   return(0);
3710: }

3712: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3713: {
3714:   PetscSection   section, s;
3715:   Mat            m;
3716:   PetscInt       maxHeight;

3720:   DMClone(dm, cdm);
3721:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3722:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3723:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3724:   DMSetLocalSection(*cdm, section);
3725:   PetscSectionDestroy(&section);
3726:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3727:   MatCreate(PETSC_COMM_SELF, &m);
3728:   DMSetDefaultConstraints(*cdm, s, m);
3729:   PetscSectionDestroy(&s);
3730:   MatDestroy(&m);

3732:   DMSetNumFields(*cdm, 1);
3733:   DMCreateDS(*cdm);
3734:   return(0);
3735: }

3737: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3738: {
3739:   Vec            coordsLocal;
3740:   DM             coordsDM;

3744:   *field = NULL;
3745:   DMGetCoordinatesLocal(dm,&coordsLocal);
3746:   DMGetCoordinateDM(dm,&coordsDM);
3747:   if (coordsLocal && coordsDM) {
3748:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3749:   }
3750:   return(0);
3751: }

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

3756:   Not Collective

3758:   Input Parameters:
3759: . dm        - The DMPlex object

3761:   Output Parameter:
3762: . section - The PetscSection object

3764:   Level: developer

3766: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3767: @*/
3768: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3769: {
3770:   DM_Plex *mesh = (DM_Plex*) dm->data;

3774:   if (section) *section = mesh->coneSection;
3775:   return(0);
3776: }

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

3781:   Not Collective

3783:   Input Parameters:
3784: . dm        - The DMPlex object

3786:   Output Parameter:
3787: . section - The PetscSection object

3789:   Level: developer

3791: .seealso: DMPlexGetConeSection()
3792: @*/
3793: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3794: {
3795:   DM_Plex *mesh = (DM_Plex*) dm->data;

3799:   if (section) *section = mesh->supportSection;
3800:   return(0);
3801: }

3803: /*@C
3804:   DMPlexGetCones - Return cone data

3806:   Not Collective

3808:   Input Parameters:
3809: . dm        - The DMPlex object

3811:   Output Parameter:
3812: . cones - The cone for each point

3814:   Level: developer

3816: .seealso: DMPlexGetConeSection()
3817: @*/
3818: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3819: {
3820:   DM_Plex *mesh = (DM_Plex*) dm->data;

3824:   if (cones) *cones = mesh->cones;
3825:   return(0);
3826: }

3828: /*@C
3829:   DMPlexGetConeOrientations - Return cone orientation data

3831:   Not Collective

3833:   Input Parameters:
3834: . dm        - The DMPlex object

3836:   Output Parameter:
3837: . coneOrientations - The cone orientation for each point

3839:   Level: developer

3841: .seealso: DMPlexGetConeSection()
3842: @*/
3843: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3844: {
3845:   DM_Plex *mesh = (DM_Plex*) dm->data;

3849:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3850:   return(0);
3851: }

3853: /******************************** FEM Support **********************************/

3855: /*
3856:  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
3857:  representing a line in the section.
3858: */
3859: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
3860: {

3864:   PetscSectionGetFieldComponents(section, field, Nc);
3865:   if (line < 0) {
3866:     *k = 0;
3867:     *Nc = 0;
3868:   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
3869:     *k = 1;
3870:   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
3871:     /* An order k SEM disc has k-1 dofs on an edge */
3872:     PetscSectionGetFieldDof(section, line, field, k);
3873:     *k = *k / *Nc + 1;
3874:   }
3875:   return(0);
3876: }

3878: /*@

3880:   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
3881:   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
3882:   section provided (or the section of the DM).

3884:   Input Parameters:
3885: + dm      - The DM
3886: . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
3887: - section - The PetscSection to reorder, or NULL for the default section

3889:   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
3890:   degree of the basis.

3892:   Example:
3893:   A typical interpolated single-quad mesh might order points as
3894: .vb
3895:   [c0, v1, v2, v3, v4, e5, e6, e7, e8]

3897:   v4 -- e6 -- v3
3898:   |           |
3899:   e7    c0    e8
3900:   |           |
3901:   v1 -- e5 -- v2
3902: .ve

3904:   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
3905:   dofs in the order of points, e.g.,
3906: .vb
3907:     c0 -> [0,1,2,3]
3908:     v1 -> [4]
3909:     ...
3910:     e5 -> [8, 9]
3911: .ve

3913:   which corresponds to the dofs
3914: .vb
3915:     6   10  11  7
3916:     13  2   3   15
3917:     12  0   1   14
3918:     4   8   9   5
3919: .ve

3921:   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
3922: .vb
3923:   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
3924: .ve

3926:   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
3927: .vb
3928:    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
3929: .ve

3931:   Level: developer

3933: .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection()
3934: @*/
3935: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
3936: {
3937:   DMLabel        label;
3938:   PetscInt      *perm;
3939:   PetscInt       dim, depth = -1, eStart = -1, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3940:   PetscBool      vertexchart;

3944:   DMGetDimension(dm, &dim);
3945:   if (dim < 1) return(0);
3946:   if (point < 0) {
3947:     PetscInt sStart,sEnd;

3949:     DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);
3950:     point = sEnd-sStart ? sStart : point;
3951:   }
3952:   DMPlexGetDepthLabel(dm, &label);
3953:   if (point >= 0) { DMLabelGetValue(label, point, &depth); }
3954:   if (!section) {DMGetLocalSection(dm, &section);}
3955:   if (depth == 1) {eStart = point;}
3956:   else if  (depth == dim) {
3957:     const PetscInt *cone;

3959:     DMPlexGetCone(dm, point, &cone);
3960:     if (dim == 2) eStart = cone[0];
3961:     else if (dim == 3) {
3962:       const PetscInt *cone2;
3963:       DMPlexGetCone(dm, cone[0], &cone2);
3964:       eStart = cone2[0];
3965:     } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim);
3966:   } else if (depth >= 0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim);
3967:   {                             /* Determine whether the chart covers all points or just vertices. */
3968:     PetscInt pStart,pEnd,cStart,cEnd;
3969:     DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);
3970:     PetscSectionGetChart(section,&cStart,&cEnd);
3971:     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
3972:     else vertexchart = PETSC_FALSE;                                 /* Assume all interpolated points are in chart */
3973:   }
3974:   PetscSectionGetNumFields(section, &Nf);
3975:   for (f = 0; f < Nf; ++f) {
3976:     PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3977:     size += PetscPowInt(k+1, dim)*Nc;
3978:   }
3979:   PetscMalloc1(size, &perm);
3980:   for (f = 0; f < Nf; ++f) {
3981:     switch (dim) {
3982:     case 1:
3983:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3984:       /*
3985:         Original ordering is [ edge of length k-1; vtx0; vtx1 ]
3986:         We want              [ vtx0; edge of length k-1; vtx1 ]
3987:       */
3988:       for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
3989:       for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
3990:       for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
3991:       foffset = offset;
3992:       break;
3993:     case 2:
3994:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3995:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3996:       /* The SEM order is

3998:          v_lb, {e_b}, v_rb,
3999:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
4000:          v_lt, reverse {e_t}, v_rt
4001:       */
4002:       {
4003:         const PetscInt of   = 0;
4004:         const PetscInt oeb  = of   + PetscSqr(k-1);
4005:         const PetscInt oer  = oeb  + (k-1);
4006:         const PetscInt oet  = oer  + (k-1);
4007:         const PetscInt oel  = oet  + (k-1);
4008:         const PetscInt ovlb = oel  + (k-1);
4009:         const PetscInt ovrb = ovlb + 1;
4010:         const PetscInt ovrt = ovrb + 1;
4011:         const PetscInt ovlt = ovrt + 1;
4012:         PetscInt       o;

4014:         /* bottom */
4015:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
4016:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4017:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
4018:         /* middle */
4019:         for (i = 0; i < k-1; ++i) {
4020:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
4021:           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;
4022:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
4023:         }
4024:         /* top */
4025:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
4026:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4027:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
4028:         foffset = offset;
4029:       }
4030:       break;
4031:     case 3:
4032:       /* The original hex closure is

4034:          {c,
4035:           f_b, f_t, f_f, f_b, f_r, f_l,
4036:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
4037:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
4038:       */
4039:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
4040:       /* The SEM order is
4041:          Bottom Slice
4042:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
4043:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
4044:          v_blb, {e_bb}, v_brb,

4046:          Middle Slice (j)
4047:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
4048:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
4049:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

4051:          Top Slice
4052:          v_tlf, {e_tf}, v_trf,
4053:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
4054:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
4055:       */
4056:       {
4057:         const PetscInt oc    = 0;
4058:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
4059:         const PetscInt oft   = ofb   + PetscSqr(k-1);
4060:         const PetscInt off   = oft   + PetscSqr(k-1);
4061:         const PetscInt ofk   = off   + PetscSqr(k-1);
4062:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
4063:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
4064:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
4065:         const PetscInt oebb  = oebl  + (k-1);
4066:         const PetscInt oebr  = oebb  + (k-1);
4067:         const PetscInt oebf  = oebr  + (k-1);
4068:         const PetscInt oetf  = oebf  + (k-1);
4069:         const PetscInt oetr  = oetf  + (k-1);
4070:         const PetscInt oetb  = oetr  + (k-1);
4071:         const PetscInt oetl  = oetb  + (k-1);
4072:         const PetscInt oerf  = oetl  + (k-1);
4073:         const PetscInt oelf  = oerf  + (k-1);
4074:         const PetscInt oelb  = oelf  + (k-1);
4075:         const PetscInt oerb  = oelb  + (k-1);
4076:         const PetscInt ovblf = oerb  + (k-1);
4077:         const PetscInt ovblb = ovblf + 1;
4078:         const PetscInt ovbrb = ovblb + 1;
4079:         const PetscInt ovbrf = ovbrb + 1;
4080:         const PetscInt ovtlf = ovbrf + 1;
4081:         const PetscInt ovtrf = ovtlf + 1;
4082:         const PetscInt ovtrb = ovtrf + 1;
4083:         const PetscInt ovtlb = ovtrb + 1;
4084:         PetscInt       o, n;

4086:         /* Bottom Slice */
4087:         /*   bottom */
4088:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
4089:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4090:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
4091:         /*   middle */
4092:         for (i = 0; i < k-1; ++i) {
4093:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
4094:           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;}
4095:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
4096:         }
4097:         /*   top */
4098:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
4099:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4100:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

4102:         /* Middle Slice */
4103:         for (j = 0; j < k-1; ++j) {
4104:           /*   bottom */
4105:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
4106:           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;
4107:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
4108:           /*   middle */
4109:           for (i = 0; i < k-1; ++i) {
4110:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
4111:             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;
4112:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
4113:           }
4114:           /*   top */
4115:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
4116:           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;
4117:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
4118:         }

4120:         /* Top Slice */
4121:         /*   bottom */
4122:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
4123:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4124:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
4125:         /*   middle */
4126:         for (i = 0; i < k-1; ++i) {
4127:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
4128:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
4129:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
4130:         }
4131:         /*   top */
4132:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
4133:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4134:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

4136:         foffset = offset;
4137:       }
4138:       break;
4139:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
4140:     }
4141:   }
4142:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
4143:   /* Check permutation */
4144:   {
4145:     PetscInt *check;

4147:     PetscMalloc1(size, &check);
4148:     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]);}
4149:     for (i = 0; i < size; ++i) check[perm[i]] = i;
4150:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
4151:     PetscFree(check);
4152:   }
4153:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
4154:   return(0);
4155: }

4157: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
4158: {
4159:   PetscDS        prob;
4160:   PetscInt       depth, Nf, h;
4161:   DMLabel        label;

4165:   DMGetDS(dm, &prob);
4166:   Nf      = prob->Nf;
4167:   label   = dm->depthLabel;
4168:   *dspace = NULL;
4169:   if (field < Nf) {
4170:     PetscObject disc = prob->disc[field];

4172:     if (disc->classid == PETSCFE_CLASSID) {
4173:       PetscDualSpace dsp;

4175:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
4176:       DMLabelGetNumValues(label,&depth);
4177:       DMLabelGetValue(label,point,&h);
4178:       h    = depth - 1 - h;
4179:       if (h) {
4180:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
4181:       } else {
4182:         *dspace = dsp;
4183:       }
4184:     }
4185:   }
4186:   return(0);
4187: }


4190: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4191: {
4192:   PetscScalar    *array, *vArray;
4193:   const PetscInt *cone, *coneO;
4194:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
4195:   PetscErrorCode  ierr;

4198:   PetscSectionGetChart(section, &pStart, &pEnd);
4199:   DMPlexGetConeSize(dm, point, &numPoints);
4200:   DMPlexGetCone(dm, point, &cone);
4201:   DMPlexGetConeOrientation(dm, point, &coneO);
4202:   if (!values || !*values) {
4203:     if ((point >= pStart) && (point < pEnd)) {
4204:       PetscInt dof;

4206:       PetscSectionGetDof(section, point, &dof);
4207:       size += dof;
4208:     }
4209:     for (p = 0; p < numPoints; ++p) {
4210:       const PetscInt cp = cone[p];
4211:       PetscInt       dof;

4213:       if ((cp < pStart) || (cp >= pEnd)) continue;
4214:       PetscSectionGetDof(section, cp, &dof);
4215:       size += dof;
4216:     }
4217:     if (!values) {
4218:       if (csize) *csize = size;
4219:       return(0);
4220:     }
4221:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
4222:   } else {
4223:     array = *values;
4224:   }
4225:   size = 0;
4226:   VecGetArray(v, &vArray);
4227:   if ((point >= pStart) && (point < pEnd)) {
4228:     PetscInt     dof, off, d;
4229:     PetscScalar *varr;

4231:     PetscSectionGetDof(section, point, &dof);
4232:     PetscSectionGetOffset(section, point, &off);
4233:     varr = &vArray[off];
4234:     for (d = 0; d < dof; ++d, ++offset) {
4235:       array[offset] = varr[d];
4236:     }
4237:     size += dof;
4238:   }
4239:   for (p = 0; p < numPoints; ++p) {
4240:     const PetscInt cp = cone[p];
4241:     PetscInt       o  = coneO[p];
4242:     PetscInt       dof, off, d;
4243:     PetscScalar   *varr;

4245:     if ((cp < pStart) || (cp >= pEnd)) continue;
4246:     PetscSectionGetDof(section, cp, &dof);
4247:     PetscSectionGetOffset(section, cp, &off);
4248:     varr = &vArray[off];
4249:     if (o >= 0) {
4250:       for (d = 0; d < dof; ++d, ++offset) {
4251:         array[offset] = varr[d];
4252:       }
4253:     } else {
4254:       for (d = dof-1; d >= 0; --d, ++offset) {
4255:         array[offset] = varr[d];
4256:       }
4257:     }
4258:     size += dof;
4259:   }
4260:   VecRestoreArray(v, &vArray);
4261:   if (!*values) {
4262:     if (csize) *csize = size;
4263:     *values = array;
4264:   } else {
4265:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4266:     *csize = size;
4267:   }
4268:   return(0);
4269: }

4271: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4272: {
4273:   const PetscInt *cla;
4274:   PetscInt       np, *pts = NULL;

4278:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
4279:   if (!*clPoints) {
4280:     PetscInt pStart, pEnd, p, q;

4282:     PetscSectionGetChart(section, &pStart, &pEnd);
4283:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
4284:     /* Compress out points not in the section */
4285:     for (p = 0, q = 0; p < np; p++) {
4286:       PetscInt r = pts[2*p];
4287:       if ((r >= pStart) && (r < pEnd)) {
4288:         pts[q*2]   = r;
4289:         pts[q*2+1] = pts[2*p+1];
4290:         ++q;
4291:       }
4292:     }
4293:     np = q;
4294:     cla = NULL;
4295:   } else {
4296:     PetscInt dof, off;

4298:     PetscSectionGetDof(*clSec, point, &dof);
4299:     PetscSectionGetOffset(*clSec, point, &off);
4300:     ISGetIndices(*clPoints, &cla);
4301:     np   = dof/2;
4302:     pts  = (PetscInt *) &cla[off];
4303:   }
4304:   *numPoints = np;
4305:   *points    = pts;
4306:   *clp       = cla;

4308:   return(0);
4309: }

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

4316:   if (!*clPoints) {
4317:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
4318:   } else {
4319:     ISRestoreIndices(*clPoints, clp);
4320:   }
4321:   *numPoints = 0;
4322:   *points    = NULL;
4323:   *clSec     = NULL;
4324:   *clPoints  = NULL;
4325:   *clp       = NULL;
4326:   return(0);
4327: }

4329: 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[])
4330: {
4331:   PetscInt          offset = 0, p;
4332:   const PetscInt    **perms = NULL;
4333:   const PetscScalar **flips = NULL;
4334:   PetscErrorCode    ierr;

4337:   *size = 0;
4338:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4339:   for (p = 0; p < numPoints; p++) {
4340:     const PetscInt    point = points[2*p];
4341:     const PetscInt    *perm = perms ? perms[p] : NULL;
4342:     const PetscScalar *flip = flips ? flips[p] : NULL;
4343:     PetscInt          dof, off, d;
4344:     const PetscScalar *varr;

4346:     PetscSectionGetDof(section, point, &dof);
4347:     PetscSectionGetOffset(section, point, &off);
4348:     varr = &vArray[off];
4349:     if (clperm) {
4350:       if (perm) {
4351:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4352:       } else {
4353:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4354:       }
4355:       if (flip) {
4356:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4357:       }
4358:     } else {
4359:       if (perm) {
4360:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4361:       } else {
4362:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4363:       }
4364:       if (flip) {
4365:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4366:       }
4367:     }
4368:     offset += dof;
4369:   }
4370:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4371:   *size = offset;
4372:   return(0);
4373: }

4375: 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[])
4376: {
4377:   PetscInt          offset = 0, f;
4378:   PetscErrorCode    ierr;

4381:   *size = 0;
4382:   for (f = 0; f < numFields; ++f) {
4383:     PetscInt          p;
4384:     const PetscInt    **perms = NULL;
4385:     const PetscScalar **flips = NULL;

4387:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4388:     for (p = 0; p < numPoints; p++) {
4389:       const PetscInt    point = points[2*p];
4390:       PetscInt          fdof, foff, b;
4391:       const PetscScalar *varr;
4392:       const PetscInt    *perm = perms ? perms[p] : NULL;
4393:       const PetscScalar *flip = flips ? flips[p] : NULL;

4395:       PetscSectionGetFieldDof(section, point, f, &fdof);
4396:       PetscSectionGetFieldOffset(section, point, f, &foff);
4397:       varr = &vArray[foff];
4398:       if (clperm) {
4399:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4400:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4401:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4402:       } else {
4403:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4404:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4405:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4406:       }
4407:       offset += fdof;
4408:     }
4409:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4410:   }
4411:   *size = offset;
4412:   return(0);
4413: }

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

4418:   Not collective

4420:   Input Parameters:
4421: + dm - The DM
4422: . section - The section describing the layout in v, or NULL to use the default section
4423: . v - The local vector
4424: . point - The point in the DM
4425: . csize - The size of the input values array, or NULL
4426: - values - An array to use for the values, or NULL to have it allocated automatically

4428:   Output Parameters:
4429: + csize - The number of values in the closure
4430: - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed

4432: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4433: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4434: $ assembly function, and a user may already have allocated storage for this operation.
4435: $
4436: $ A typical use could be
4437: $
4438: $  values = NULL;
4439: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4440: $  for (cl = 0; cl < clSize; ++cl) {
4441: $    <Compute on closure>
4442: $  }
4443: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4444: $
4445: $ or
4446: $
4447: $  PetscMalloc1(clMaxSize, &values);
4448: $  for (p = pStart; p < pEnd; ++p) {
4449: $    clSize = clMaxSize;
4450: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4451: $    for (cl = 0; cl < clSize; ++cl) {
4452: $      <Compute on closure>
4453: $    }
4454: $  }
4455: $  PetscFree(values);

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

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

4463:   Level: intermediate

4465: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4466: @*/
4467: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4468: {
4469:   PetscSection       clSection;
4470:   IS                 clPoints;
4471:   PetscScalar       *array;
4472:   const PetscScalar *vArray;
4473:   PetscInt          *points = NULL;
4474:   const PetscInt    *clp, *perm;
4475:   PetscInt           depth, numFields, numPoints, size;
4476:   PetscErrorCode     ierr;

4480:   if (!section) {DMGetLocalSection(dm, &section);}
4483:   DMPlexGetDepth(dm, &depth);
4484:   PetscSectionGetNumFields(section, &numFields);
4485:   if (depth == 1 && numFields < 2) {
4486:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4487:     return(0);
4488:   }
4489:   /* Get points */
4490:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4491:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4492:   /* Get array */
4493:   if (!values || !*values) {
4494:     PetscInt asize = 0, dof, p;

4496:     for (p = 0; p < numPoints*2; p += 2) {
4497:       PetscSectionGetDof(section, points[p], &dof);
4498:       asize += dof;
4499:     }
4500:     if (!values) {
4501:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4502:       if (csize) *csize = asize;
4503:       return(0);
4504:     }
4505:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4506:   } else {
4507:     array = *values;
4508:   }
4509:   VecGetArrayRead(v, &vArray);
4510:   /* Get values */
4511:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4512:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4513:   /* Cleanup points */
4514:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4515:   /* Cleanup array */
4516:   VecRestoreArrayRead(v, &vArray);
4517:   if (!*values) {
4518:     if (csize) *csize = size;
4519:     *values = array;
4520:   } else {
4521:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4522:     *csize = size;
4523:   }
4524:   return(0);
4525: }

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

4530:   Not collective

4532:   Input Parameters:
4533: + dm - The DM
4534: . section - The section describing the layout in v, or NULL to use the default section
4535: . v - The local vector
4536: . point - The point in the DM
4537: . csize - The number of values in the closure, or NULL
4538: - values - The array of values, which is a borrowed array and should not be freed

4540:   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()

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

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

4548:   Level: intermediate

4550: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4551: @*/
4552: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4553: {
4554:   PetscInt       size = 0;

4558:   /* Should work without recalculating size */
4559:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4560:   *values = NULL;
4561:   return(0);
4562: }

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

4567: 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[])
4568: {
4569:   PetscInt        cdof;   /* The number of constraints on this point */
4570:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4571:   PetscScalar    *a;
4572:   PetscInt        off, cind = 0, k;
4573:   PetscErrorCode  ierr;

4576:   PetscSectionGetConstraintDof(section, point, &cdof);
4577:   PetscSectionGetOffset(section, point, &off);
4578:   a    = &array[off];
4579:   if (!cdof || setBC) {
4580:     if (clperm) {
4581:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4582:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4583:     } else {
4584:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4585:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4586:     }
4587:   } else {
4588:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4589:     if (clperm) {
4590:       if (perm) {for (k = 0; k < dof; ++k) {
4591:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4592:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4593:         }
4594:       } else {
4595:         for (k = 0; k < dof; ++k) {
4596:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4597:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4598:         }
4599:       }
4600:     } else {
4601:       if (perm) {
4602:         for (k = 0; k < dof; ++k) {
4603:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4604:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4605:         }
4606:       } else {
4607:         for (k = 0; k < dof; ++k) {
4608:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4609:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4610:         }
4611:       }
4612:     }
4613:   }
4614:   return(0);
4615: }

4617: 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[])
4618: {
4619:   PetscInt        cdof;   /* The number of constraints on this point */
4620:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4621:   PetscScalar    *a;
4622:   PetscInt        off, cind = 0, k;
4623:   PetscErrorCode  ierr;

4626:   PetscSectionGetConstraintDof(section, point, &cdof);
4627:   PetscSectionGetOffset(section, point, &off);
4628:   a    = &array[off];
4629:   if (cdof) {
4630:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4631:     if (clperm) {
4632:       if (perm) {
4633:         for (k = 0; k < dof; ++k) {
4634:           if ((cind < cdof) && (k == cdofs[cind])) {
4635:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4636:             cind++;
4637:           }
4638:         }
4639:       } else {
4640:         for (k = 0; k < dof; ++k) {
4641:           if ((cind < cdof) && (k == cdofs[cind])) {
4642:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4643:             cind++;
4644:           }
4645:         }
4646:       }
4647:     } else {
4648:       if (perm) {
4649:         for (k = 0; k < dof; ++k) {
4650:           if ((cind < cdof) && (k == cdofs[cind])) {
4651:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4652:             cind++;
4653:           }
4654:         }
4655:       } else {
4656:         for (k = 0; k < dof; ++k) {
4657:           if ((cind < cdof) && (k == cdofs[cind])) {
4658:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4659:             cind++;
4660:           }
4661:         }
4662:       }
4663:     }
4664:   }
4665:   return(0);
4666: }

4668: 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[])
4669: {
4670:   PetscScalar    *a;
4671:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4672:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4673:   PetscInt        cind = 0, b;
4674:   PetscErrorCode  ierr;

4677:   PetscSectionGetFieldDof(section, point, f, &fdof);
4678:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4679:   PetscSectionGetFieldOffset(section, point, f, &foff);
4680:   a    = &array[foff];
4681:   if (!fcdof || setBC) {
4682:     if (clperm) {
4683:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4684:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4685:     } else {
4686:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4687:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4688:     }
4689:   } else {
4690:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4691:     if (clperm) {
4692:       if (perm) {
4693:         for (b = 0; b < fdof; b++) {
4694:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4695:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4696:         }
4697:       } else {
4698:         for (b = 0; b < fdof; b++) {
4699:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4700:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4701:         }
4702:       }
4703:     } else {
4704:       if (perm) {
4705:         for (b = 0; b < fdof; b++) {
4706:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4707:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4708:         }
4709:       } else {
4710:         for (b = 0; b < fdof; b++) {
4711:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4712:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4713:         }
4714:       }
4715:     }
4716:   }
4717:   *offset += fdof;
4718:   return(0);
4719: }

4721: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4722: {
4723:   PetscScalar    *a;
4724:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4725:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4726:   PetscInt        cind = 0, ncind = 0, b;
4727:   PetscBool       ncSet, fcSet;
4728:   PetscErrorCode  ierr;

4731:   PetscSectionGetFieldDof(section, point, f, &fdof);
4732:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4733:   PetscSectionGetFieldOffset(section, point, f, &foff);
4734:   a    = &array[foff];
4735:   if (fcdof) {
4736:     /* We just override fcdof and fcdofs with Ncc and comps */
4737:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4738:     if (clperm) {
4739:       if (perm) {
4740:         if (comps) {
4741:           for (b = 0; b < fdof; b++) {
4742:             ncSet = fcSet = PETSC_FALSE;
4743:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4744:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4745:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4746:           }
4747:         } else {
4748:           for (b = 0; b < fdof; b++) {
4749:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4750:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4751:               ++cind;
4752:             }
4753:           }
4754:         }
4755:       } else {
4756:         if (comps) {
4757:           for (b = 0; b < fdof; b++) {
4758:             ncSet = fcSet = PETSC_FALSE;
4759:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4760:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4761:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4762:           }
4763:         } else {
4764:           for (b = 0; b < fdof; b++) {
4765:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4766:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4767:               ++cind;
4768:             }
4769:           }
4770:         }
4771:       }
4772:     } else {
4773:       if (perm) {
4774:         if (comps) {
4775:           for (b = 0; b < fdof; b++) {
4776:             ncSet = fcSet = PETSC_FALSE;
4777:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4778:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4779:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4780:           }
4781:         } else {
4782:           for (b = 0; b < fdof; b++) {
4783:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4784:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4785:               ++cind;
4786:             }
4787:           }
4788:         }
4789:       } else {
4790:         if (comps) {
4791:           for (b = 0; b < fdof; b++) {
4792:             ncSet = fcSet = PETSC_FALSE;
4793:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4794:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4795:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4796:           }
4797:         } else {
4798:           for (b = 0; b < fdof; b++) {
4799:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4800:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4801:               ++cind;
4802:             }
4803:           }
4804:         }
4805:       }
4806:     }
4807:   }
4808:   *offset += fdof;
4809:   return(0);
4810: }

4812: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4813: {
4814:   PetscScalar    *array;
4815:   const PetscInt *cone, *coneO;
4816:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4817:   PetscErrorCode  ierr;

4820:   PetscSectionGetChart(section, &pStart, &pEnd);
4821:   DMPlexGetConeSize(dm, point, &numPoints);
4822:   DMPlexGetCone(dm, point, &cone);
4823:   DMPlexGetConeOrientation(dm, point, &coneO);
4824:   VecGetArray(v, &array);
4825:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4826:     const PetscInt cp = !p ? point : cone[p-1];
4827:     const PetscInt o  = !p ? 0     : coneO[p-1];

4829:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4830:     PetscSectionGetDof(section, cp, &dof);
4831:     /* ADD_VALUES */
4832:     {
4833:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4834:       PetscScalar    *a;
4835:       PetscInt        cdof, coff, cind = 0, k;

4837:       PetscSectionGetConstraintDof(section, cp, &cdof);
4838:       PetscSectionGetOffset(section, cp, &coff);
4839:       a    = &array[coff];
4840:       if (!cdof) {
4841:         if (o >= 0) {
4842:           for (k = 0; k < dof; ++k) {
4843:             a[k] += values[off+k];
4844:           }
4845:         } else {
4846:           for (k = 0; k < dof; ++k) {
4847:             a[k] += values[off+dof-k-1];
4848:           }
4849:         }
4850:       } else {
4851:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4852:         if (o >= 0) {
4853:           for (k = 0; k < dof; ++k) {
4854:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4855:             a[k] += values[off+k];
4856:           }
4857:         } else {
4858:           for (k = 0; k < dof; ++k) {
4859:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4860:             a[k] += values[off+dof-k-1];
4861:           }
4862:         }
4863:       }
4864:     }
4865:   }
4866:   VecRestoreArray(v, &array);
4867:   return(0);
4868: }

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

4873:   Not collective

4875:   Input Parameters:
4876: + dm - The DM
4877: . section - The section describing the layout in v, or NULL to use the default section
4878: . v - The local vector
4879: . point - The point in the DM
4880: . values - The array of values
4881: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4882:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4887:   Level: intermediate

4889: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4890: @*/
4891: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4892: {
4893:   PetscSection    clSection;
4894:   IS              clPoints;
4895:   PetscScalar    *array;
4896:   PetscInt       *points = NULL;
4897:   const PetscInt *clp, *clperm;
4898:   PetscInt        depth, numFields, numPoints, p;
4899:   PetscErrorCode  ierr;

4903:   if (!section) {DMGetLocalSection(dm, &section);}
4906:   DMPlexGetDepth(dm, &depth);
4907:   PetscSectionGetNumFields(section, &numFields);
4908:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4909:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4910:     return(0);
4911:   }
4912:   /* Get points */
4913:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4914:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4915:   /* Get array */
4916:   VecGetArray(v, &array);
4917:   /* Get values */
4918:   if (numFields > 0) {
4919:     PetscInt offset = 0, f;
4920:     for (f = 0; f < numFields; ++f) {
4921:       const PetscInt    **perms = NULL;
4922:       const PetscScalar **flips = NULL;

4924:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4925:       switch (mode) {
4926:       case INSERT_VALUES:
4927:         for (p = 0; p < numPoints; p++) {
4928:           const PetscInt    point = points[2*p];
4929:           const PetscInt    *perm = perms ? perms[p] : NULL;
4930:           const PetscScalar *flip = flips ? flips[p] : NULL;
4931:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4932:         } break;
4933:       case INSERT_ALL_VALUES:
4934:         for (p = 0; p < numPoints; p++) {
4935:           const PetscInt    point = points[2*p];
4936:           const PetscInt    *perm = perms ? perms[p] : NULL;
4937:           const PetscScalar *flip = flips ? flips[p] : NULL;
4938:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4939:         } break;
4940:       case INSERT_BC_VALUES:
4941:         for (p = 0; p < numPoints; p++) {
4942:           const PetscInt    point = points[2*p];
4943:           const PetscInt    *perm = perms ? perms[p] : NULL;
4944:           const PetscScalar *flip = flips ? flips[p] : NULL;
4945:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4946:         } break;
4947:       case ADD_VALUES:
4948:         for (p = 0; p < numPoints; p++) {
4949:           const PetscInt    point = points[2*p];
4950:           const PetscInt    *perm = perms ? perms[p] : NULL;
4951:           const PetscScalar *flip = flips ? flips[p] : NULL;
4952:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4953:         } break;
4954:       case ADD_ALL_VALUES:
4955:         for (p = 0; p < numPoints; p++) {
4956:           const PetscInt    point = points[2*p];
4957:           const PetscInt    *perm = perms ? perms[p] : NULL;
4958:           const PetscScalar *flip = flips ? flips[p] : NULL;
4959:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4960:         } break;
4961:       case ADD_BC_VALUES:
4962:         for (p = 0; p < numPoints; p++) {
4963:           const PetscInt    point = points[2*p];
4964:           const PetscInt    *perm = perms ? perms[p] : NULL;
4965:           const PetscScalar *flip = flips ? flips[p] : NULL;
4966:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4967:         } break;
4968:       default:
4969:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4970:       }
4971:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4972:     }
4973:   } else {
4974:     PetscInt dof, off;
4975:     const PetscInt    **perms = NULL;
4976:     const PetscScalar **flips = NULL;

4978:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4979:     switch (mode) {
4980:     case INSERT_VALUES:
4981:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4982:         const PetscInt    point = points[2*p];
4983:         const PetscInt    *perm = perms ? perms[p] : NULL;
4984:         const PetscScalar *flip = flips ? flips[p] : NULL;
4985:         PetscSectionGetDof(section, point, &dof);
4986:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4987:       } break;
4988:     case INSERT_ALL_VALUES:
4989:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4990:         const PetscInt    point = points[2*p];
4991:         const PetscInt    *perm = perms ? perms[p] : NULL;
4992:         const PetscScalar *flip = flips ? flips[p] : NULL;
4993:         PetscSectionGetDof(section, point, &dof);
4994:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4995:       } break;
4996:     case INSERT_BC_VALUES:
4997:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4998:         const PetscInt    point = points[2*p];
4999:         const PetscInt    *perm = perms ? perms[p] : NULL;
5000:         const PetscScalar *flip = flips ? flips[p] : NULL;
5001:         PetscSectionGetDof(section, point, &dof);
5002:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
5003:       } break;
5004:     case ADD_VALUES:
5005:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5006:         const PetscInt    point = points[2*p];
5007:         const PetscInt    *perm = perms ? perms[p] : NULL;
5008:         const PetscScalar *flip = flips ? flips[p] : NULL;
5009:         PetscSectionGetDof(section, point, &dof);
5010:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
5011:       } break;
5012:     case ADD_ALL_VALUES:
5013:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5014:         const PetscInt    point = points[2*p];
5015:         const PetscInt    *perm = perms ? perms[p] : NULL;
5016:         const PetscScalar *flip = flips ? flips[p] : NULL;
5017:         PetscSectionGetDof(section, point, &dof);
5018:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
5019:       } break;
5020:     case ADD_BC_VALUES:
5021:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5022:         const PetscInt    point = points[2*p];
5023:         const PetscInt    *perm = perms ? perms[p] : NULL;
5024:         const PetscScalar *flip = flips ? flips[p] : NULL;
5025:         PetscSectionGetDof(section, point, &dof);
5026:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
5027:       } break;
5028:     default:
5029:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5030:     }
5031:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
5032:   }
5033:   /* Cleanup points */
5034:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5035:   /* Cleanup array */
5036:   VecRestoreArray(v, &array);
5037:   return(0);
5038: }

5040: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
5041: {
5042:   PetscSection      clSection;
5043:   IS                clPoints;
5044:   PetscScalar       *array;
5045:   PetscInt          *points = NULL;
5046:   const PetscInt    *clp, *clperm;
5047:   PetscInt          numFields, numPoints, p;
5048:   PetscInt          offset = 0, f;
5049:   PetscErrorCode    ierr;

5053:   if (!section) {DMGetLocalSection(dm, &section);}
5056:   PetscSectionGetNumFields(section, &numFields);
5057:   /* Get points */
5058:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5059:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5060:   /* Get array */
5061:   VecGetArray(v, &array);
5062:   /* Get values */
5063:   for (f = 0; f < numFields; ++f) {
5064:     const PetscInt    **perms = NULL;
5065:     const PetscScalar **flips = NULL;

5067:     if (!fieldActive[f]) {
5068:       for (p = 0; p < numPoints*2; p += 2) {
5069:         PetscInt fdof;
5070:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
5071:         offset += fdof;
5072:       }
5073:       continue;
5074:     }
5075:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5076:     switch (mode) {
5077:     case INSERT_VALUES:
5078:       for (p = 0; p < numPoints; p++) {
5079:         const PetscInt    point = points[2*p];
5080:         const PetscInt    *perm = perms ? perms[p] : NULL;
5081:         const PetscScalar *flip = flips ? flips[p] : NULL;
5082:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5083:       } break;
5084:     case INSERT_ALL_VALUES:
5085:       for (p = 0; p < numPoints; p++) {
5086:         const PetscInt    point = points[2*p];
5087:         const PetscInt    *perm = perms ? perms[p] : NULL;
5088:         const PetscScalar *flip = flips ? flips[p] : NULL;
5089:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5090:         } break;
5091:     case INSERT_BC_VALUES:
5092:       for (p = 0; p < numPoints; p++) {
5093:         const PetscInt    point = points[2*p];
5094:         const PetscInt    *perm = perms ? perms[p] : NULL;
5095:         const PetscScalar *flip = flips ? flips[p] : NULL;
5096:         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
5097:       } break;
5098:     case ADD_VALUES:
5099:       for (p = 0; p < numPoints; p++) {
5100:         const PetscInt    point = points[2*p];
5101:         const PetscInt    *perm = perms ? perms[p] : NULL;
5102:         const PetscScalar *flip = flips ? flips[p] : NULL;
5103:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5104:       } break;
5105:     case ADD_ALL_VALUES:
5106:       for (p = 0; p < numPoints; p++) {
5107:         const PetscInt    point = points[2*p];
5108:         const PetscInt    *perm = perms ? perms[p] : NULL;
5109:         const PetscScalar *flip = flips ? flips[p] : NULL;
5110:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5111:       } break;
5112:     default:
5113:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5114:     }
5115:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5116:   }
5117:   /* Cleanup points */
5118:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5119:   /* Cleanup array */
5120:   VecRestoreArray(v, &array);
5121:   return(0);
5122: }

5124: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
5125: {
5126:   PetscMPIInt    rank;
5127:   PetscInt       i, j;

5131:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
5132:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
5133:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
5134:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
5135:   numCIndices = numCIndices ? numCIndices : numRIndices;
5136:   for (i = 0; i < numRIndices; i++) {
5137:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
5138:     for (j = 0; j < numCIndices; j++) {
5139: #if defined(PETSC_USE_COMPLEX)
5140:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
5141: #else
5142:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
5143: #endif
5144:     }
5145:     PetscViewerASCIIPrintf(viewer, "\n");
5146:   }
5147:   return(0);
5148: }

5150: /*
5151:   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array

5153:   Input Parameters:
5154: + section - The section for this data layout
5155: . point   - The point contributing dofs with these indices
5156: . off     - The global offset of this point
5157: . loff    - The local offset of each field
5158: . setBC   - The flag determining whether to include indices of bounsary values
5159: . perm    - A permutation of the dofs on this point, or NULL
5160: - indperm - A permutation of the entire indices array, or NULL

5162:   Output Parameter:
5163: . indices - Indices for dofs on this point

5165:   Level: developer

5167:   Note: The indices could be local or global, depending on the value of 'off'.
5168: */
5169: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
5170: {
5171:   PetscInt        dof;   /* The number of unknowns on this point */
5172:   PetscInt        cdof;  /* The number of constraints on this point */
5173:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5174:   PetscInt        cind = 0, k;
5175:   PetscErrorCode  ierr;

5178:   PetscSectionGetDof(section, point, &dof);
5179:   PetscSectionGetConstraintDof(section, point, &cdof);
5180:   if (!cdof || setBC) {
5181:     for (k = 0; k < dof; ++k) {
5182:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5183:       const PetscInt ind    = indperm ? indperm[preind] : preind;

5185:       indices[ind] = off + k;
5186:     }
5187:   } else {
5188:     PetscSectionGetConstraintIndices(section, point, &cdofs);
5189:     for (k = 0; k < dof; ++k) {
5190:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5191:       const PetscInt ind    = indperm ? indperm[preind] : preind;

5193:       if ((cind < cdof) && (k == cdofs[cind])) {
5194:         /* Insert check for returning constrained indices */
5195:         indices[ind] = -(off+k+1);
5196:         ++cind;
5197:       } else {
5198:         indices[ind] = off+k-cind;
5199:       }
5200:     }
5201:   }
5202:   *loff += dof;
5203:   return(0);
5204: }

5206: /*
5207:   This version only believes the point offset from the globalSection

5209:  . off - The global offset of this point
5210: */
5211: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5212: {
5213:   PetscInt       numFields, foff, f;

5217:   PetscSectionGetNumFields(section, &numFields);
5218:   for (f = 0, foff = 0; f < numFields; ++f) {
5219:     PetscInt        fdof, cfdof;
5220:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5221:     PetscInt        cind = 0, b;
5222:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5224:     PetscSectionGetFieldDof(section, point, f, &fdof);
5225:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5226:     if (!cfdof || setBC) {
5227:       for (b = 0; b < fdof; ++b) {
5228:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5229:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5231:         indices[ind] = off+foff+b;
5232:       }
5233:     } else {
5234:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5235:       for (b = 0; b < fdof; ++b) {
5236:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5237:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5239:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5240:           indices[ind] = -(off+foff+b+1);
5241:           ++cind;
5242:         } else {
5243:           indices[ind] = off+foff+b-cind;
5244:         }
5245:       }
5246:     }
5247:     foff     += (setBC ? fdof : (fdof - cfdof));
5248:     foffs[f] += fdof;
5249:   }
5250:   return(0);
5251: }

5253: /*
5254:   This version believes the globalSection offsets for each field, rather than just the point offset

5256:  . foffs - The offset into 'indices' for each field, since it is segregated by field
5257: */
5258: PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5259: {
5260:   PetscInt       numFields, foff, f;

5264:   PetscSectionGetNumFields(section, &numFields);
5265:   for (f = 0; f < numFields; ++f) {
5266:     PetscInt        fdof, cfdof;
5267:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5268:     PetscInt        cind = 0, b;
5269:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5271:     PetscSectionGetFieldDof(section, point, f, &fdof);
5272:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5273:     PetscSectionGetFieldOffset(globalSection, point, f, &foff);
5274:     if (!cfdof || setBC) {
5275:       for (b = 0; b < fdof; ++b) {
5276:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5277:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5279:         indices[ind] = foff+b;
5280:       }
5281:     } else {
5282:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5283:       for (b = 0; b < fdof; ++b) {
5284:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5285:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5287:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5288:           indices[ind] = -(foff+b+1);
5289:           ++cind;
5290:         } else {
5291:           indices[ind] = foff+b-cind;
5292:         }
5293:       }
5294:     }
5295:     foffs[f] += fdof;
5296:   }
5297:   return(0);
5298: }

5300: 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)
5301: {
5302:   Mat             cMat;
5303:   PetscSection    aSec, cSec;
5304:   IS              aIS;
5305:   PetscInt        aStart = -1, aEnd = -1;
5306:   const PetscInt  *anchors;
5307:   PetscInt        numFields, f, p, q, newP = 0;
5308:   PetscInt        newNumPoints = 0, newNumIndices = 0;
5309:   PetscInt        *newPoints, *indices, *newIndices;
5310:   PetscInt        maxAnchor, maxDof;
5311:   PetscInt        newOffsets[32];
5312:   PetscInt        *pointMatOffsets[32];
5313:   PetscInt        *newPointOffsets[32];
5314:   PetscScalar     *pointMat[32];
5315:   PetscScalar     *newValues=NULL,*tmpValues;
5316:   PetscBool       anyConstrained = PETSC_FALSE;
5317:   PetscErrorCode  ierr;

5322:   PetscSectionGetNumFields(section, &numFields);

5324:   DMPlexGetAnchors(dm,&aSec,&aIS);
5325:   /* if there are point-to-point constraints */
5326:   if (aSec) {
5327:     PetscArrayzero(newOffsets, 32);
5328:     ISGetIndices(aIS,&anchors);
5329:     PetscSectionGetChart(aSec,&aStart,&aEnd);
5330:     /* figure out how many points are going to be in the new element matrix
5331:      * (we allow double counting, because it's all just going to be summed
5332:      * into the global matrix anyway) */
5333:     for (p = 0; p < 2*numPoints; p+=2) {
5334:       PetscInt b    = points[p];
5335:       PetscInt bDof = 0, bSecDof;

5337:       PetscSectionGetDof(section,b,&bSecDof);
5338:       if (!bSecDof) {
5339:         continue;
5340:       }
5341:       if (b >= aStart && b < aEnd) {
5342:         PetscSectionGetDof(aSec,b,&bDof);
5343:       }
5344:       if (bDof) {
5345:         /* this point is constrained */
5346:         /* it is going to be replaced by its anchors */
5347:         PetscInt bOff, q;

5349:         anyConstrained = PETSC_TRUE;
5350:         newNumPoints  += bDof;
5351:         PetscSectionGetOffset(aSec,b,&bOff);
5352:         for (q = 0; q < bDof; q++) {
5353:           PetscInt a = anchors[bOff + q];
5354:           PetscInt aDof;

5356:           PetscSectionGetDof(section,a,&aDof);
5357:           newNumIndices += aDof;
5358:           for (f = 0; f < numFields; ++f) {
5359:             PetscInt fDof;

5361:             PetscSectionGetFieldDof(section, a, f, &fDof);
5362:             newOffsets[f+1] += fDof;
5363:           }
5364:         }
5365:       }
5366:       else {
5367:         /* this point is not constrained */
5368:         newNumPoints++;
5369:         newNumIndices += bSecDof;
5370:         for (f = 0; f < numFields; ++f) {
5371:           PetscInt fDof;

5373:           PetscSectionGetFieldDof(section, b, f, &fDof);
5374:           newOffsets[f+1] += fDof;
5375:         }
5376:       }
5377:     }
5378:   }
5379:   if (!anyConstrained) {
5380:     if (outNumPoints)  *outNumPoints  = 0;
5381:     if (outNumIndices) *outNumIndices = 0;
5382:     if (outPoints)     *outPoints     = NULL;
5383:     if (outValues)     *outValues     = NULL;
5384:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5385:     return(0);
5386:   }

5388:   if (outNumPoints)  *outNumPoints  = newNumPoints;
5389:   if (outNumIndices) *outNumIndices = newNumIndices;

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

5393:   if (!outPoints && !outValues) {
5394:     if (offsets) {
5395:       for (f = 0; f <= numFields; f++) {
5396:         offsets[f] = newOffsets[f];
5397:       }
5398:     }
5399:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5400:     return(0);
5401:   }

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

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

5407:   /* workspaces */
5408:   if (numFields) {
5409:     for (f = 0; f < numFields; f++) {
5410:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5411:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5412:     }
5413:   }
5414:   else {
5415:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5416:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5417:   }

5419:   /* get workspaces for the point-to-point matrices */
5420:   if (numFields) {
5421:     PetscInt totalOffset, totalMatOffset;

5423:     for (p = 0; p < numPoints; p++) {
5424:       PetscInt b    = points[2*p];
5425:       PetscInt bDof = 0, bSecDof;

5427:       PetscSectionGetDof(section,b,&bSecDof);
5428:       if (!bSecDof) {
5429:         for (f = 0; f < numFields; f++) {
5430:           newPointOffsets[f][p + 1] = 0;
5431:           pointMatOffsets[f][p + 1] = 0;
5432:         }
5433:         continue;
5434:       }
5435:       if (b >= aStart && b < aEnd) {
5436:         PetscSectionGetDof(aSec, b, &bDof);
5437:       }
5438:       if (bDof) {
5439:         for (f = 0; f < numFields; f++) {
5440:           PetscInt fDof, q, bOff, allFDof = 0;

5442:           PetscSectionGetFieldDof(section, b, f, &fDof);
5443:           PetscSectionGetOffset(aSec, b, &bOff);
5444:           for (q = 0; q < bDof; q++) {
5445:             PetscInt a = anchors[bOff + q];
5446:             PetscInt aFDof;

5448:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5449:             allFDof += aFDof;
5450:           }
5451:           newPointOffsets[f][p+1] = allFDof;
5452:           pointMatOffsets[f][p+1] = fDof * allFDof;
5453:         }
5454:       }
5455:       else {
5456:         for (f = 0; f < numFields; f++) {
5457:           PetscInt fDof;

5459:           PetscSectionGetFieldDof(section, b, f, &fDof);
5460:           newPointOffsets[f][p+1] = fDof;
5461:           pointMatOffsets[f][p+1] = 0;
5462:         }
5463:       }
5464:     }
5465:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5466:       newPointOffsets[f][0] = totalOffset;
5467:       pointMatOffsets[f][0] = totalMatOffset;
5468:       for (p = 0; p < numPoints; p++) {
5469:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5470:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5471:       }
5472:       totalOffset    = newPointOffsets[f][numPoints];
5473:       totalMatOffset = pointMatOffsets[f][numPoints];
5474:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5475:     }
5476:   }
5477:   else {
5478:     for (p = 0; p < numPoints; p++) {
5479:       PetscInt b    = points[2*p];
5480:       PetscInt bDof = 0, bSecDof;

5482:       PetscSectionGetDof(section,b,&bSecDof);
5483:       if (!bSecDof) {
5484:         newPointOffsets[0][p + 1] = 0;
5485:         pointMatOffsets[0][p + 1] = 0;
5486:         continue;
5487:       }
5488:       if (b >= aStart && b < aEnd) {
5489:         PetscSectionGetDof(aSec, b, &bDof);
5490:       }
5491:       if (bDof) {
5492:         PetscInt bOff, q, allDof = 0;

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

5498:           PetscSectionGetDof(section, a, &aDof);
5499:           allDof += aDof;
5500:         }
5501:         newPointOffsets[0][p+1] = allDof;
5502:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5503:       }
5504:       else {
5505:         newPointOffsets[0][p+1] = bSecDof;
5506:         pointMatOffsets[0][p+1] = 0;
5507:       }
5508:     }
5509:     newPointOffsets[0][0] = 0;
5510:     pointMatOffsets[0][0] = 0;
5511:     for (p = 0; p < numPoints; p++) {
5512:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5513:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5514:     }
5515:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5516:   }

5518:   /* output arrays */
5519:   DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);

5521:   /* get the point-to-point matrices; construct newPoints */
5522:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5523:   PetscSectionGetMaxDof(section, &maxDof);
5524:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5525:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5526:   if (numFields) {
5527:     for (p = 0, newP = 0; p < numPoints; p++) {
5528:       PetscInt b    = points[2*p];
5529:       PetscInt o    = points[2*p+1];
5530:       PetscInt bDof = 0, bSecDof;

5532:       PetscSectionGetDof(section, b, &bSecDof);
5533:       if (!bSecDof) {
5534:         continue;
5535:       }
5536:       if (b >= aStart && b < aEnd) {
5537:         PetscSectionGetDof(aSec, b, &bDof);
5538:       }
5539:       if (bDof) {
5540:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5542:         fStart[0] = 0;
5543:         fEnd[0]   = 0;
5544:         for (f = 0; f < numFields; f++) {
5545:           PetscInt fDof;

5547:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5548:           fStart[f+1] = fStart[f] + fDof;
5549:           fEnd[f+1]   = fStart[f+1];
5550:         }
5551:         PetscSectionGetOffset(cSec, b, &bOff);
5552:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);

5554:         fAnchorStart[0] = 0;
5555:         fAnchorEnd[0]   = 0;
5556:         for (f = 0; f < numFields; f++) {
5557:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5559:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5560:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5561:         }
5562:         PetscSectionGetOffset(aSec, b, &bOff);
5563:         for (q = 0; q < bDof; q++) {
5564:           PetscInt a = anchors[bOff + q], aOff;

5566:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5567:           newPoints[2*(newP + q)]     = a;
5568:           newPoints[2*(newP + q) + 1] = 0;
5569:           PetscSectionGetOffset(section, a, &aOff);
5570:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);
5571:         }
5572:         newP += bDof;

5574:         if (outValues) {
5575:           /* get the point-to-point submatrix */
5576:           for (f = 0; f < numFields; f++) {
5577:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5578:           }
5579:         }
5580:       }
5581:       else {
5582:         newPoints[2 * newP]     = b;
5583:         newPoints[2 * newP + 1] = o;
5584:         newP++;
5585:       }
5586:     }
5587:   } else {
5588:     for (p = 0; p < numPoints; p++) {
5589:       PetscInt b    = points[2*p];
5590:       PetscInt o    = points[2*p+1];
5591:       PetscInt bDof = 0, bSecDof;

5593:       PetscSectionGetDof(section, b, &bSecDof);
5594:       if (!bSecDof) {
5595:         continue;
5596:       }
5597:       if (b >= aStart && b < aEnd) {
5598:         PetscSectionGetDof(aSec, b, &bDof);
5599:       }
5600:       if (bDof) {
5601:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5612:           newPoints[2*(newP + q)]     = a;
5613:           newPoints[2*(newP + q) + 1] = 0;
5614:           PetscSectionGetOffset(section, a, &aOff);
5615:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);
5616:         }
5617:         newP += bDof;

5619:         /* get the point-to-point submatrix */
5620:         if (outValues) {
5621:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5622:         }
5623:       }
5624:       else {
5625:         newPoints[2 * newP]     = b;
5626:         newPoints[2 * newP + 1] = o;
5627:         newP++;
5628:       }
5629:     }
5630:   }

5632:   if (outValues) {
5633:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5634:     PetscArrayzero(tmpValues,newNumIndices*numIndices);
5635:     /* multiply constraints on the right */
5636:     if (numFields) {
5637:       for (f = 0; f < numFields; f++) {
5638:         PetscInt oldOff = offsets[f];

5640:         for (p = 0; p < numPoints; p++) {
5641:           PetscInt cStart = newPointOffsets[f][p];
5642:           PetscInt b      = points[2 * p];
5643:           PetscInt c, r, k;
5644:           PetscInt dof;

5646:           PetscSectionGetFieldDof(section,b,f,&dof);
5647:           if (!dof) {
5648:             continue;
5649:           }
5650:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5651:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5652:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5654:             for (r = 0; r < numIndices; r++) {
5655:               for (c = 0; c < nCols; c++) {
5656:                 for (k = 0; k < dof; k++) {
5657:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5658:                 }
5659:               }
5660:             }
5661:           }
5662:           else {
5663:             /* copy this column as is */
5664:             for (r = 0; r < numIndices; r++) {
5665:               for (c = 0; c < dof; c++) {
5666:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5667:               }
5668:             }
5669:           }
5670:           oldOff += dof;
5671:         }
5672:       }
5673:     }
5674:     else {
5675:       PetscInt oldOff = 0;
5676:       for (p = 0; p < numPoints; p++) {
5677:         PetscInt cStart = newPointOffsets[0][p];
5678:         PetscInt b      = points[2 * p];
5679:         PetscInt c, r, k;
5680:         PetscInt dof;

5682:         PetscSectionGetDof(section,b,&dof);
5683:         if (!dof) {
5684:           continue;
5685:         }
5686:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5687:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5688:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5690:           for (r = 0; r < numIndices; r++) {
5691:             for (c = 0; c < nCols; c++) {
5692:               for (k = 0; k < dof; k++) {
5693:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5694:               }
5695:             }
5696:           }
5697:         }
5698:         else {
5699:           /* copy this column as is */
5700:           for (r = 0; r < numIndices; r++) {
5701:             for (c = 0; c < dof; c++) {
5702:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5703:             }
5704:           }
5705:         }
5706:         oldOff += dof;
5707:       }
5708:     }

5710:     if (multiplyLeft) {
5711:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5712:       PetscArrayzero(newValues,newNumIndices*newNumIndices);
5713:       /* multiply constraints transpose on the left */
5714:       if (numFields) {
5715:         for (f = 0; f < numFields; f++) {
5716:           PetscInt oldOff = offsets[f];

5718:           for (p = 0; p < numPoints; p++) {
5719:             PetscInt rStart = newPointOffsets[f][p];
5720:             PetscInt b      = points[2 * p];
5721:             PetscInt c, r, k;
5722:             PetscInt dof;

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

5729:               for (r = 0; r < nRows; r++) {
5730:                 for (c = 0; c < newNumIndices; c++) {
5731:                   for (k = 0; k < dof; k++) {
5732:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5733:                   }
5734:                 }
5735:               }
5736:             }
5737:             else {
5738:               /* copy this row as is */
5739:               for (r = 0; r < dof; r++) {
5740:                 for (c = 0; c < newNumIndices; c++) {
5741:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5742:                 }
5743:               }
5744:             }
5745:             oldOff += dof;
5746:           }
5747:         }
5748:       }
5749:       else {
5750:         PetscInt oldOff = 0;

5752:         for (p = 0; p < numPoints; p++) {
5753:           PetscInt rStart = newPointOffsets[0][p];
5754:           PetscInt b      = points[2 * p];
5755:           PetscInt c, r, k;
5756:           PetscInt dof;

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

5763:             for (r = 0; r < nRows; r++) {
5764:               for (c = 0; c < newNumIndices; c++) {
5765:                 for (k = 0; k < dof; k++) {
5766:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5767:                 }
5768:               }
5769:             }
5770:           }
5771:           else {
5772:             /* copy this row as is */
5773:             for (r = 0; r < dof; r++) {
5774:               for (c = 0; c < newNumIndices; c++) {
5775:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5776:               }
5777:             }
5778:           }
5779:           oldOff += dof;
5780:         }
5781:       }

5783:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5784:     }
5785:     else {
5786:       newValues = tmpValues;
5787:     }
5788:   }

5790:   /* clean up */
5791:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5792:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5794:   if (numFields) {
5795:     for (f = 0; f < numFields; f++) {
5796:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5797:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5798:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5799:     }
5800:   }
5801:   else {
5802:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5803:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5804:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5805:   }
5806:   ISRestoreIndices(aIS,&anchors);

5808:   /* output */
5809:   if (outPoints) {
5810:     *outPoints = newPoints;
5811:   }
5812:   else {
5813:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5814:   }
5815:   if (outValues) {
5816:     *outValues = newValues;
5817:   }
5818:   for (f = 0; f <= numFields; f++) {
5819:     offsets[f] = newOffsets[f];
5820:   }
5821:   return(0);
5822: }

5824: /*@C
5825:   DMPlexGetClosureIndices - Get the global indices for all local points in the closure of the given point

5827:   Not collective

5829:   Input Parameters:
5830: + dm - The DM
5831: . section - The section describing the local layout
5832: . globalSection - The section describing the parallel layout
5833: - point - The mesh point

5835:   Output parameters:
5836: + numIndices - The number of indices
5837: . indices - The indices
5838: - outOffsets - Field offset if not NULL

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

5842:   Level: advanced

5844: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5845: @*/
5846: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5847: {
5848:   PetscSection    clSection;
5849:   IS              clPoints;
5850:   const PetscInt *clp, *clperm;
5851:   const PetscInt  **perms[32] = {NULL};
5852:   PetscInt       *points = NULL, *pointsNew;
5853:   PetscInt        numPoints, numPointsNew;
5854:   PetscInt        offsets[32];
5855:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5856:   PetscErrorCode  ierr;

5864:   PetscSectionGetNumFields(section, &Nf);
5865:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5866:   PetscArrayzero(offsets, 32);
5867:   /* Get points in closure */
5868:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5869:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5870:   /* Get number of indices and indices per field */
5871:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5872:     PetscInt dof, fdof;

5874:     PetscSectionGetDof(section, points[p], &dof);
5875:     for (f = 0; f < Nf; ++f) {
5876:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5877:       offsets[f+1] += fdof;
5878:     }
5879:     Nind += dof;
5880:   }
5881:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5882:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5883:   if (!Nf) offsets[1] = Nind;
5884:   /* Get dual space symmetries */
5885:   for (f = 0; f < PetscMax(1,Nf); f++) {
5886:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5887:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5888:   }
5889:   /* Correct for hanging node constraints */
5890:   {
5891:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5892:     if (numPointsNew) {
5893:       for (f = 0; f < PetscMax(1,Nf); f++) {
5894:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5895:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5896:       }
5897:       for (f = 0; f < PetscMax(1,Nf); f++) {
5898:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5899:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5900:       }
5901:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5902:       numPoints = numPointsNew;
5903:       Nind      = NindNew;
5904:       points    = pointsNew;
5905:     }
5906:   }
5907:   /* Calculate indices */
5908:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5909:   if (Nf) {
5910:     if (outOffsets) {
5911:       PetscInt f;

5913:       for (f = 0; f <= Nf; f++) {
5914:         outOffsets[f] = offsets[f];
5915:       }
5916:     }
5917:     for (p = 0; p < numPoints; p++) {
5918:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5919:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);
5920:     }
5921:   } else {
5922:     for (p = 0, off = 0; p < numPoints; p++) {
5923:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5925:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5926:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);
5927:     }
5928:   }
5929:   /* Cleanup points */
5930:   for (f = 0; f < PetscMax(1,Nf); f++) {
5931:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5932:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5933:   }
5934:   if (numPointsNew) {
5935:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5936:   } else {
5937:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5938:   }
5939:   if (numIndices) *numIndices = Nind;
5940:   return(0);
5941: }

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

5946:   Not collective

5948:   Input Parameters:
5949: + dm - The DM
5950: . section - The section describing the layout in v, or NULL to use the default section
5951: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5952: . point - The mesh point
5953: . numIndices - The number of indices
5954: . indices - The indices
5955: - outOffsets - Field offset if not NULL

5957:   Level: advanced

5959: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5960: @*/
5961: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5962: {

5968:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5969:   return(0);
5970: }

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

5975:   Not collective

5977:   Input Parameters:
5978: + dm - The DM
5979: . section - The section describing the layout in v, or NULL to use the default section
5980: . globalSection - The section describing the layout in v, or NULL to use the default global section
5981: . A - The matrix
5982: . point - The point in the DM
5983: . values - The array of values
5984: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5989:   Level: intermediate

5991: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5992: @*/
5993: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5994: {
5995:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5996:   PetscSection        clSection;
5997:   IS                  clPoints;
5998:   PetscInt           *points = NULL, *newPoints;
5999:   const PetscInt     *clp, *clperm;
6000:   PetscInt           *indices;
6001:   PetscInt            offsets[32];
6002:   const PetscInt    **perms[32] = {NULL};
6003:   const PetscScalar **flips[32] = {NULL};
6004:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
6005:   PetscScalar        *valCopy = NULL;
6006:   PetscScalar        *newValues;
6007:   PetscErrorCode      ierr;

6011:   if (!section) {DMGetLocalSection(dm, &section);}
6013:   if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
6016:   PetscSectionGetNumFields(section, &numFields);
6017:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6018:   PetscArrayzero(offsets, 32);
6019:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
6020:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6021:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
6022:     PetscInt fdof;

6024:     PetscSectionGetDof(section, points[p], &dof);
6025:     for (f = 0; f < numFields; ++f) {
6026:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
6027:       offsets[f+1] += fdof;
6028:     }
6029:     numIndices += dof;
6030:   }
6031:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

6045:         if (!numFields) {
6046:           PetscSectionGetDof(section,point,&fdof);
6047:         } else {
6048:           PetscSectionGetFieldDof(section,point,f,&fdof);
6049:         }
6050:         if (flip) {
6051:           PetscInt i, j, k;

6053:           if (!valCopy) {
6054:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6055:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
6056:             values = valCopy;
6057:           }
6058:           for (i = 0; i < fdof; i++) {
6059:             PetscScalar fval = flip[i];

6061:             for (k = 0; k < numIndices; k++) {
6062:               valCopy[numIndices * (foffset + i) + k] *= fval;
6063:               valCopy[numIndices * k + (foffset + i)] *= fval;
6064:             }
6065:           }
6066:         }
6067:         foffset += fdof;
6068:       }
6069:     }
6070:   }
6071:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
6072:   if (newNumPoints) {
6073:     if (valCopy) {
6074:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6075:     }
6076:     for (f = 0; f < PetscMax(1,numFields); f++) {
6077:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6078:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6079:     }
6080:     for (f = 0; f < PetscMax(1,numFields); f++) {
6081:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
6082:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
6083:     }
6084:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6085:     numPoints  = newNumPoints;
6086:     numIndices = newNumIndices;
6087:     points     = newPoints;
6088:     values     = newValues;
6089:   }
6090:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
6091:   if (numFields) {
6092:     PetscBool useFieldOffsets;

6094:     PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
6095:     if (useFieldOffsets) {
6096:       for (p = 0; p < numPoints; p++) {
6097:         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices);
6098:       }
6099:     } else {
6100:       for (p = 0; p < numPoints; p++) {
6101:         PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6102:         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);
6103:       }
6104:     }
6105:   } else {
6106:     for (p = 0, off = 0; p < numPoints; p++) {
6107:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
6108:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6109:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);
6110:     }
6111:   }
6112:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
6113:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6114:   if (mesh->printFEM > 1) {
6115:     PetscInt i;
6116:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
6117:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
6118:     PetscPrintf(PETSC_COMM_SELF, "\n");
6119:   }
6120:   if (ierr) {
6121:     PetscMPIInt    rank;
6122:     PetscErrorCode ierr2;

6124:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6125:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6126:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
6127:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
6128: 
6129:   }
6130:   for (f = 0; f < PetscMax(1,numFields); f++) {
6131:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6132:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6133:   }
6134:   if (newNumPoints) {
6135:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
6136:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
6137:   }
6138:   else {
6139:     if (valCopy) {
6140:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6141:     }
6142:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6143:   }
6144:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
6145:   return(0);
6146: }

6148: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6149: {
6150:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
6151:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
6152:   PetscInt       *cpoints = NULL;
6153:   PetscInt       *findices, *cindices;
6154:   const PetscInt *fclperm, *cclperm;
6155:   PetscInt        foffsets[32], coffsets[32];
6156:   CellRefiner     cellRefiner;
6157:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6158:   PetscErrorCode  ierr;

6163:   if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6165:   if (!csection) {DMGetLocalSection(dmc, &csection);}
6167:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6169:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6172:   PetscSectionGetNumFields(fsection, &numFields);
6173:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6174:   PetscArrayzero(foffsets, 32);
6175:   PetscArrayzero(coffsets, 32);
6176:   PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6177:   PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6178:   /* Column indices */
6179:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6180:   maxFPoints = numCPoints;
6181:   /* Compress out points not in the section */
6182:   /*   TODO: Squeeze out points with 0 dof as well */
6183:   PetscSectionGetChart(csection, &pStart, &pEnd);
6184:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6185:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6186:       cpoints[q*2]   = cpoints[p];
6187:       cpoints[q*2+1] = cpoints[p+1];
6188:       ++q;
6189:     }
6190:   }
6191:   numCPoints = q;
6192:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6193:     PetscInt fdof;

6195:     PetscSectionGetDof(csection, cpoints[p], &dof);
6196:     if (!dof) continue;
6197:     for (f = 0; f < numFields; ++f) {
6198:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6199:       coffsets[f+1] += fdof;
6200:     }
6201:     numCIndices += dof;
6202:   }
6203:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6204:   /* Row indices */
6205:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6206:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6207:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6208:   for (r = 0, q = 0; r < numSubcells; ++r) {
6209:     /* TODO Map from coarse to fine cells */
6210:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6211:     /* Compress out points not in the section */
6212:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6213:     for (p = 0; p < numFPoints*2; p += 2) {
6214:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6215:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6216:         if (!dof) continue;
6217:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6218:         if (s < q) continue;
6219:         ftotpoints[q*2]   = fpoints[p];
6220:         ftotpoints[q*2+1] = fpoints[p+1];
6221:         ++q;
6222:       }
6223:     }
6224:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6225:   }
6226:   numFPoints = q;
6227:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6228:     PetscInt fdof;

6230:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6231:     if (!dof) continue;
6232:     for (f = 0; f < numFields; ++f) {
6233:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6234:       foffsets[f+1] += fdof;
6235:     }
6236:     numFIndices += dof;
6237:   }
6238:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

6240:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6241:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6242:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6243:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6244:   if (numFields) {
6245:     const PetscInt **permsF[32] = {NULL};
6246:     const PetscInt **permsC[32] = {NULL};

6248:     for (f = 0; f < numFields; f++) {
6249:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6250:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6251:     }
6252:     for (p = 0; p < numFPoints; p++) {
6253:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6254:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6255:     }
6256:     for (p = 0; p < numCPoints; p++) {
6257:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6258:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6259:     }
6260:     for (f = 0; f < numFields; f++) {
6261:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6262:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6263:     }
6264:   } else {
6265:     const PetscInt **permsF = NULL;
6266:     const PetscInt **permsC = NULL;

6268:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6269:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6270:     for (p = 0, off = 0; p < numFPoints; p++) {
6271:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6273:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6274:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6275:     }
6276:     for (p = 0, off = 0; p < numCPoints; p++) {
6277:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6279:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6280:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6281:     }
6282:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6283:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6284:   }
6285:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
6286:   /* TODO: flips */
6287:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6288:   if (ierr) {
6289:     PetscMPIInt    rank;
6290:     PetscErrorCode ierr2;

6292:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6293:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6294:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6295:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6296:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6297: 
6298:   }
6299:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6300:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6301:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6302:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6303:   return(0);
6304: }

6306: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6307: {
6308:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6309:   PetscInt      *cpoints = NULL;
6310:   PetscInt       foffsets[32], coffsets[32];
6311:   const PetscInt *fclperm, *cclperm;
6312:   CellRefiner    cellRefiner;
6313:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

6319:   if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6321:   if (!csection) {DMGetLocalSection(dmc, &csection);}
6323:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6325:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6327:   PetscSectionGetNumFields(fsection, &numFields);
6328:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6329:   PetscArrayzero(foffsets, 32);
6330:   PetscArrayzero(coffsets, 32);
6331:   PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6332:   PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6333:   /* Column indices */
6334:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6335:   maxFPoints = numCPoints;
6336:   /* Compress out points not in the section */
6337:   /*   TODO: Squeeze out points with 0 dof as well */
6338:   PetscSectionGetChart(csection, &pStart, &pEnd);
6339:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6340:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6341:       cpoints[q*2]   = cpoints[p];
6342:       cpoints[q*2+1] = cpoints[p+1];
6343:       ++q;
6344:     }
6345:   }
6346:   numCPoints = q;
6347:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6348:     PetscInt fdof;

6350:     PetscSectionGetDof(csection, cpoints[p], &dof);
6351:     if (!dof) continue;
6352:     for (f = 0; f < numFields; ++f) {
6353:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6354:       coffsets[f+1] += fdof;
6355:     }
6356:     numCIndices += dof;
6357:   }
6358:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6359:   /* Row indices */
6360:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6361:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6362:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6363:   for (r = 0, q = 0; r < numSubcells; ++r) {
6364:     /* TODO Map from coarse to fine cells */
6365:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6366:     /* Compress out points not in the section */
6367:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6368:     for (p = 0; p < numFPoints*2; p += 2) {
6369:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6370:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6371:         if (!dof) continue;
6372:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6373:         if (s < q) continue;
6374:         ftotpoints[q*2]   = fpoints[p];
6375:         ftotpoints[q*2+1] = fpoints[p+1];
6376:         ++q;
6377:       }
6378:     }
6379:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6380:   }
6381:   numFPoints = q;
6382:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6383:     PetscInt fdof;

6385:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6386:     if (!dof) continue;
6387:     for (f = 0; f < numFields; ++f) {
6388:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6389:       foffsets[f+1] += fdof;
6390:     }
6391:     numFIndices += dof;
6392:   }
6393:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

6401:     for (f = 0; f < numFields; f++) {
6402:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6403:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6404:     }
6405:     for (p = 0; p < numFPoints; p++) {
6406:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6407:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6408:     }
6409:     for (p = 0; p < numCPoints; p++) {
6410:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6411:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6412:     }
6413:     for (f = 0; f < numFields; f++) {
6414:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6415:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6416:     }
6417:   } else {
6418:     const PetscInt **permsF = NULL;
6419:     const PetscInt **permsC = NULL;

6421:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6422:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6423:     for (p = 0, off = 0; p < numFPoints; p++) {
6424:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6426:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6427:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6428:     }
6429:     for (p = 0, off = 0; p < numCPoints; p++) {
6430:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6432:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6433:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6434:     }
6435:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6436:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6437:   }
6438:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6439:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6440:   return(0);
6441: }

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

6446:   Input Parameter:
6447: . dm - The DMPlex object

6449:   Output Parameters:
6450: + cMax - The first hybrid cell
6451: . fMax - The first hybrid face
6452: . eMax - The first hybrid edge
6453: - vMax - The first hybrid vertex

6455:   Level: developer

6457: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6458: @*/
6459: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6460: {
6461:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6462:   PetscInt       dim;

6467:   DMGetDimension(dm, &dim);
6468:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6469:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6470:   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6471:   if (eMax) *eMax = mesh->hybridPointMax[1];
6472:   if (vMax) *vMax = mesh->hybridPointMax[0];
6473:   return(0);
6474: }

6476: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6477: {
6478:   IS             is, his;
6479:   PetscInt       first = 0, stride;
6480:   PetscBool      isStride;

6484:   DMLabelGetStratumIS(depthLabel, d, &is);
6485:   PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6486:   if (isStride) {
6487:     ISStrideGetInfo(is, &first, &stride);
6488:   }
6489:   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6490:   ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6491:   DMLabelSetStratumIS(dimLabel, d, his);
6492:   ISDestroy(&his);
6493:   ISDestroy(&is);
6494:   return(0);
6495: }

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

6500:   Input Parameters:
6501: + dm   - The DMPlex object
6502: . cMax - The first hybrid cell
6503: . fMax - The first hybrid face
6504: . eMax - The first hybrid edge
6505: - vMax - The first hybrid vertex

6507:   Level: developer

6509: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6510: @*/
6511: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6512: {
6513:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6514:   PetscInt       dim;

6519:   DMGetDimension(dm, &dim);
6520:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6521:   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6522:   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6523:   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6524:   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6525:   return(0);
6526: }

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

6531:   Input Parameter:
6532: . dm   - The DMPlex object

6534:   Output Parameter:
6535: . cellHeight - The height of a cell

6537:   Level: developer

6539: .seealso DMPlexSetVTKCellHeight()
6540: @*/
6541: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6542: {
6543:   DM_Plex *mesh = (DM_Plex*) dm->data;

6548:   *cellHeight = mesh->vtkCellHeight;
6549:   return(0);
6550: }

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

6555:   Input Parameters:
6556: + dm   - The DMPlex object
6557: - cellHeight - The height of a cell

6559:   Level: developer

6561: .seealso DMPlexGetVTKCellHeight()
6562: @*/
6563: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6564: {
6565:   DM_Plex *mesh = (DM_Plex*) dm->data;

6569:   mesh->vtkCellHeight = cellHeight;
6570:   return(0);
6571: }

6573: /*@
6574:   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions

6576:   Input Parameter:
6577: . dm - The DMPlex object

6579:   Output Parameters:
6580: + gcStart - The first ghost cell, or NULL
6581: - gcEnd   - The upper bound on ghost cells, or NULL

6583:   Level: advanced

6585: .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds()
6586: @*/
6587: PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
6588: {
6589:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6590:   PetscInt       dim;

6595:   DMGetDimension(dm, &dim);
6596:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6598:   if (gcEnd)   {
6600:     if (mesh->ghostCellStart >= 0) {DMPlexGetHeightStratum(dm, 0, NULL, gcEnd);}
6601:     else                           {*gcEnd = -1;}
6602:   }
6603:   return(0);
6604: }

6606: /*@
6607:   DMPlexSetGhostCellStratum - Set the range of cells which are used to enforce FV boundary conditions

6609:   Input Parameters:
6610: + dm      - The DMPlex object
6611: . gcStart - The first ghost cell, or PETSC_DETERMINE
6612: - gcEnd   - The upper bound on ghost cells, or PETSC_DETERMINE

6614:   Level: advanced

6616:   Note: This is not usually called directly by a user.

6618: .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum(), DMPlexSetHybridBounds()
6619: @*/
6620: PetscErrorCode DMPlexSetGhostCellStratum(DM dm, PetscInt gcStart, PetscInt gcEnd)
6621: {
6622:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6623:   PetscInt       dim;

6628:   DMGetDimension(dm, &dim);
6629:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6630:   mesh->ghostCellStart = gcStart;
6631:   if (gcEnd >= 0) {
6632:     PetscInt cEnd;
6633:     DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);
6634:     if (gcEnd != cEnd) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Ghost cells must appear at the end of the cell range, but gcEnd %D is not equal to cEnd %D", gcEnd, cEnd);
6635:   }
6636:   return(0);
6637: }

6639: /*@
6640:   DMPlexGetInteriorCellStratum - Get the range of cells which are neither hybrid nor ghost FV cells

6642:   Input Parameter:
6643: . dm - The DMPlex object

6645:   Output Parameters:
6646: + cStartInterior - The first ghost cell
6647: - cEndInterior   - The upper bound on ghost cells

6649:   Level: developer

6651: .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds()
6652: @*/
6653: PetscErrorCode DMPlexGetInteriorCellStratum(DM dm, PetscInt *cStartInterior, PetscInt *cEndInterior)
6654: {
6655:   PetscInt       gcEnd, cMax;

6659:   DMPlexGetHeightStratum(dm, 0, cStartInterior, cEndInterior);
6660:   DMPlexGetGhostCellStratum(dm, &gcEnd, NULL);
6661:   *cEndInterior = gcEnd < 0 ? *cEndInterior : gcEnd;
6662:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6663:   *cEndInterior = cMax  < 0 ? *cEndInterior : cMax;
6664:   return(0);
6665: }

6667: /* We can easily have a form that takes an IS instead */
6668: PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6669: {
6670:   PetscSection   section, globalSection;
6671:   PetscInt      *numbers, p;

6675:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6676:   PetscSectionSetChart(section, pStart, pEnd);
6677:   for (p = pStart; p < pEnd; ++p) {
6678:     PetscSectionSetDof(section, p, 1);
6679:   }
6680:   PetscSectionSetUp(section);
6681:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6682:   PetscMalloc1(pEnd - pStart, &numbers);
6683:   for (p = pStart; p < pEnd; ++p) {
6684:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6685:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6686:     else                       numbers[p-pStart] += shift;
6687:   }
6688:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6689:   if (globalSize) {
6690:     PetscLayout layout;
6691:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6692:     PetscLayoutGetSize(layout, globalSize);
6693:     PetscLayoutDestroy(&layout);
6694:   }
6695:   PetscSectionDestroy(&section);
6696:   PetscSectionDestroy(&globalSection);
6697:   return(0);
6698: }

6700: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6701: {
6702:   PetscInt       cellHeight, cStart, cEnd, cMax;

6706:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6707:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6708:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6709:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6710:   DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6711:   return(0);
6712: }

6714: /*@
6715:   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process

6717:   Input Parameter:
6718: . dm   - The DMPlex object

6720:   Output Parameter:
6721: . globalCellNumbers - Global cell numbers for all cells on this process

6723:   Level: developer

6725: .seealso DMPlexGetVertexNumbering()
6726: @*/
6727: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6728: {
6729:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6734:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6735:   *globalCellNumbers = mesh->globalCellNumbers;
6736:   return(0);
6737: }

6739: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6740: {
6741:   PetscInt       vStart, vEnd, vMax;

6746:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6747:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6748:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6749:   DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6750:   return(0);
6751: }

6753: /*@
6754:   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process

6756:   Input Parameter:
6757: . dm   - The DMPlex object

6759:   Output Parameter:
6760: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6762:   Level: developer

6764: .seealso DMPlexGetCellNumbering()
6765: @*/
6766: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6767: {
6768:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6773:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6774:   *globalVertexNumbers = mesh->globalVertexNumbers;
6775:   return(0);
6776: }

6778: /*@
6779:   DMPlexCreatePointNumbering - Create a global numbering for all points on this process

6781:   Input Parameter:
6782: . dm   - The DMPlex object

6784:   Output Parameter:
6785: . globalPointNumbers - Global numbers for all points on this process

6787:   Level: developer

6789: .seealso DMPlexGetCellNumbering()
6790: @*/
6791: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6792: {
6793:   IS             nums[4];
6794:   PetscInt       depths[4], gdepths[4], starts[4];
6795:   PetscInt       depth, d, shift = 0;

6800:   DMPlexGetDepth(dm, &depth);
6801:   /* For unstratified meshes use dim instead of depth */
6802:   if (depth < 0) {DMGetDimension(dm, &depth);}
6803:   for (d = 0; d <= depth; ++d) {
6804:     PetscInt end;

6806:     depths[d] = depth-d;
6807:     DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6808:     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6809:   }
6810:   PetscSortIntWithArray(depth+1, starts, depths);
6811:   MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6812:   for (d = 0; d <= depth; ++d) {
6813:     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6814:   }
6815:   for (d = 0; d <= depth; ++d) {
6816:     PetscInt pStart, pEnd, gsize;

6818:     DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6819:     DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6820:     shift += gsize;
6821:   }
6822:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6823:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6824:   return(0);
6825: }


6828: /*@
6829:   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner

6831:   Input Parameter:
6832: . dm - The DMPlex object

6834:   Output Parameter:
6835: . ranks - The rank field

6837:   Options Database Keys:
6838: . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer

6840:   Level: intermediate

6842: .seealso: DMView()
6843: @*/
6844: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6845: {
6846:   DM             rdm;
6847:   PetscFE        fe;
6848:   PetscScalar   *r;
6849:   PetscMPIInt    rank;
6850:   PetscInt       dim, cStart, cEnd, c;

6856:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6857:   DMClone(dm, &rdm);
6858:   DMGetDimension(rdm, &dim);
6859:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6860:   PetscObjectSetName((PetscObject) fe, "rank");
6861:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6862:   PetscFEDestroy(&fe);
6863:   DMCreateDS(rdm);
6864:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6865:   DMCreateGlobalVector(rdm, ranks);
6866:   PetscObjectSetName((PetscObject) *ranks, "partition");
6867:   VecGetArray(*ranks, &r);
6868:   for (c = cStart; c < cEnd; ++c) {
6869:     PetscScalar *lr;

6871:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6872:     *lr = rank;
6873:   }
6874:   VecRestoreArray(*ranks, &r);
6875:   DMDestroy(&rdm);
6876:   return(0);
6877: }

6879: /*@
6880:   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell

6882:   Input Parameters:
6883: + dm    - The DMPlex
6884: - label - The DMLabel

6886:   Output Parameter:
6887: . val - The label value field

6889:   Options Database Keys:
6890: . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer

6892:   Level: intermediate

6894: .seealso: DMView()
6895: @*/
6896: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6897: {
6898:   DM             rdm;
6899:   PetscFE        fe;
6900:   PetscScalar   *v;
6901:   PetscInt       dim, cStart, cEnd, c;

6908:   DMClone(dm, &rdm);
6909:   DMGetDimension(rdm, &dim);
6910:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6911:   PetscObjectSetName((PetscObject) fe, "label_value");
6912:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6913:   PetscFEDestroy(&fe);
6914:   DMCreateDS(rdm);
6915:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6916:   DMCreateGlobalVector(rdm, val);
6917:   PetscObjectSetName((PetscObject) *val, "label_value");
6918:   VecGetArray(*val, &v);
6919:   for (c = cStart; c < cEnd; ++c) {
6920:     PetscScalar *lv;
6921:     PetscInt     cval;

6923:     DMPlexPointGlobalRef(rdm, c, v, &lv);
6924:     DMLabelGetValue(label, c, &cval);
6925:     *lv = cval;
6926:   }
6927:   VecRestoreArray(*val, &v);
6928:   DMDestroy(&rdm);
6929:   return(0);
6930: }

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

6935:   Input Parameter:
6936: . dm - The DMPlex object

6938:   Notes:
6939:   This is a useful diagnostic when creating meshes programmatically.

6941:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

6943:   Level: developer

6945: .seealso: DMCreate(), DMSetFromOptions()
6946: @*/
6947: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6948: {
6949:   PetscSection    coneSection, supportSection;
6950:   const PetscInt *cone, *support;
6951:   PetscInt        coneSize, c, supportSize, s;
6952:   PetscInt        pStart, pEnd, p, pp, csize, ssize;
6953:   PetscBool       storagecheck = PETSC_TRUE;
6954:   PetscErrorCode  ierr;

6958:   DMPlexGetConeSection(dm, &coneSection);
6959:   DMPlexGetSupportSection(dm, &supportSection);
6960:   /* Check that point p is found in the support of its cone points, and vice versa */
6961:   DMPlexGetChart(dm, &pStart, &pEnd);
6962:   for (p = pStart; p < pEnd; ++p) {
6963:     DMPlexGetConeSize(dm, p, &coneSize);
6964:     DMPlexGetCone(dm, p, &cone);
6965:     for (c = 0; c < coneSize; ++c) {
6966:       PetscBool dup = PETSC_FALSE;
6967:       PetscInt  d;
6968:       for (d = c-1; d >= 0; --d) {
6969:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6970:       }
6971:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6972:       DMPlexGetSupport(dm, cone[c], &support);
6973:       for (s = 0; s < supportSize; ++s) {
6974:         if (support[s] == p) break;
6975:       }
6976:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6977:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6978:         for (s = 0; s < coneSize; ++s) {
6979:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6980:         }
6981:         PetscPrintf(PETSC_COMM_SELF, "\n");
6982:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6983:         for (s = 0; s < supportSize; ++s) {
6984:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6985:         }
6986:         PetscPrintf(PETSC_COMM_SELF, "\n");
6987:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6988:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6989:       }
6990:     }
6991:     DMPlexGetTreeParent(dm, p, &pp, NULL);
6992:     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6993:     DMPlexGetSupportSize(dm, p, &supportSize);
6994:     DMPlexGetSupport(dm, p, &support);
6995:     for (s = 0; s < supportSize; ++s) {
6996:       DMPlexGetConeSize(dm, support[s], &coneSize);
6997:       DMPlexGetCone(dm, support[s], &cone);
6998:       for (c = 0; c < coneSize; ++c) {
6999:         DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
7000:         if (cone[c] != pp) { c = 0; break; }
7001:         if (cone[c] == p) break;
7002:       }
7003:       if (c >= coneSize) {
7004:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
7005:         for (c = 0; c < supportSize; ++c) {
7006:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
7007:         }
7008:         PetscPrintf(PETSC_COMM_SELF, "\n");
7009:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
7010:         for (c = 0; c < coneSize; ++c) {
7011:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
7012:         }
7013:         PetscPrintf(PETSC_COMM_SELF, "\n");
7014:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
7015:       }
7016:     }
7017:   }
7018:   if (storagecheck) {
7019:     PetscSectionGetStorageSize(coneSection, &csize);
7020:     PetscSectionGetStorageSize(supportSection, &ssize);
7021:     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
7022:   }
7023:   return(0);
7024: }

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

7029:   Input Parameters:
7030: + dm - The DMPlex object
7031: - cellHeight - Normally 0

7033:   Notes:
7034:   This is a useful diagnostic when creating meshes programmatically.
7035:   Currently applicable only to homogeneous simplex or tensor meshes.

7037:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7039:   Level: developer

7041: .seealso: DMCreate(), DMSetFromOptions()
7042: @*/
7043: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
7044: {
7045:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
7046:   PetscBool      isSimplex = PETSC_FALSE;

7051:   DMGetDimension(dm, &dim);
7052:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
7053:   if (cStart < cEnd) {
7054:     DMPlexGetConeSize(dm, cStart, &c);
7055:     isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE;
7056:   }
7057:   switch (dim) {
7058:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
7059:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
7060:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
7061:   default:
7062:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
7063:   }
7064:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7065:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
7066:   cMax = cMax >= 0 ? cMax : cEnd;
7067:   for (c = cStart; c < cMax; ++c) {
7068:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

7070:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7071:     for (cl = 0; cl < closureSize*2; cl += 2) {
7072:       const PetscInt p = closure[cl];
7073:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
7074:     }
7075:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7076:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
7077:   }
7078:   for (c = cMax; c < cEnd; ++c) {
7079:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

7081:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7082:     for (cl = 0; cl < closureSize*2; cl += 2) {
7083:       const PetscInt p = closure[cl];
7084:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
7085:     }
7086:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7087:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
7088:   }
7089:   return(0);
7090: }

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

7095:   Not Collective

7097:   Input Parameters:
7098: + dm - The DMPlex object
7099: - cellHeight - Normally 0

7101:   Notes:
7102:   This is a useful diagnostic when creating meshes programmatically.
7103:   This routine is only relevant for meshes that are fully interpolated across all ranks.
7104:   It will error out if a partially interpolated mesh is given on some rank.
7105:   It will do nothing for locally uninterpolated mesh (as there is nothing to check).

7107:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7109:   Level: developer

7111: .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
7112: @*/
7113: PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
7114: {
7115:   PetscInt       pMax[4];
7116:   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
7118:   DMPlexInterpolatedFlag interpEnum;

7122:   DMPlexIsInterpolated(dm, &interpEnum);
7123:   if (interpEnum == DMPLEX_INTERPOLATED_NONE) return(0);
7124:   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
7125:     PetscMPIInt        rank;
7126:     MPI_Comm        comm;

7128:     PetscObjectGetComm((PetscObject) dm, &comm);
7129:     MPI_Comm_rank(comm, &rank);
7130:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
7131:   }

7133:   DMGetDimension(dm, &dim);
7134:   DMPlexGetDepth(dm, &depth);
7135:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7136:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
7137:   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
7138:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
7139:     for (c = cStart; c < cEnd; ++c) {
7140:       const PetscInt *cone, *ornt, *faces;
7141:       PetscInt        numFaces, faceSize, coneSize,f;
7142:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

7144:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
7145:       DMPlexGetConeSize(dm, c, &coneSize);
7146:       DMPlexGetCone(dm, c, &cone);
7147:       DMPlexGetConeOrientation(dm, c, &ornt);
7148:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7149:       for (cl = 0; cl < closureSize*2; cl += 2) {
7150:         const PetscInt p = closure[cl];
7151:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
7152:       }
7153:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
7154:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
7155:       for (f = 0; f < numFaces; ++f) {
7156:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

7158:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
7159:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
7160:           const PetscInt p = fclosure[cl];
7161:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
7162:         }
7163:         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);
7164:         for (v = 0; v < fnumCorners; ++v) {
7165:           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]);
7166:         }
7167:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
7168:       }
7169:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
7170:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7171:     }
7172:   }
7173:   return(0);
7174: }

7176: /*@
7177:   DMPlexCheckGeometry - Check the geometry of mesh cells

7179:   Input Parameter:
7180: . dm - The DMPlex object

7182:   Notes:
7183:   This is a useful diagnostic when creating meshes programmatically.

7185:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7187:   Level: developer

7189: .seealso: DMCreate(), DMSetFromOptions()
7190: @*/
7191: PetscErrorCode DMPlexCheckGeometry(DM dm)
7192: {
7193:   PetscReal      detJ, J[9], refVol = 1.0;
7194:   PetscReal      vol;
7195:   PetscInt       dim, depth, d, cStart, cEnd, c, cMax;

7199:   DMGetDimension(dm, &dim);
7200:   DMPlexGetDepth(dm, &depth);
7201:   for (d = 0; d < dim; ++d) refVol *= 2.0;
7202:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7203:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
7204:   cMax = cMax < 0 ? cEnd : cMax;
7205:   for (c = cStart; c < cMax; ++c) {
7206:     DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
7207:     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
7208:     PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
7209:     if (depth > 1) {
7210:       DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
7211:       if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
7212:       PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
7213:     }
7214:   }
7215:   return(0);
7216: }

7218: /*@
7219:   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.

7221:   Input Parameters:
7222: . dm - The DMPlex object

7224:   Notes:
7225:   This is mainly intended for debugging/testing purposes.
7226:   It currently checks only meshes with no partition overlapping.

7228:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7230:   Level: developer

7232: .seealso: DMGetPointSF(), DMSetFromOptions()
7233: @*/
7234: PetscErrorCode DMPlexCheckPointSF(DM dm)
7235: {
7236:   PetscSF         pointSF;
7237:   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
7238:   const PetscInt *locals, *rootdegree;
7239:   PetscBool       distributed;
7240:   PetscErrorCode  ierr;

7244:   DMGetPointSF(dm, &pointSF);
7245:   DMPlexIsDistributed(dm, &distributed);
7246:   if (!distributed) return(0);
7247:   DMPlexGetOverlap(dm, &overlap);
7248:   if (overlap) {
7249:     PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");
7250:     return(0);
7251:   }
7252:   if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
7253:   PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);
7254:   if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
7255:   PetscSFComputeDegreeBegin(pointSF, &rootdegree);
7256:   PetscSFComputeDegreeEnd(pointSF, &rootdegree);

7258:   /* 1) check there are no faces in 2D, cells in 3D, in interface */
7259:   DMPlexGetVTKCellHeight(dm, &cellHeight);
7260:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
7261:   for (l = 0; l < nleaves; ++l) {
7262:     const PetscInt point = locals[l];

7264:     if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
7265:   }

7267:   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
7268:   for (l = 0; l < nleaves; ++l) {
7269:     const PetscInt  point = locals[l];
7270:     const PetscInt *cone;
7271:     PetscInt        coneSize, c, idx;

7273:     DMPlexGetConeSize(dm, point, &coneSize);
7274:     DMPlexGetCone(dm, point, &cone);
7275:     for (c = 0; c < coneSize; ++c) {
7276:       if (!rootdegree[cone[c]]) {
7277:         PetscFindInt(cone[c], nleaves, locals, &idx);
7278:         if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
7279:       }
7280:     }
7281:   }
7282:   return(0);
7283: }

7285: typedef struct cell_stats
7286: {
7287:   PetscReal min, max, sum, squaresum;
7288:   PetscInt  count;
7289: } cell_stats_t;

7291: static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
7292: {
7293:   PetscInt i, N = *len;

7295:   for (i = 0; i < N; i++) {
7296:     cell_stats_t *A = (cell_stats_t *) a;
7297:     cell_stats_t *B = (cell_stats_t *) b;

7299:     B->min = PetscMin(A->min,B->min);
7300:     B->max = PetscMax(A->max,B->max);
7301:     B->sum += A->sum;
7302:     B->squaresum += A->squaresum;
7303:     B->count += A->count;
7304:   }
7305: }

7307: /*@
7308:   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.

7310:   Collective on dm

7312:   Input Parameters:
7313: + dm        - The DMPlex object
7314: . output    - If true, statistics will be displayed on stdout
7315: - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output

7317:   Notes:
7318:   This is mainly intended for debugging/testing purposes.

7320:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7322:   Level: developer

7324: .seealso: DMSetFromOptions()
7325: @*/
7326: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
7327: {
7328:   DM             dmCoarse;
7329:   cell_stats_t   stats, globalStats;
7330:   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
7331:   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
7332:   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
7333:   PetscInt       cdim, cStart, cEnd, cMax, c, eStart, eEnd, count = 0;
7334:   PetscMPIInt    rank,size;

7339:   stats.min   = PETSC_MAX_REAL;
7340:   stats.max   = PETSC_MIN_REAL;
7341:   stats.sum   = stats.squaresum = 0.;
7342:   stats.count = 0;

7344:   MPI_Comm_size(comm, &size);
7345:   MPI_Comm_rank(comm, &rank);
7346:   DMGetCoordinateDim(dm,&cdim);
7347:   PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);
7348:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
7349:   DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);
7350:   DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
7351:   cMax = cMax < 0 ? cEnd : cMax;
7352:   for (c = cStart; c < cMax; c++) {
7353:     PetscInt  i;
7354:     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;

7356:     DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
7357:     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
7358:     for (i = 0; i < PetscSqr(cdim); ++i) {
7359:       frobJ    += J[i] * J[i];
7360:       frobInvJ += invJ[i] * invJ[i];
7361:     }
7362:     cond2 = frobJ * frobInvJ;
7363:     cond  = PetscSqrtReal(cond2);

7365:     stats.min        = PetscMin(stats.min,cond);
7366:     stats.max        = PetscMax(stats.max,cond);
7367:     stats.sum       += cond;
7368:     stats.squaresum += cond2;
7369:     stats.count++;
7370:     if (output && cond > limit) {
7371:       PetscSection coordSection;
7372:       Vec          coordsLocal;
7373:       PetscScalar *coords = NULL;
7374:       PetscInt     Nv, d, clSize, cl, *closure = NULL;

7376:       DMGetCoordinatesLocal(dm, &coordsLocal);
7377:       DMGetCoordinateSection(dm, &coordSection);
7378:       DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7379:       PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);
7380:       for (i = 0; i < Nv/cdim; ++i) {
7381:         PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);
7382:         for (d = 0; d < cdim; ++d) {
7383:           if (d > 0) {PetscSynchronizedPrintf(comm, ", ");}
7384:           PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));
7385:         }
7386:         PetscSynchronizedPrintf(comm, ")\n");
7387:       }
7388:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7389:       for (cl = 0; cl < clSize*2; cl += 2) {
7390:         const PetscInt edge = closure[cl];

7392:         if ((edge >= eStart) && (edge < eEnd)) {
7393:           PetscReal len;

7395:           DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);
7396:           PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);
7397:         }
7398:       }
7399:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7400:       DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7401:     }
7402:   }
7403:   if (output) {PetscSynchronizedFlush(comm, NULL);}

7405:   if (size > 1) {
7406:     PetscMPIInt   blockLengths[2] = {4,1};
7407:     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
7408:     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
7409:     MPI_Op        statReduce;

7411:     MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
7412:     MPI_Type_commit(&statType);
7413:     MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
7414:     MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
7415:     MPI_Op_free(&statReduce);
7416:     MPI_Type_free(&statType);
7417:   } else {
7418:     PetscArraycpy(&globalStats,&stats,1);
7419:   }
7420:   if (!rank) {
7421:     count = globalStats.count;
7422:     min   = globalStats.min;
7423:     max   = globalStats.max;
7424:     mean  = globalStats.sum / globalStats.count;
7425:     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
7426:   }

7428:   if (output) {
7429:     PetscPrintf(comm,"Mesh with %D cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double) min, (double) max, (double) mean, (double) stdev);
7430:   }
7431:   PetscFree2(J,invJ);

7433:   DMGetCoarseDM(dm,&dmCoarse);
7434:   if (dmCoarse) {
7435:     PetscBool isplex;

7437:     PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
7438:     if (isplex) {
7439:       DMPlexCheckCellShape(dmCoarse,output,condLimit);
7440:     }
7441:   }
7442:   return(0);
7443: }

7445: /* Pointwise interpolation
7446:      Just code FEM for now
7447:      u^f = I u^c
7448:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
7449:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
7450:      I_{ij} = psi^f_i phi^c_j
7451: */
7452: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
7453: {
7454:   PetscSection   gsc, gsf;
7455:   PetscInt       m, n;
7456:   void          *ctx;
7457:   DM             cdm;
7458:   PetscBool      regular, ismatis;

7462:   DMGetGlobalSection(dmFine, &gsf);
7463:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7464:   DMGetGlobalSection(dmCoarse, &gsc);
7465:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7467:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
7468:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
7469:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7470:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
7471:   DMGetApplicationContext(dmFine, &ctx);

7473:   DMGetCoarseDM(dmFine, &cdm);
7474:   DMPlexGetRegularRefinement(dmFine, &regular);
7475:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
7476:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
7477:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
7478:   if (scaling) {
7479:     /* Use naive scaling */
7480:     DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
7481:   }
7482:   return(0);
7483: }

7485: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
7486: {
7488:   VecScatter     ctx;

7491:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
7492:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
7493:   VecScatterDestroy(&ctx);
7494:   return(0);
7495: }

7497: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
7498: {
7499:   PetscSection   gsc, gsf;
7500:   PetscInt       m, n;
7501:   void          *ctx;
7502:   DM             cdm;
7503:   PetscBool      regular;

7507:   DMGetGlobalSection(dmFine, &gsf);
7508:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7509:   DMGetGlobalSection(dmCoarse, &gsc);
7510:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7512:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
7513:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7514:   MatSetType(*mass, dmCoarse->mattype);
7515:   DMGetApplicationContext(dmFine, &ctx);

7517:   DMGetCoarseDM(dmFine, &cdm);
7518:   DMPlexGetRegularRefinement(dmFine, &regular);
7519:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
7520:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
7521:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
7522:   return(0);
7523: }

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

7528:   Input Parameter:
7529: . dm - The DMPlex object

7531:   Output Parameter:
7532: . regular - The flag

7534:   Level: intermediate

7536: .seealso: DMPlexSetRegularRefinement()
7537: @*/
7538: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7539: {
7543:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7544:   return(0);
7545: }

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

7550:   Input Parameters:
7551: + dm - The DMPlex object
7552: - regular - The flag

7554:   Level: intermediate

7556: .seealso: DMPlexGetRegularRefinement()
7557: @*/
7558: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7559: {
7562:   ((DM_Plex *) dm->data)->regularRefinement = regular;
7563:   return(0);
7564: }

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

7571:   not collective

7573:   Input Parameters:
7574: . dm - The DMPlex object

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


7581:   Level: intermediate

7583: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7584: @*/
7585: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7586: {
7587:   DM_Plex *plex = (DM_Plex *)dm->data;

7592:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7593:   if (anchorSection) *anchorSection = plex->anchorSection;
7594:   if (anchorIS) *anchorIS = plex->anchorIS;
7595:   return(0);
7596: }

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

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

7606:   collective on dm

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

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

7615:   Level: intermediate

7617: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7618: @*/
7619: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7620: {
7621:   DM_Plex        *plex = (DM_Plex *)dm->data;
7622:   PetscMPIInt    result;

7627:   if (anchorSection) {
7629:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7630:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7631:   }
7632:   if (anchorIS) {
7634:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7635:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7636:   }

7638:   PetscObjectReference((PetscObject)anchorSection);
7639:   PetscSectionDestroy(&plex->anchorSection);
7640:   plex->anchorSection = anchorSection;

7642:   PetscObjectReference((PetscObject)anchorIS);
7643:   ISDestroy(&plex->anchorIS);
7644:   plex->anchorIS = anchorIS;

7646: #if defined(PETSC_USE_DEBUG)
7647:   if (anchorIS && anchorSection) {
7648:     PetscInt size, a, pStart, pEnd;
7649:     const PetscInt *anchors;

7651:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7652:     ISGetLocalSize(anchorIS,&size);
7653:     ISGetIndices(anchorIS,&anchors);
7654:     for (a = 0; a < size; a++) {
7655:       PetscInt p;

7657:       p = anchors[a];
7658:       if (p >= pStart && p < pEnd) {
7659:         PetscInt dof;

7661:         PetscSectionGetDof(anchorSection,p,&dof);
7662:         if (dof) {
7663:           PetscErrorCode ierr2;

7665:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7666:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7667:         }
7668:       }
7669:     }
7670:     ISRestoreIndices(anchorIS,&anchors);
7671:   }
7672: #endif
7673:   /* reset the generic constraints */
7674:   DMSetDefaultConstraints(dm,NULL,NULL);
7675:   return(0);
7676: }

7678: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7679: {
7680:   PetscSection anchorSection;
7681:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

7686:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7687:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
7688:   PetscSectionGetNumFields(section,&numFields);
7689:   if (numFields) {
7690:     PetscInt f;
7691:     PetscSectionSetNumFields(*cSec,numFields);

7693:     for (f = 0; f < numFields; f++) {
7694:       PetscInt numComp;

7696:       PetscSectionGetFieldComponents(section,f,&numComp);
7697:       PetscSectionSetFieldComponents(*cSec,f,numComp);
7698:     }
7699:   }
7700:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7701:   PetscSectionGetChart(section,&sStart,&sEnd);
7702:   pStart = PetscMax(pStart,sStart);
7703:   pEnd   = PetscMin(pEnd,sEnd);
7704:   pEnd   = PetscMax(pStart,pEnd);
7705:   PetscSectionSetChart(*cSec,pStart,pEnd);
7706:   for (p = pStart; p < pEnd; p++) {
7707:     PetscSectionGetDof(anchorSection,p,&dof);
7708:     if (dof) {
7709:       PetscSectionGetDof(section,p,&dof);
7710:       PetscSectionSetDof(*cSec,p,dof);
7711:       for (f = 0; f < numFields; f++) {
7712:         PetscSectionGetFieldDof(section,p,f,&dof);
7713:         PetscSectionSetFieldDof(*cSec,p,f,dof);
7714:       }
7715:     }
7716:   }
7717:   PetscSectionSetUp(*cSec);
7718:   return(0);
7719: }

7721: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7722: {
7723:   PetscSection aSec;
7724:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7725:   const PetscInt *anchors;
7726:   PetscInt numFields, f;
7727:   IS aIS;

7732:   PetscSectionGetStorageSize(cSec, &m);
7733:   PetscSectionGetStorageSize(section, &n);
7734:   MatCreate(PETSC_COMM_SELF,cMat);
7735:   MatSetSizes(*cMat,m,n,m,n);
7736:   MatSetType(*cMat,MATSEQAIJ);
7737:   DMPlexGetAnchors(dm,&aSec,&aIS);
7738:   ISGetIndices(aIS,&anchors);
7739:   /* cSec will be a subset of aSec and section */
7740:   PetscSectionGetChart(cSec,&pStart,&pEnd);
7741:   PetscMalloc1(m+1,&i);
7742:   i[0] = 0;
7743:   PetscSectionGetNumFields(section,&numFields);
7744:   for (p = pStart; p < pEnd; p++) {
7745:     PetscInt rDof, rOff, r;

7747:     PetscSectionGetDof(aSec,p,&rDof);
7748:     if (!rDof) continue;
7749:     PetscSectionGetOffset(aSec,p,&rOff);
7750:     if (numFields) {
7751:       for (f = 0; f < numFields; f++) {
7752:         annz = 0;
7753:         for (r = 0; r < rDof; r++) {
7754:           a = anchors[rOff + r];
7755:           PetscSectionGetFieldDof(section,a,f,&aDof);
7756:           annz += aDof;
7757:         }
7758:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7759:         PetscSectionGetFieldOffset(cSec,p,f,&off);
7760:         for (q = 0; q < dof; q++) {
7761:           i[off + q + 1] = i[off + q] + annz;
7762:         }
7763:       }
7764:     }
7765:     else {
7766:       annz = 0;
7767:       for (q = 0; q < dof; q++) {
7768:         a = anchors[off + q];
7769:         PetscSectionGetDof(section,a,&aDof);
7770:         annz += aDof;
7771:       }
7772:       PetscSectionGetDof(cSec,p,&dof);
7773:       PetscSectionGetOffset(cSec,p,&off);
7774:       for (q = 0; q < dof; q++) {
7775:         i[off + q + 1] = i[off + q] + annz;
7776:       }
7777:     }
7778:   }
7779:   nnz = i[m];
7780:   PetscMalloc1(nnz,&j);
7781:   offset = 0;
7782:   for (p = pStart; p < pEnd; p++) {
7783:     if (numFields) {
7784:       for (f = 0; f < numFields; f++) {
7785:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7786:         for (q = 0; q < dof; q++) {
7787:           PetscInt rDof, rOff, r;
7788:           PetscSectionGetDof(aSec,p,&rDof);
7789:           PetscSectionGetOffset(aSec,p,&rOff);
7790:           for (r = 0; r < rDof; r++) {
7791:             PetscInt s;

7793:             a = anchors[rOff + r];
7794:             PetscSectionGetFieldDof(section,a,f,&aDof);
7795:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7796:             for (s = 0; s < aDof; s++) {
7797:               j[offset++] = aOff + s;
7798:             }
7799:           }
7800:         }
7801:       }
7802:     }
7803:     else {
7804:       PetscSectionGetDof(cSec,p,&dof);
7805:       for (q = 0; q < dof; q++) {
7806:         PetscInt rDof, rOff, r;
7807:         PetscSectionGetDof(aSec,p,&rDof);
7808:         PetscSectionGetOffset(aSec,p,&rOff);
7809:         for (r = 0; r < rDof; r++) {
7810:           PetscInt s;

7812:           a = anchors[rOff + r];
7813:           PetscSectionGetDof(section,a,&aDof);
7814:           PetscSectionGetOffset(section,a,&aOff);
7815:           for (s = 0; s < aDof; s++) {
7816:             j[offset++] = aOff + s;
7817:           }
7818:         }
7819:       }
7820:     }
7821:   }
7822:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7823:   PetscFree(i);
7824:   PetscFree(j);
7825:   ISRestoreIndices(aIS,&anchors);
7826:   return(0);
7827: }

7829: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7830: {
7831:   DM_Plex        *plex = (DM_Plex *)dm->data;
7832:   PetscSection   anchorSection, section, cSec;
7833:   Mat            cMat;

7838:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7839:   if (anchorSection) {
7840:     PetscInt Nf;

7842:     DMGetLocalSection(dm,&section);
7843:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7844:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7845:     DMGetNumFields(dm,&Nf);
7846:     if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7847:     DMSetDefaultConstraints(dm,cSec,cMat);
7848:     PetscSectionDestroy(&cSec);
7849:     MatDestroy(&cMat);
7850:   }
7851:   return(0);
7852: }

7854: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7855: {
7856:   IS             subis;
7857:   PetscSection   section, subsection;

7861:   DMGetLocalSection(dm, &section);
7862:   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7863:   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7864:   /* Create subdomain */
7865:   DMPlexFilter(dm, label, value, subdm);
7866:   /* Create submodel */
7867:   DMPlexCreateSubpointIS(*subdm, &subis);
7868:   PetscSectionCreateSubmeshSection(section, subis, &subsection);
7869:   ISDestroy(&subis);
7870:   DMSetLocalSection(*subdm, subsection);
7871:   PetscSectionDestroy(&subsection);
7872:   DMCopyDisc(dm, *subdm);
7873:   /* Create map from submodel to global model */
7874:   if (is) {
7875:     PetscSection    sectionGlobal, subsectionGlobal;
7876:     IS              spIS;
7877:     const PetscInt *spmap;
7878:     PetscInt       *subIndices;
7879:     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
7880:     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];

7882:     DMPlexCreateSubpointIS(*subdm, &spIS);
7883:     ISGetIndices(spIS, &spmap);
7884:     PetscSectionGetNumFields(section, &Nf);
7885:     DMGetGlobalSection(dm, &sectionGlobal);
7886:     DMGetGlobalSection(*subdm, &subsectionGlobal);
7887:     PetscSectionGetChart(subsection, &pStart, &pEnd);
7888:     for (p = pStart; p < pEnd; ++p) {
7889:       PetscInt gdof, pSubSize  = 0;

7891:       PetscSectionGetDof(sectionGlobal, p, &gdof);
7892:       if (gdof > 0) {
7893:         for (f = 0; f < Nf; ++f) {
7894:           PetscInt fdof, fcdof;

7896:           PetscSectionGetFieldDof(subsection, p, f, &fdof);
7897:           PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7898:           pSubSize += fdof-fcdof;
7899:         }
7900:         subSize += pSubSize;
7901:         if (pSubSize) {
7902:           if (bs < 0) {
7903:             bs = pSubSize;
7904:           } else if (bs != pSubSize) {
7905:             /* Layout does not admit a pointwise block size */
7906:             bs = 1;
7907:           }
7908:         }
7909:       }
7910:     }
7911:     /* Must have same blocksize on all procs (some might have no points) */
7912:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7913:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7914:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7915:     else                            {bs = bsMinMax[0];}
7916:     PetscMalloc1(subSize, &subIndices);
7917:     for (p = pStart; p < pEnd; ++p) {
7918:       PetscInt gdof, goff;

7920:       PetscSectionGetDof(subsectionGlobal, p, &gdof);
7921:       if (gdof > 0) {
7922:         const PetscInt point = spmap[p];

7924:         PetscSectionGetOffset(sectionGlobal, point, &goff);
7925:         for (f = 0; f < Nf; ++f) {
7926:           PetscInt fdof, fcdof, fc, f2, poff = 0;

7928:           /* Can get rid of this loop by storing field information in the global section */
7929:           for (f2 = 0; f2 < f; ++f2) {
7930:             PetscSectionGetFieldDof(section, p, f2, &fdof);
7931:             PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7932:             poff += fdof-fcdof;
7933:           }
7934:           PetscSectionGetFieldDof(section, p, f, &fdof);
7935:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7936:           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7937:             subIndices[subOff] = goff+poff+fc;
7938:           }
7939:         }
7940:       }
7941:     }
7942:     ISRestoreIndices(spIS, &spmap);
7943:     ISDestroy(&spIS);
7944:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7945:     if (bs > 1) {
7946:       /* We need to check that the block size does not come from non-contiguous fields */
7947:       PetscInt i, j, set = 1;
7948:       for (i = 0; i < subSize; i += bs) {
7949:         for (j = 0; j < bs; ++j) {
7950:           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7951:         }
7952:       }
7953:       if (set) {ISSetBlockSize(*is, bs);}
7954:     }
7955:     /* Attach nullspace */
7956:     for (f = 0; f < Nf; ++f) {
7957:       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7958:       if ((*subdm)->nullspaceConstructors[f]) break;
7959:     }
7960:     if (f < Nf) {
7961:       MatNullSpace nullSpace;

7963:       (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7964:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7965:       MatNullSpaceDestroy(&nullSpace);
7966:     }
7967:   }
7968:   return(0);
7969: }

7971: /*@
7972:   DMPlexMonitorThroughput - Report the cell throughput of FE integration

7974:   Input Parameter:
7975: - dm - The DM

7977:   Level: developer

7979:   Options Database Keys:
7980: . -dm_plex_monitor_throughput - Activate the monitor

7982: .seealso: DMSetFromOptions(), DMPlexCreate()
7983: @*/
7984: PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
7985: {
7986:   PetscStageLog      stageLog;
7987:   PetscLogEvent      event;
7988:   PetscLogStage      stage;
7989:   PetscEventPerfInfo eventInfo;
7990:   PetscReal          cellRate, flopRate;
7991:   PetscInt           cStart, cEnd, Nf, N;
7992:   const char        *name;
7993:   PetscErrorCode     ierr;

7997: #if defined(PETSC_USE_LOG)
7998:   PetscObjectGetName((PetscObject) dm, &name);
7999:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
8000:   DMGetNumFields(dm, &Nf);
8001:   PetscLogGetStageLog(&stageLog);
8002:   PetscStageLogGetCurrent(stageLog, &stage);
8003:   PetscLogEventGetId("DMPlexResidualFE", &event);
8004:   PetscLogEventGetPerfInfo(stage, event, &eventInfo);
8005:   N        = (cEnd - cStart)*Nf*eventInfo.count;
8006:   flopRate = eventInfo.flops/eventInfo.time;
8007:   cellRate = N/eventInfo.time;
8008:   PetscPrintf(PetscObjectComm((PetscObject) dm), "DM (%s) FE Residual Integration: %D integrals %D reps\n  Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, (double) cellRate, (double) flopRate/1.e6);
8009: #else
8010:   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
8011: #endif
8012:   return(0);
8013: }