Actual source code: plex.c

petsc-master 2019-10-20
Report Typos and Errors
  1:  #include <petsc/private/dmpleximpl.h>
  2:  #include <petsc/private/isimpl.h>
  3:  #include <petsc/private/vecimpl.h>
  4:  #include <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_POINT_FIELD;
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 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
135:   return(0);
136: }

138: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
139: {
140:   DM                 dm;
141:   PetscSection       s;
142:   PetscDraw          draw, popup;
143:   DM                 cdm;
144:   PetscSection       coordSection;
145:   Vec                coordinates;
146:   const PetscScalar *coords, *array;
147:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
148:   PetscReal          vbound[2], time;
149:   PetscBool          isnull, flg;
150:   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
151:   const char        *name;
152:   char               title[PETSC_MAX_PATH_LEN];
153:   PetscErrorCode     ierr;

156:   PetscViewerDrawGetDraw(viewer, 0, &draw);
157:   PetscDrawIsNull(draw, &isnull);
158:   if (isnull) return(0);

160:   VecGetDM(v, &dm);
161:   DMGetCoordinateDim(dm, &dim);
162:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
163:   DMGetLocalSection(dm, &s);
164:   PetscSectionGetNumFields(s, &Nf);
165:   DMGetCoarsenLevel(dm, &level);
166:   DMGetCoordinateDM(dm, &cdm);
167:   DMGetLocalSection(cdm, &coordSection);
168:   DMGetCoordinatesLocal(dm, &coordinates);
169:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
170:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

172:   PetscObjectGetName((PetscObject) v, &name);
173:   DMGetOutputSequenceNumber(dm, &step, &time);

175:   VecGetLocalSize(coordinates, &N);
176:   VecGetArrayRead(coordinates, &coords);
177:   for (c = 0; c < N; c += dim) {
178:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
179:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
180:   }
181:   VecRestoreArrayRead(coordinates, &coords);
182:   PetscDrawClear(draw);

184:   /* Could implement something like DMDASelectFields() */
185:   for (f = 0; f < Nf; ++f) {
186:     DM   fdm = dm;
187:     Vec  fv  = v;
188:     IS   fis;
189:     char prefix[PETSC_MAX_PATH_LEN];
190:     const char *fname;

192:     PetscSectionGetFieldComponents(s, f, &Nc);
193:     PetscSectionGetFieldName(s, f, &fname);

195:     if (v->hdr.prefix) {PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));}
196:     else               {prefix[0] = '\0';}
197:     if (Nf > 1) {
198:       DMCreateSubDM(dm, 1, &f, &fis, &fdm);
199:       VecGetSubVector(v, fis, &fv);
200:       PetscStrlcat(prefix, fname,sizeof(prefix));
201:       PetscStrlcat(prefix, "_",sizeof(prefix));
202:     }
203:     for (comp = 0; comp < Nc; ++comp, ++w) {
204:       PetscInt nmax = 2;

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

211:       /* TODO Get max and min only for this component */
212:       PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
213:       if (!flg) {
214:         VecMin(fv, NULL, &vbound[0]);
215:         VecMax(fv, NULL, &vbound[1]);
216:         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
217:       }
218:       PetscDrawGetPopup(draw, &popup);
219:       PetscDrawScalePopup(popup, vbound[0], vbound[1]);
220:       PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);

222:       VecGetArrayRead(fv, &array);
223:       for (c = cStart; c < cEnd; ++c) {
224:         PetscScalar *coords = NULL, *a = NULL;
225:         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};

227:         DMPlexPointLocalRead(fdm, c, array, &a);
228:         if (a) {
229:           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
230:           color[1] = color[2] = color[3] = color[0];
231:         } else {
232:           PetscScalar *vals = NULL;
233:           PetscInt     numVals, va;

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

277: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
278: {
279:   DM                      dm;
280:   Vec                     locv;
281:   const char              *name;
282:   PetscSection            section;
283:   PetscInt                pStart, pEnd;
284:   PetscViewerVTKFieldType ft;
285:   PetscErrorCode          ierr;

288:   VecGetDM(v, &dm);
289:   DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
290:   PetscObjectGetName((PetscObject) v, &name);
291:   PetscObjectSetName((PetscObject) locv, name);
292:   VecCopy(v, locv);
293:   DMGetLocalSection(dm, &section);
294:   DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
295:   PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, PETSC_TRUE,(PetscObject) locv);
296:   return(0);
297: }

299: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
300: {
301:   DM             dm;
302:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

306:   VecGetDM(v, &dm);
307:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
308:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
309:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
310:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
311:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
312:   if (isvtk || ishdf5 || isdraw || isglvis) {
313:     PetscInt    i,numFields;
314:     PetscObject fe;
315:     PetscBool   fem = PETSC_FALSE;
316:     Vec         locv = v;
317:     const char  *name;
318:     PetscInt    step;
319:     PetscReal   time;

321:     DMGetNumFields(dm, &numFields);
322:     for (i=0; i<numFields; i++) {
323:       DMGetField(dm, i, NULL, &fe);
324:       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
325:     }
326:     if (fem) {
327:       DMGetLocalVector(dm, &locv);
328:       PetscObjectGetName((PetscObject) v, &name);
329:       PetscObjectSetName((PetscObject) locv, name);
330:       VecCopy(v, locv);
331:       DMGetOutputSequenceNumber(dm, NULL, &time);
332:       DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
333:     }
334:     if (isvtk) {
335:       VecView_Plex_Local_VTK(locv, viewer);
336:     } else if (ishdf5) {
337: #if defined(PETSC_HAVE_HDF5)
338:       VecView_Plex_Local_HDF5_Internal(locv, viewer);
339: #else
340:       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
341: #endif
342:     } else if (isdraw) {
343:       VecView_Plex_Local_Draw(locv, viewer);
344:     } else if (isglvis) {
345:       DMGetOutputSequenceNumber(dm, &step, NULL);
346:       PetscViewerGLVisSetSnapId(viewer, step);
347:       VecView_GLVis(locv, viewer);
348:     }
349:     if (fem) {DMRestoreLocalVector(dm, &locv);}
350:   } else {
351:     PetscBool isseq;

353:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
354:     if (isseq) {VecView_Seq(v, viewer);}
355:     else       {VecView_MPI(v, viewer);}
356:   }
357:   return(0);
358: }

360: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
361: {
362:   DM             dm;
363:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

367:   VecGetDM(v, &dm);
368:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
369:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
370:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
371:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
372:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
373:   if (isvtk || isdraw || isglvis) {
374:     Vec         locv;
375:     const char *name;

377:     DMGetLocalVector(dm, &locv);
378:     PetscObjectGetName((PetscObject) v, &name);
379:     PetscObjectSetName((PetscObject) locv, name);
380:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
381:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
382:     VecView_Plex_Local(locv, viewer);
383:     DMRestoreLocalVector(dm, &locv);
384:   } else if (ishdf5) {
385: #if defined(PETSC_HAVE_HDF5)
386:     VecView_Plex_HDF5_Internal(v, viewer);
387: #else
388:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
389: #endif
390:   } else {
391:     PetscBool isseq;

393:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
394:     if (isseq) {VecView_Seq(v, viewer);}
395:     else       {VecView_MPI(v, viewer);}
396:   }
397:   return(0);
398: }

400: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
401: {
402:   DM                dm;
403:   MPI_Comm          comm;
404:   PetscViewerFormat format;
405:   Vec               v;
406:   PetscBool         isvtk, ishdf5;
407:   PetscErrorCode    ierr;

410:   VecGetDM(originalv, &dm);
411:   PetscObjectGetComm((PetscObject) originalv, &comm);
412:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
413:   PetscViewerGetFormat(viewer, &format);
414:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
415:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
416:   if (format == PETSC_VIEWER_NATIVE) {
417:     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
418:     /* this need a better fix */
419:     if (dm->useNatural) {
420:       if (dm->sfNatural) {
421:         const char *vecname;
422:         PetscInt    n, nroots;

424:         VecGetLocalSize(originalv, &n);
425:         PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
426:         if (n == nroots) {
427:           DMGetGlobalVector(dm, &v);
428:           DMPlexGlobalToNaturalBegin(dm, originalv, v);
429:           DMPlexGlobalToNaturalEnd(dm, originalv, v);
430:           PetscObjectGetName((PetscObject) originalv, &vecname);
431:           PetscObjectSetName((PetscObject) v, vecname);
432:         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
433:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
434:     } else v = originalv;
435:   } else v = originalv;

437:   if (ishdf5) {
438: #if defined(PETSC_HAVE_HDF5)
439:     VecView_Plex_HDF5_Native_Internal(v, viewer);
440: #else
441:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
442: #endif
443:   } else if (isvtk) {
444:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
445:   } else {
446:     PetscBool isseq;

448:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
449:     if (isseq) {VecView_Seq(v, viewer);}
450:     else       {VecView_MPI(v, viewer);}
451:   }
452:   if (v != originalv) {DMRestoreGlobalVector(dm, &v);}
453:   return(0);
454: }

456: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
457: {
458:   DM             dm;
459:   PetscBool      ishdf5;

463:   VecGetDM(v, &dm);
464:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
465:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
466:   if (ishdf5) {
467:     DM          dmBC;
468:     Vec         gv;
469:     const char *name;

471:     DMGetOutputDM(dm, &dmBC);
472:     DMGetGlobalVector(dmBC, &gv);
473:     PetscObjectGetName((PetscObject) v, &name);
474:     PetscObjectSetName((PetscObject) gv, name);
475:     VecLoad_Default(gv, viewer);
476:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
477:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
478:     DMRestoreGlobalVector(dmBC, &gv);
479:   } else {
480:     VecLoad_Default(v, viewer);
481:   }
482:   return(0);
483: }

485: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
486: {
487:   DM             dm;
488:   PetscBool      ishdf5;

492:   VecGetDM(v, &dm);
493:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
494:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
495:   if (ishdf5) {
496: #if defined(PETSC_HAVE_HDF5)
497:     VecLoad_Plex_HDF5_Internal(v, viewer);
498: #else
499:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
500: #endif
501:   } else {
502:     VecLoad_Default(v, viewer);
503:   }
504:   return(0);
505: }

507: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
508: {
509:   DM                dm;
510:   PetscViewerFormat format;
511:   PetscBool         ishdf5;
512:   PetscErrorCode    ierr;

515:   VecGetDM(originalv, &dm);
516:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
517:   PetscViewerGetFormat(viewer, &format);
518:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
519:   if (format == PETSC_VIEWER_NATIVE) {
520:     if (dm->useNatural) {
521:       if (dm->sfNatural) {
522:         if (ishdf5) {
523: #if defined(PETSC_HAVE_HDF5)
524:           Vec         v;
525:           const char *vecname;

527:           DMGetGlobalVector(dm, &v);
528:           PetscObjectGetName((PetscObject) originalv, &vecname);
529:           PetscObjectSetName((PetscObject) v, vecname);
530:           VecLoad_Plex_HDF5_Native_Internal(v, viewer);
531:           DMPlexNaturalToGlobalBegin(dm, v, originalv);
532:           DMPlexNaturalToGlobalEnd(dm, v, originalv);
533:           DMRestoreGlobalVector(dm, &v);
534: #else
535:           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
536: #endif
537:         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
538:       }
539:     } else {
540:       VecLoad_Default(originalv, viewer);
541:     }
542:   }
543:   return(0);
544: }

546: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
547: {
548:   PetscSection       coordSection;
549:   Vec                coordinates;
550:   DMLabel            depthLabel;
551:   const char        *name[4];
552:   const PetscScalar *a;
553:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
554:   PetscErrorCode     ierr;

557:   DMGetDimension(dm, &dim);
558:   DMGetCoordinatesLocal(dm, &coordinates);
559:   DMGetCoordinateSection(dm, &coordSection);
560:   DMPlexGetDepthLabel(dm, &depthLabel);
561:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
562:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
563:   VecGetArrayRead(coordinates, &a);
564:   name[0]     = "vertex";
565:   name[1]     = "edge";
566:   name[dim-1] = "face";
567:   name[dim]   = "cell";
568:   for (c = cStart; c < cEnd; ++c) {
569:     PetscInt *closure = NULL;
570:     PetscInt  closureSize, cl;

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

578:       if ((point < pStart) || (point >= pEnd)) continue;
579:       PetscSectionGetDof(coordSection, point, &dof);
580:       if (!dof) continue;
581:       DMLabelGetValue(depthLabel, point, &depth);
582:       PetscSectionGetOffset(coordSection, point, &off);
583:       PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
584:       for (p = 0; p < dof/dim; ++p) {
585:         PetscViewerASCIIPrintf(viewer, " (");
586:         for (d = 0; d < dim; ++d) {
587:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
588:           PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));
589:         }
590:         PetscViewerASCIIPrintf(viewer, ")");
591:       }
592:       PetscViewerASCIIPrintf(viewer, "\n");
593:     }
594:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
595:     PetscViewerASCIIPopTab(viewer);
596:   }
597:   VecRestoreArrayRead(coordinates, &a);
598:   return(0);
599: }

601: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
602: {
603:   DM_Plex          *mesh = (DM_Plex*) dm->data;
604:   DM                cdm;
605:   DMLabel           markers;
606:   PetscSection      coordSection;
607:   Vec               coordinates;
608:   PetscViewerFormat format;
609:   PetscErrorCode    ierr;

612:   DMGetCoordinateDM(dm, &cdm);
613:   DMGetLocalSection(cdm, &coordSection);
614:   DMGetCoordinatesLocal(dm, &coordinates);
615:   PetscViewerGetFormat(viewer, &format);
616:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
617:     const char *name;
618:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
619:     PetscInt    pStart, pEnd, p;
620:     PetscMPIInt rank, size;

622:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
623:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
624:     PetscObjectGetName((PetscObject) dm, &name);
625:     DMPlexGetChart(dm, &pStart, &pEnd);
626:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
627:     DMGetDimension(dm, &dim);
628:     DMPlexGetVTKCellHeight(dm, &cellHeight);
629:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
630:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
631:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
632:     PetscViewerASCIIPrintf(viewer, "Supports:\n", name);
633:     PetscViewerASCIIPushSynchronized(viewer);
634:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);
635:     for (p = pStart; p < pEnd; ++p) {
636:       PetscInt dof, off, s;

638:       PetscSectionGetDof(mesh->supportSection, p, &dof);
639:       PetscSectionGetOffset(mesh->supportSection, p, &off);
640:       for (s = off; s < off+dof; ++s) {
641:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
642:       }
643:     }
644:     PetscViewerFlush(viewer);
645:     PetscViewerASCIIPrintf(viewer, "Cones:\n", name);
646:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);
647:     for (p = pStart; p < pEnd; ++p) {
648:       PetscInt dof, off, c;

650:       PetscSectionGetDof(mesh->coneSection, p, &dof);
651:       PetscSectionGetOffset(mesh->coneSection, p, &off);
652:       for (c = off; c < off+dof; ++c) {
653:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
654:       }
655:     }
656:     PetscViewerFlush(viewer);
657:     PetscViewerASCIIPopSynchronized(viewer);
658:     if (coordSection && coordinates) {
659:       PetscSectionVecView(coordSection, coordinates, viewer);
660:     }
661:     DMGetLabel(dm, "marker", &markers);
662:     if (markers) {DMLabelView(markers,viewer);}
663:     if (size > 1) {
664:       PetscSF sf;

666:       DMGetPointSF(dm, &sf);
667:       PetscSFView(sf, viewer);
668:     }
669:     PetscViewerFlush(viewer);
670:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
671:     const char  *name, *color;
672:     const char  *defcolors[3]  = {"gray", "orange", "green"};
673:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
674:     char         lname[PETSC_MAX_PATH_LEN];
675:     PetscReal    scale         = 2.0;
676:     PetscReal    tikzscale     = 1.0;
677:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
678:     double       tcoords[3];
679:     PetscScalar *coords;
680:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
681:     PetscMPIInt  rank, size;
682:     char         **names, **colors, **lcolors;
683:     PetscBool    plotEdges, flg, lflg;
684:     PetscBT      wp = NULL;
685:     PetscInt     pEnd, pStart;

687:     DMGetDimension(dm, &dim);
688:     DMPlexGetDepth(dm, &depth);
689:     DMGetNumLabels(dm, &numLabels);
690:     numLabels  = PetscMax(numLabels, 10);
691:     numColors  = 10;
692:     numLColors = 10;
693:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
694:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
695:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);
696:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
697:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
698:     if (!useLabels) numLabels = 0;
699:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
700:     if (!useColors) {
701:       numColors = 3;
702:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
703:     }
704:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
705:     if (!useColors) {
706:       numLColors = 4;
707:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
708:     }
709:     PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, PETSC_MAX_PATH_LEN, &lflg);
710:     plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
711:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);
712:     if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
713:     if (depth < dim) plotEdges = PETSC_FALSE;

715:     /* filter points with labelvalue != labeldefaultvalue */
716:     DMPlexGetChart(dm, &pStart, &pEnd);
717:     if (lflg) {
718:       DMLabel lbl;

720:       DMGetLabel(dm, lname, &lbl);
721:       if (lbl) {
722:         PetscInt val, defval;

724:         DMLabelGetDefaultValue(lbl, &defval);
725:         PetscBTCreate(pEnd-pStart, &wp);
726:         for (c = pStart;  c < pEnd; c++) {
727:           PetscInt *closure = NULL;
728:           PetscInt  closureSize;

730:           DMLabelGetValue(lbl, c, &val);
731:           if (val == defval) continue;

733:           DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
734:           for (p = 0; p < closureSize*2; p += 2) {
735:             PetscBTSet(wp, closure[p] - pStart);
736:           }
737:           DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
738:         }
739:       }
740:     }

742:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
743:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
744:     PetscObjectGetName((PetscObject) dm, &name);
745:     PetscViewerASCIIPrintf(viewer, "\
746: \\documentclass[tikz]{standalone}\n\n\
747: \\usepackage{pgflibraryshapes}\n\
748: \\usetikzlibrary{backgrounds}\n\
749: \\usetikzlibrary{arrows}\n\
750: \\begin{document}\n");
751:     if (size > 1) {
752:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
753:       for (p = 0; p < size; ++p) {
754:         if (p > 0 && p == size-1) {
755:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
756:         } else if (p > 0) {
757:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
758:         }
759:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
760:       }
761:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
762:     }
763:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);

765:     /* Plot vertices */
766:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
767:     VecGetArray(coordinates, &coords);
768:     PetscViewerASCIIPushSynchronized(viewer);
769:     for (v = vStart; v < vEnd; ++v) {
770:       PetscInt  off, dof, d;
771:       PetscBool isLabeled = PETSC_FALSE;

773:       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
774:       PetscSectionGetDof(coordSection, v, &dof);
775:       PetscSectionGetOffset(coordSection, v, &off);
776:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
777:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
778:       for (d = 0; d < dof; ++d) {
779:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
780:         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
781:       }
782:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
783:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
784:       for (d = 0; d < dof; ++d) {
785:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
786:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);
787:       }
788:       color = colors[rank%numColors];
789:       for (l = 0; l < numLabels; ++l) {
790:         PetscInt val;
791:         DMGetLabelValue(dm, names[l], v, &val);
792:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
793:       }
794:       if (useNumbers) {
795:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
796:       } else {
797:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
798:       }
799:     }
800:     VecRestoreArray(coordinates, &coords);
801:     PetscViewerFlush(viewer);
802:     /* Plot cells */
803:     DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
804:     DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
805:     if (dim == 3 || !useNumbers) {
806:       for (e = eStart; e < eEnd; ++e) {
807:         const PetscInt *cone;

809:         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
810:         color = colors[rank%numColors];
811:         for (l = 0; l < numLabels; ++l) {
812:           PetscInt val;
813:           DMGetLabelValue(dm, names[l], e, &val);
814:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
815:         }
816:         DMPlexGetCone(dm, e, &cone);
817:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
818:       }
819:     } else {
820:       for (c = cStart; c < cEnd; ++c) {
821:         PetscInt *closure = NULL;
822:         PetscInt  closureSize, firstPoint = -1;

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

830:           if ((point < vStart) || (point >= vEnd)) continue;
831:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
832:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
833:           if (firstPoint < 0) firstPoint = point;
834:         }
835:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
836:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
837:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
838:       }
839:     }
840:     VecGetArray(coordinates, &coords);
841:     for (c = cStart; c < cEnd; ++c) {
842:       double    ccoords[3] = {0.0, 0.0, 0.0};
843:       PetscBool isLabeled  = PETSC_FALSE;
844:       PetscInt *closure    = NULL;
845:       PetscInt  closureSize, dof, d, n = 0;

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

854:         if ((point < vStart) || (point >= vEnd)) continue;
855:         PetscSectionGetDof(coordSection, point, &dof);
856:         PetscSectionGetOffset(coordSection, point, &off);
857:         for (d = 0; d < dof; ++d) {
858:           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
859:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
860:         }
861:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
862:         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
863:         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
864:         ++n;
865:       }
866:       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
867:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
868:       for (d = 0; d < dof; ++d) {
869:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
870:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);
871:       }
872:       color = colors[rank%numColors];
873:       for (l = 0; l < numLabels; ++l) {
874:         PetscInt val;
875:         DMGetLabelValue(dm, names[l], c, &val);
876:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
877:       }
878:       if (useNumbers) {
879:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);
880:       } else {
881:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);
882:       }
883:     }
884:     VecRestoreArray(coordinates, &coords);
885:     /* Plot edges */
886:     if (plotEdges) {
887:       VecGetArray(coordinates, &coords);
888:       PetscViewerASCIIPrintf(viewer, "\\path\n");
889:       for (e = eStart; e < eEnd; ++e) {
890:         const PetscInt *cone;
891:         PetscInt        coneSize, offA, offB, dof, d;

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

946:     PetscObjectGetComm((PetscObject)dm,&comm);
947:     MPI_Comm_rank(comm,&rank);
948: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
949:     MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);
950: #endif
951:     if (ncomm != MPI_COMM_NULL) {
952:       MPI_Comm_group(comm,&ggroup);
953:       MPI_Comm_group(ncomm,&ngroup);
954:       d1   = 0;
955:       MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);
956:       nid  = d2;
957:       MPI_Group_free(&ggroup);
958:       MPI_Group_free(&ngroup);
959:       MPI_Comm_free(&ncomm);
960:     } else nid = 0.0;

962:     /* Get connectivity */
963:     DMPlexGetVTKCellHeight(dm,&cellHeight);
964:     DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);

966:     /* filter overlapped local cells */
967:     DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);
968:     ISGetIndices(gid,&idxs);
969:     ISGetLocalSize(gid,&cum);
970:     PetscMalloc1(cum,&idxs2);
971:     for (c = cStart, cum = 0; c < cEnd; c++) {
972:       if (idxs[c-cStart] < 0) continue;
973:       idxs2[cum++] = idxs[c-cStart];
974:     }
975:     ISRestoreIndices(gid,&idxs);
976:     if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
977:     ISDestroy(&gid);
978:     ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);

980:     /* support for node-aware cell locality */
981:     ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);
982:     VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);
983:     VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);
984:     VecGetArray(cown,&array);
985:     for (c = 0; c < numVertices; c++) array[c] = nid;
986:     VecRestoreArray(cown,&array);
987:     VecScatterCreate(cown,acis,acown,NULL,&sct);
988:     VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
989:     VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
990:     ISDestroy(&acis);
991:     VecScatterDestroy(&sct);
992:     VecDestroy(&cown);

994:     /* compute edgeCut */
995:     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
996:     PetscMalloc1(cum,&work);
997:     ISLocalToGlobalMappingCreateIS(gid,&g2l);
998:     ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);
999:     ISDestroy(&gid);
1000:     VecGetArray(acown,&array);
1001:     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1002:       PetscInt totl;

1004:       totl = start[c+1]-start[c];
1005:       ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);
1006:       for (i = 0; i < totl; i++) {
1007:         if (work[i] < 0) {
1008:           ect  += 1;
1009:           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1010:         }
1011:       }
1012:     }
1013:     PetscFree(work);
1014:     VecRestoreArray(acown,&array);
1015:     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
1016:     lm[1] = -numVertices;
1017:     MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);
1018:     PetscViewerASCIIPrintf(viewer,"  Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);
1019:     lm[0] = ect; /* edgeCut */
1020:     lm[1] = ectn; /* node-aware edgeCut */
1021:     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1022:     MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);
1023:     PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);
1024: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1025:     PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.);
1026: #else
1027:     PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);
1028: #endif
1029:     ISLocalToGlobalMappingDestroy(&g2l);
1030:     PetscFree(start);
1031:     PetscFree(adjacency);
1032:     VecDestroy(&acown);
1033:   } else {
1034:     MPI_Comm    comm;
1035:     PetscInt   *sizes, *hybsizes, *ghostsizes;
1036:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
1037:     PetscInt    pStart, pEnd, p, gcStart, gcEnd, gcNum;
1038:     PetscInt    numLabels, l;
1039:     const char *name;
1040:     PetscMPIInt size;

1042:     PetscObjectGetComm((PetscObject)dm,&comm);
1043:     MPI_Comm_size(comm, &size);
1044:     DMGetDimension(dm, &dim);
1045:     DMPlexGetVTKCellHeight(dm, &cellHeight);
1046:     PetscObjectGetName((PetscObject) dm, &name);
1047:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
1048:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
1049:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
1050:     DMPlexGetDepth(dm, &locDepth);
1051:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
1052:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);
1053:     DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);
1054:     gcNum = gcEnd - gcStart;
1055:     PetscCalloc3(size,&sizes,size,&hybsizes,size,&ghostsizes);
1056:     if (depth == 1) {
1057:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
1058:       pEnd = pEnd - pStart;
1059:       pMax[0] -= pStart;
1060:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1061:       MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1062:       MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);
1063:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
1064:       for (p = 0; p < size; ++p) {
1065:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1066:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1067:       }
1068:       PetscViewerASCIIPrintf(viewer, "\n");
1069:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
1070:       pEnd = pEnd - pStart;
1071:       pMax[depth] -= pStart;
1072:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1073:       MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1074:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
1075:       for (p = 0; p < size; ++p) {
1076:         PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);
1077:         if (hybsizes[p] >= 0)   {PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);}
1078:         if (ghostsizes[p] > 0) {PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);}
1079:       }
1080:       PetscViewerASCIIPrintf(viewer, "\n");
1081:     } else {
1082:       PetscMPIInt rank;
1083:       MPI_Comm_rank(comm, &rank);
1084:       for (d = 0; d <= dim; d++) {
1085:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
1086:         pEnd    -= pStart;
1087:         pMax[d] -= pStart;
1088:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1089:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1090:         if (d == dim) {MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);}
1091:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
1092:         for (p = 0; p < size; ++p) {
1093:           if (!rank) {
1094:             PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);
1095:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);}
1096:             if (d == dim && ghostsizes[p] > 0) {PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);}
1097:           }
1098:         }
1099:         PetscViewerASCIIPrintf(viewer, "\n");
1100:       }
1101:     }
1102:     PetscFree3(sizes,hybsizes,ghostsizes);
1103:     DMGetNumLabels(dm, &numLabels);
1104:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
1105:     for (l = 0; l < numLabels; ++l) {
1106:       DMLabel         label;
1107:       const char     *name;
1108:       IS              valueIS;
1109:       const PetscInt *values;
1110:       PetscInt        numValues, v;

1112:       DMGetLabelName(dm, l, &name);
1113:       DMGetLabel(dm, name, &label);
1114:       DMLabelGetNumValues(label, &numValues);
1115:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
1116:       DMLabelGetValueIS(label, &valueIS);
1117:       ISGetIndices(valueIS, &values);
1118:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
1119:       for (v = 0; v < numValues; ++v) {
1120:         PetscInt size;

1122:         DMLabelGetStratumSize(label, values[v], &size);
1123:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
1124:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
1125:       }
1126:       PetscViewerASCIIPrintf(viewer, ")\n");
1127:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
1128:       ISRestoreIndices(valueIS, &values);
1129:       ISDestroy(&valueIS);
1130:     }
1131:     /* If no fields are specified, people do not want to see adjacency */
1132:     if (dm->Nf) {
1133:       PetscInt f;

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

1138:         PetscObjectGetName(dm->fields[f].disc, &name);
1139:         if (numLabels) {PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);}
1140:         PetscViewerASCIIPushTab(viewer);
1141:         if (dm->fields[f].label) {DMLabelView(dm->fields[f].label, viewer);}
1142:         if (dm->fields[f].adjacency[0]) {
1143:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");}
1144:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");}
1145:         } else {
1146:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");}
1147:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");}
1148:         }
1149:         PetscViewerASCIIPopTab(viewer);
1150:       }
1151:     }
1152:     DMGetCoarseDM(dm, &cdm);
1153:     if (cdm) {
1154:       PetscViewerASCIIPushTab(viewer);
1155:       DMPlexView_Ascii(cdm, viewer);
1156:       PetscViewerASCIIPopTab(viewer);
1157:     }
1158:   }
1159:   return(0);
1160: }

1162: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1163: {
1164:   PetscDraw          draw;
1165:   DM                 cdm;
1166:   PetscSection       coordSection;
1167:   Vec                coordinates;
1168:   const PetscScalar *coords;
1169:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1170:   PetscBool          isnull;
1171:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
1172:   PetscMPIInt        rank;
1173:   PetscErrorCode     ierr;

1176:   DMGetCoordinateDim(dm, &dim);
1177:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1178:   DMGetCoordinateDM(dm, &cdm);
1179:   DMGetLocalSection(cdm, &coordSection);
1180:   DMGetCoordinatesLocal(dm, &coordinates);
1181:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1182:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

1184:   PetscViewerDrawGetDraw(viewer, 0, &draw);
1185:   PetscDrawIsNull(draw, &isnull);
1186:   if (isnull) return(0);
1187:   PetscDrawSetTitle(draw, "Mesh");

1189:   VecGetLocalSize(coordinates, &N);
1190:   VecGetArrayRead(coordinates, &coords);
1191:   for (c = 0; c < N; c += dim) {
1192:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1193:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1194:   }
1195:   VecRestoreArrayRead(coordinates, &coords);
1196:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1197:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1198:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1199:   PetscDrawClear(draw);

1201:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1202:   for (c = cStart; c < cEnd; ++c) {
1203:     PetscScalar *coords = NULL;
1204:     PetscInt     numCoords,coneSize;

1206:     DMPlexGetConeSize(dm, c, &coneSize);
1207:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1208:     switch (coneSize) {
1209:     case 3:
1210:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1211:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1212:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1213:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1214:       break;
1215:     case 4:
1216:       PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1217:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1218:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1219:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1220:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1221:       break;
1222:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1223:     }
1224:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1225:   }
1226:   for (c = cStart; c < cEnd; ++c) {
1227:     PetscScalar *coords = NULL;
1228:     PetscInt     numCoords,coneSize;

1230:     DMPlexGetConeSize(dm, c, &coneSize);
1231:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1232:     switch (coneSize) {
1233:     case 3:
1234:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1235:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1236:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1237:       break;
1238:     case 4:
1239:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1240:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1241:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
1242:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1243:       break;
1244:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1245:     }
1246:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1247:   }
1248:   PetscDrawFlush(draw);
1249:   PetscDrawPause(draw);
1250:   PetscDrawSave(draw);
1251:   return(0);
1252: }

1254: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1255: {
1256:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1257:   char           name[PETSC_MAX_PATH_LEN];

1263:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
1264:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
1265:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
1266:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
1267:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
1268:   if (iascii) {
1269:     PetscViewerFormat format;
1270:     PetscViewerGetFormat(viewer, &format);
1271:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1272:       DMPlexView_GLVis(dm, viewer);
1273:     } else {
1274:       DMPlexView_Ascii(dm, viewer);
1275:     }
1276:   } else if (ishdf5) {
1277: #if defined(PETSC_HAVE_HDF5)
1278:     DMPlexView_HDF5_Internal(dm, viewer);
1279: #else
1280:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1281: #endif
1282:   } else if (isvtk) {
1283:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
1284:   } else if (isdraw) {
1285:     DMPlexView_Draw(dm, viewer);
1286:   } else if (isglvis) {
1287:     DMPlexView_GLVis(dm, viewer);
1288:   } else {
1289:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1290:   }
1291:   /* Optionally view the partition */
1292:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1293:   if (flg) {
1294:     Vec ranks;
1295:     DMPlexCreateRankField(dm, &ranks);
1296:     VecView(ranks, viewer);
1297:     VecDestroy(&ranks);
1298:   }
1299:   /* Optionally view a label */
1300:   PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, PETSC_MAX_PATH_LEN, &flg);
1301:   if (flg) {
1302:     DMLabel label;
1303:     Vec     val;

1305:     DMGetLabel(dm, name, &label);
1306:     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1307:     DMPlexCreateLabelField(dm, label, &val);
1308:     VecView(val, viewer);
1309:     VecDestroy(&val);
1310:   }
1311:   return(0);
1312: }

1314: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1315: {
1316:   PetscBool      ishdf5;

1322:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1323:   if (ishdf5) {
1324: #if defined(PETSC_HAVE_HDF5)
1325:     PetscViewerFormat format;
1326:     PetscViewerGetFormat(viewer, &format);
1327:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1328:       DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1329:     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1330:       DMPlexLoad_HDF5_Internal(dm, viewer);
1331:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1332: #else
1333:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1334: #endif
1335:   } else {
1336:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1337:   }
1338:   return(0);
1339: }

1341: PetscErrorCode DMDestroy_Plex(DM dm)
1342: {
1343:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1347:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1348:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1349:   PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);
1350:   if (--mesh->refct > 0) return(0);
1351:   PetscSectionDestroy(&mesh->coneSection);
1352:   PetscFree(mesh->cones);
1353:   PetscFree(mesh->coneOrientations);
1354:   PetscSectionDestroy(&mesh->supportSection);
1355:   PetscSectionDestroy(&mesh->subdomainSection);
1356:   PetscFree(mesh->supports);
1357:   PetscFree(mesh->facesTmp);
1358:   PetscFree(mesh->tetgenOpts);
1359:   PetscFree(mesh->triangleOpts);
1360:   PetscPartitionerDestroy(&mesh->partitioner);
1361:   DMLabelDestroy(&mesh->subpointMap);
1362:   ISDestroy(&mesh->globalVertexNumbers);
1363:   ISDestroy(&mesh->globalCellNumbers);
1364:   PetscSectionDestroy(&mesh->anchorSection);
1365:   ISDestroy(&mesh->anchorIS);
1366:   PetscSectionDestroy(&mesh->parentSection);
1367:   PetscFree(mesh->parents);
1368:   PetscFree(mesh->childIDs);
1369:   PetscSectionDestroy(&mesh->childSection);
1370:   PetscFree(mesh->children);
1371:   DMDestroy(&mesh->referenceTree);
1372:   PetscGridHashDestroy(&mesh->lbox);
1373:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1374:   PetscFree(mesh);
1375:   return(0);
1376: }

1378: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1379: {
1380:   PetscSection           sectionGlobal;
1381:   PetscInt               bs = -1, mbs;
1382:   PetscInt               localSize;
1383:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1384:   PetscErrorCode         ierr;
1385:   MatType                mtype;
1386:   ISLocalToGlobalMapping ltog;

1389:   MatInitializePackage();
1390:   mtype = dm->mattype;
1391:   DMGetGlobalSection(dm, &sectionGlobal);
1392:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1393:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1394:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1395:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1396:   MatSetType(*J, mtype);
1397:   MatSetFromOptions(*J);
1398:   MatGetBlockSize(*J, &mbs);
1399:   if (mbs > 1) bs = mbs;
1400:   PetscStrcmp(mtype, MATSHELL, &isShell);
1401:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1402:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1403:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1404:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1405:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1406:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1407:   PetscStrcmp(mtype, MATIS, &isMatIS);
1408:   if (!isShell) {
1409:     PetscSection subSection;
1410:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1411:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1412:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1419:       DMGetLocalSection(dm, &section);
1420:       PetscSectionGetStorageSize(section, &size);
1421:       PetscMalloc1(size,&ltogidx);
1422:       DMPlexGetSubdomainSection(dm, &subSection);
1423:     } else {
1424:       DMGetLocalToGlobalMapping(dm,&ltog);
1425:     }
1426:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1427:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1428:       PetscInt bdof;

1430:       PetscSectionGetDof(sectionGlobal, p, &dof);
1431:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1432:       dof  = dof < 0 ? -(dof+1) : dof;
1433:       bdof = cdof && (dof-cdof) ? 1 : dof;
1434:       if (dof) {
1435:         if (bs < 0)          {bs = bdof;}
1436:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1437:       }
1438:       if (isMatIS) {
1439:         PetscInt loff,c,off;
1440:         PetscSectionGetOffset(subSection, p, &loff);
1441:         PetscSectionGetOffset(sectionGlobal, p, &off);
1442:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1443:       }
1444:     }
1445:     /* Must have same blocksize on all procs (some might have no points) */
1446:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1447:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1448:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1449:     else                            {bs = bsMinMax[0];}
1450:     bs = PetscMax(1,bs);
1451:     if (isMatIS) { /* Must reduce indices by blocksize */
1452:       PetscInt l;

1454:       lsize = lsize/bs;
1455:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs;
1456:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1457:     }
1458:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1459:     if (isMatIS) {
1460:       ISLocalToGlobalMappingDestroy(&ltog);
1461:     }
1462:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1463:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1464:     PetscFree4(dnz, onz, dnzu, onzu);
1465:   }
1466:   MatSetDM(*J, dm);
1467:   return(0);
1468: }

1470: /*@
1471:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1473:   Not collective

1475:   Input Parameter:
1476: . mesh - The DMPlex

1478:   Output Parameters:
1479: . subsection - The subdomain section

1481:   Level: developer

1483: .seealso:
1484: @*/
1485: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1486: {
1487:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1492:   if (!mesh->subdomainSection) {
1493:     PetscSection section;
1494:     PetscSF      sf;

1496:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1497:     DMGetLocalSection(dm,&section);
1498:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1499:     PetscSFDestroy(&sf);
1500:   }
1501:   *subsection = mesh->subdomainSection;
1502:   return(0);
1503: }

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

1508:   Not collective

1510:   Input Parameter:
1511: . mesh - The DMPlex

1513:   Output Parameters:
1514: + pStart - The first mesh point
1515: - pEnd   - The upper bound for mesh points

1517:   Level: beginner

1519: .seealso: DMPlexCreate(), DMPlexSetChart()
1520: @*/
1521: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1522: {
1523:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1528:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1529:   return(0);
1530: }

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

1535:   Not collective

1537:   Input Parameters:
1538: + mesh - The DMPlex
1539: . pStart - The first mesh point
1540: - pEnd   - The upper bound for mesh points

1542:   Output Parameters:

1544:   Level: beginner

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

1555:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1556:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1557:   return(0);
1558: }

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

1563:   Not collective

1565:   Input Parameters:
1566: + mesh - The DMPlex
1567: - p - The point, which must lie in the chart set with DMPlexSetChart()

1569:   Output Parameter:
1570: . size - The cone size for point p

1572:   Level: beginner

1574: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1575: @*/
1576: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1577: {
1578:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1584:   PetscSectionGetDof(mesh->coneSection, p, size);
1585:   return(0);
1586: }

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

1591:   Not collective

1593:   Input Parameters:
1594: + mesh - The DMPlex
1595: . p - The point, which must lie in the chart set with DMPlexSetChart()
1596: - size - The cone size for point p

1598:   Output Parameter:

1600:   Note:
1601:   This should be called after DMPlexSetChart().

1603:   Level: beginner

1605: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1606: @*/
1607: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1608: {
1609:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1616:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1617:   return(0);
1618: }

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

1623:   Not collective

1625:   Input Parameters:
1626: + mesh - The DMPlex
1627: . p - The point, which must lie in the chart set with DMPlexSetChart()
1628: - size - The additional cone size for point p

1630:   Output Parameter:

1632:   Note:
1633:   This should be called after DMPlexSetChart().

1635:   Level: beginner

1637: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1638: @*/
1639: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1640: {
1641:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1642:   PetscInt       csize;

1647:   PetscSectionAddDof(mesh->coneSection, p, size);
1648:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1650:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1651:   return(0);
1652: }

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

1657:   Not collective

1659:   Input Parameters:
1660: + dm - The DMPlex
1661: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1666:   Level: beginner

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

1674: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1675: @*/
1676: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1677: {
1678:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1679:   PetscInt       off;

1685:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1686:   *cone = &mesh->cones[off];
1687:   return(0);
1688: }

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

1693:   Not collective

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

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

1703:   Level: intermediate

1705: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1706: @*/
1707: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1708: {
1709:   PetscSection        cs, newcs;
1710:   PetscInt            *cones;
1711:   PetscInt            *newarr=NULL;
1712:   PetscInt            n;
1713:   PetscErrorCode      ierr;

1716:   DMPlexGetCones(dm, &cones);
1717:   DMPlexGetConeSection(dm, &cs);
1718:   PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1719:   if (pConesSection) *pConesSection = newcs;
1720:   if (pCones) {
1721:     PetscSectionGetStorageSize(newcs, &n);
1722:     ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1723:   }
1724:   return(0);
1725: }

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

1730:   Not collective

1732:   Input Parameters:
1733: + dm - The DMPlex
1734: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()

1736:   Output Parameter:
1737: . expandedPoints - An array of vertices recursively expanded from input points

1739:   Level: advanced

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

1745: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth()
1746: @*/
1747: PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
1748: {
1749:   IS                  *expandedPointsAll;
1750:   PetscInt            depth;
1751:   PetscErrorCode      ierr;

1757:   DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);
1758:   *expandedPoints = expandedPointsAll[0];
1759:   PetscObjectReference((PetscObject)expandedPointsAll[0]);
1760:   DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);
1761:   return(0);
1762: }

1764: /*@
1765:   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).

1767:   Not collective

1769:   Input Parameters:
1770: + dm - The DMPlex
1771: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()

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

1778:   Level: advanced

1780:   Notes:
1781:   Like DMPlexGetConeTuple() but recursive.

1783:   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.
1784:   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.

1786:   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:
1787:   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
1788:   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].

1790: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
1791: @*/
1792: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
1793: {
1794:   const PetscInt      *arr0=NULL, *cone=NULL;
1795:   PetscInt            *arr=NULL, *newarr=NULL;
1796:   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
1797:   IS                  *expandedPoints_;
1798:   PetscSection        *sections_;
1799:   PetscErrorCode      ierr;

1807:   ISGetLocalSize(points, &n);
1808:   ISGetIndices(points, &arr0);
1809:   DMPlexGetDepth(dm, &depth_);
1810:   PetscCalloc1(depth_, &expandedPoints_);
1811:   PetscCalloc1(depth_, &sections_);
1812:   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
1813:   for (d=depth_-1; d>=0; d--) {
1814:     PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]);
1815:     PetscSectionSetChart(sections_[d], 0, n);
1816:     for (i=0; i<n; i++) {
1817:       DMPlexGetDepthStratum(dm, d+1, &start, &end);
1818:       if (arr[i] >= start && arr[i] < end) {
1819:         DMPlexGetConeSize(dm, arr[i], &cn);
1820:         PetscSectionSetDof(sections_[d], i, cn);
1821:       } else {
1822:         PetscSectionSetDof(sections_[d], i, 1);
1823:       }
1824:     }
1825:     PetscSectionSetUp(sections_[d]);
1826:     PetscSectionGetStorageSize(sections_[d], &newn);
1827:     PetscMalloc1(newn, &newarr);
1828:     for (i=0; i<n; i++) {
1829:       PetscSectionGetDof(sections_[d], i, &cn);
1830:       PetscSectionGetOffset(sections_[d], i, &co);
1831:       if (cn > 1) {
1832:         DMPlexGetCone(dm, arr[i], &cone);
1833:         PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));
1834:       } else {
1835:         newarr[co] = arr[i];
1836:       }
1837:     }
1838:     ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);
1839:     arr = newarr;
1840:     n = newn;
1841:   }
1842:   *depth = depth_;
1843:   if (expandedPoints) *expandedPoints = expandedPoints_;
1844:   else {
1845:     for (d=0; d<depth_; d++) {ISDestroy(&expandedPoints_[d]);}
1846:     PetscFree(expandedPoints_);
1847:   }
1848:   if (sections) *sections = sections_;
1849:   else {
1850:     for (d=0; d<depth_; d++) {PetscSectionDestroy(&sections_[d]);}
1851:     PetscFree(sections_);
1852:   }
1853:   return(0);
1854: }

1856: /*@
1857:   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive

1859:   Not collective

1861:   Input Parameters:
1862: + dm - The DMPlex
1863: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()

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

1870:   Level: advanced

1872:   Notes:
1873:   See DMPlexGetConeRecursive() for details.

1875: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
1876: @*/
1877: PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
1878: {
1879:   PetscInt            d, depth_;
1880:   PetscErrorCode      ierr;

1883:   DMPlexGetDepth(dm, &depth_);
1884:   if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
1885:   if (depth) *depth = 0;
1886:   if (expandedPoints) {
1887:     for (d=0; d<depth_; d++) {ISDestroy(&((*expandedPoints)[d]));}
1888:     PetscFree(*expandedPoints);
1889:   }
1890:   if (sections)  {
1891:     for (d=0; d<depth_; d++) {PetscSectionDestroy(&((*sections)[d]));}
1892:     PetscFree(*sections);
1893:   }
1894:   return(0);
1895: }

1897: /*@
1898:   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

1900:   Not collective

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

1907:   Output Parameter:

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

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

1914:   Level: beginner

1916: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1917: @*/
1918: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1919: {
1920:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1921:   PetscInt       pStart, pEnd;
1922:   PetscInt       dof, off, c;

1927:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1928:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1930:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1931:   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);
1932:   for (c = 0; c < dof; ++c) {
1933:     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);
1934:     mesh->cones[off+c] = cone[c];
1935:   }
1936:   return(0);
1937: }

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

1942:   Not collective

1944:   Input Parameters:
1945: + mesh - The DMPlex
1946: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1954:   Level: beginner

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

1962: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1963: @*/
1964: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1965: {
1966:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1967:   PetscInt       off;

1972: #if defined(PETSC_USE_DEBUG)
1973:   {
1974:     PetscInt dof;
1975:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1977:   }
1978: #endif
1979:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1981:   *coneOrientation = &mesh->coneOrientations[off];
1982:   return(0);
1983: }

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

1988:   Not collective

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

1998:   Output Parameter:

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

2003:   Level: beginner

2005: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2006: @*/
2007: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
2008: {
2009:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2010:   PetscInt       pStart, pEnd;
2011:   PetscInt       dof, off, c;

2016:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2017:   PetscSectionGetDof(mesh->coneSection, p, &dof);
2019:   PetscSectionGetOffset(mesh->coneSection, p, &off);
2020:   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);
2021:   for (c = 0; c < dof; ++c) {
2022:     PetscInt cdof, o = coneOrientation[c];

2024:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
2025:     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);
2026:     mesh->coneOrientations[off+c] = o;
2027:   }
2028:   return(0);
2029: }

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

2034:   Not collective

2036:   Input Parameters:
2037: + mesh - The DMPlex
2038: . p - The point, which must lie in the chart set with DMPlexSetChart()
2039: . conePos - The local index in the cone where the point should be put
2040: - conePoint - The mesh point to insert

2042:   Level: beginner

2044: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2045: @*/
2046: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
2047: {
2048:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2049:   PetscInt       pStart, pEnd;
2050:   PetscInt       dof, off;

2055:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2056:   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);
2057:   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);
2058:   PetscSectionGetDof(mesh->coneSection, p, &dof);
2059:   PetscSectionGetOffset(mesh->coneSection, p, &off);
2060:   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);
2061:   mesh->cones[off+conePos] = conePoint;
2062:   return(0);
2063: }

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

2068:   Not collective

2070:   Input Parameters:
2071: + mesh - The DMPlex
2072: . p - The point, which must lie in the chart set with DMPlexSetChart()
2073: . conePos - The local index in the cone where the point should be put
2074: - coneOrientation - The point orientation to insert

2076:   Level: beginner

2078: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2079: @*/
2080: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
2081: {
2082:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2083:   PetscInt       pStart, pEnd;
2084:   PetscInt       dof, off;

2089:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2090:   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);
2091:   PetscSectionGetDof(mesh->coneSection, p, &dof);
2092:   PetscSectionGetOffset(mesh->coneSection, p, &off);
2093:   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);
2094:   mesh->coneOrientations[off+conePos] = coneOrientation;
2095:   return(0);
2096: }

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

2101:   Not collective

2103:   Input Parameters:
2104: + mesh - The DMPlex
2105: - p - The point, which must lie in the chart set with DMPlexSetChart()

2107:   Output Parameter:
2108: . size - The support size for point p

2110:   Level: beginner

2112: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
2113: @*/
2114: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
2115: {
2116:   DM_Plex       *mesh = (DM_Plex*) dm->data;

2122:   PetscSectionGetDof(mesh->supportSection, p, size);
2123:   return(0);
2124: }

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

2129:   Not collective

2131:   Input Parameters:
2132: + mesh - The DMPlex
2133: . p - The point, which must lie in the chart set with DMPlexSetChart()
2134: - size - The support size for point p

2136:   Output Parameter:

2138:   Note:
2139:   This should be called after DMPlexSetChart().

2141:   Level: beginner

2143: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
2144: @*/
2145: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
2146: {
2147:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

2154:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
2155:   return(0);
2156: }

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

2161:   Not collective

2163:   Input Parameters:
2164: + mesh - The DMPlex
2165: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

2170:   Level: beginner

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

2178: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2179: @*/
2180: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
2181: {
2182:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2183:   PetscInt       off;

2189:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2190:   *support = &mesh->supports[off];
2191:   return(0);
2192: }

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

2197:   Not collective

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

2204:   Output Parameter:

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

2209:   Level: beginner

2211: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
2212: @*/
2213: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
2214: {
2215:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2216:   PetscInt       pStart, pEnd;
2217:   PetscInt       dof, off, c;

2222:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2223:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2225:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2226:   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);
2227:   for (c = 0; c < dof; ++c) {
2228:     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);
2229:     mesh->supports[off+c] = support[c];
2230:   }
2231:   return(0);
2232: }

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

2237:   Not collective

2239:   Input Parameters:
2240: + mesh - The DMPlex
2241: . p - The point, which must lie in the chart set with DMPlexSetChart()
2242: . supportPos - The local index in the cone where the point should be put
2243: - supportPoint - The mesh point to insert

2245:   Level: beginner

2247: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2248: @*/
2249: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
2250: {
2251:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2252:   PetscInt       pStart, pEnd;
2253:   PetscInt       dof, off;

2258:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2259:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2260:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2261:   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);
2262:   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);
2263:   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);
2264:   mesh->supports[off+supportPos] = supportPoint;
2265:   return(0);
2266: }

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

2271:   Not collective

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

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

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

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

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

2292:   Level: beginner

2294: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2295: @*/
2296: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2297: {
2298:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2299:   PetscInt       *closure, *fifo;
2300:   const PetscInt *tmp = NULL, *tmpO = NULL;
2301:   PetscInt        tmpSize, t;
2302:   PetscInt        depth       = 0, maxSize;
2303:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2304:   PetscErrorCode  ierr;

2308:   DMPlexGetDepth(dm, &depth);
2309:   /* This is only 1-level */
2310:   if (useCone) {
2311:     DMPlexGetConeSize(dm, p, &tmpSize);
2312:     DMPlexGetCone(dm, p, &tmp);
2313:     DMPlexGetConeOrientation(dm, p, &tmpO);
2314:   } else {
2315:     DMPlexGetSupportSize(dm, p, &tmpSize);
2316:     DMPlexGetSupport(dm, p, &tmp);
2317:   }
2318:   if (depth == 1) {
2319:     if (*points) {
2320:       closure = *points;
2321:     } else {
2322:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2323:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2324:     }
2325:     closure[0] = p; closure[1] = 0;
2326:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2327:       closure[closureSize]   = tmp[t];
2328:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2329:     }
2330:     if (numPoints) *numPoints = closureSize/2;
2331:     if (points)    *points    = closure;
2332:     return(0);
2333:   }
2334:   {
2335:     PetscInt c, coneSeries, s,supportSeries;

2337:     c = mesh->maxConeSize;
2338:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2339:     s = mesh->maxSupportSize;
2340:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2341:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2342:   }
2343:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2344:   if (*points) {
2345:     closure = *points;
2346:   } else {
2347:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2348:   }
2349:   closure[0] = p; closure[1] = 0;
2350:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2351:     const PetscInt cp = tmp[t];
2352:     const PetscInt co = tmpO ? tmpO[t] : 0;

2354:     closure[closureSize]   = cp;
2355:     closure[closureSize+1] = co;
2356:     fifo[fifoSize]         = cp;
2357:     fifo[fifoSize+1]       = co;
2358:   }
2359:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2360:   while (fifoSize - fifoStart) {
2361:     const PetscInt q   = fifo[fifoStart];
2362:     const PetscInt o   = fifo[fifoStart+1];
2363:     const PetscInt rev = o >= 0 ? 0 : 1;
2364:     const PetscInt off = rev ? -(o+1) : o;

2366:     if (useCone) {
2367:       DMPlexGetConeSize(dm, q, &tmpSize);
2368:       DMPlexGetCone(dm, q, &tmp);
2369:       DMPlexGetConeOrientation(dm, q, &tmpO);
2370:     } else {
2371:       DMPlexGetSupportSize(dm, q, &tmpSize);
2372:       DMPlexGetSupport(dm, q, &tmp);
2373:       tmpO = NULL;
2374:     }
2375:     for (t = 0; t < tmpSize; ++t) {
2376:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2377:       const PetscInt cp = tmp[i];
2378:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2379:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2380:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2381:       PetscInt       co = tmpO ? tmpO[i] : 0;
2382:       PetscInt       c;

2384:       if (rev) {
2385:         PetscInt childSize, coff;
2386:         DMPlexGetConeSize(dm, cp, &childSize);
2387:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2388:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2389:       }
2390:       /* Check for duplicate */
2391:       for (c = 0; c < closureSize; c += 2) {
2392:         if (closure[c] == cp) break;
2393:       }
2394:       if (c == closureSize) {
2395:         closure[closureSize]   = cp;
2396:         closure[closureSize+1] = co;
2397:         fifo[fifoSize]         = cp;
2398:         fifo[fifoSize+1]       = co;
2399:         closureSize           += 2;
2400:         fifoSize              += 2;
2401:       }
2402:     }
2403:     fifoStart += 2;
2404:   }
2405:   if (numPoints) *numPoints = closureSize/2;
2406:   if (points)    *points    = closure;
2407:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2408:   return(0);
2409: }

2411: /*@C
2412:   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

2414:   Not collective

2416:   Input Parameters:
2417: + mesh - The DMPlex
2418: . p - The point, which must lie in the chart set with DMPlexSetChart()
2419: . orientation - The orientation of the point
2420: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2421: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

2436:   Level: beginner

2438: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2439: @*/
2440: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2441: {
2442:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2443:   PetscInt       *closure, *fifo;
2444:   const PetscInt *tmp = NULL, *tmpO = NULL;
2445:   PetscInt        tmpSize, t;
2446:   PetscInt        depth       = 0, maxSize;
2447:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2448:   PetscErrorCode  ierr;

2452:   DMPlexGetDepth(dm, &depth);
2453:   /* This is only 1-level */
2454:   if (useCone) {
2455:     DMPlexGetConeSize(dm, p, &tmpSize);
2456:     DMPlexGetCone(dm, p, &tmp);
2457:     DMPlexGetConeOrientation(dm, p, &tmpO);
2458:   } else {
2459:     DMPlexGetSupportSize(dm, p, &tmpSize);
2460:     DMPlexGetSupport(dm, p, &tmp);
2461:   }
2462:   if (depth == 1) {
2463:     if (*points) {
2464:       closure = *points;
2465:     } else {
2466:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2467:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2468:     }
2469:     closure[0] = p; closure[1] = ornt;
2470:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2471:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2472:       closure[closureSize]   = tmp[i];
2473:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2474:     }
2475:     if (numPoints) *numPoints = closureSize/2;
2476:     if (points)    *points    = closure;
2477:     return(0);
2478:   }
2479:   {
2480:     PetscInt c, coneSeries, s,supportSeries;

2482:     c = mesh->maxConeSize;
2483:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2484:     s = mesh->maxSupportSize;
2485:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2486:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2487:   }
2488:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2489:   if (*points) {
2490:     closure = *points;
2491:   } else {
2492:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2493:   }
2494:   closure[0] = p; closure[1] = ornt;
2495:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2496:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2497:     const PetscInt cp = tmp[i];
2498:     PetscInt       co = tmpO ? tmpO[i] : 0;

2500:     if (ornt < 0) {
2501:       PetscInt childSize, coff;
2502:       DMPlexGetConeSize(dm, cp, &childSize);
2503:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2504:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2505:     }
2506:     closure[closureSize]   = cp;
2507:     closure[closureSize+1] = co;
2508:     fifo[fifoSize]         = cp;
2509:     fifo[fifoSize+1]       = co;
2510:   }
2511:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2512:   while (fifoSize - fifoStart) {
2513:     const PetscInt q   = fifo[fifoStart];
2514:     const PetscInt o   = fifo[fifoStart+1];
2515:     const PetscInt rev = o >= 0 ? 0 : 1;
2516:     const PetscInt off = rev ? -(o+1) : o;

2518:     if (useCone) {
2519:       DMPlexGetConeSize(dm, q, &tmpSize);
2520:       DMPlexGetCone(dm, q, &tmp);
2521:       DMPlexGetConeOrientation(dm, q, &tmpO);
2522:     } else {
2523:       DMPlexGetSupportSize(dm, q, &tmpSize);
2524:       DMPlexGetSupport(dm, q, &tmp);
2525:       tmpO = NULL;
2526:     }
2527:     for (t = 0; t < tmpSize; ++t) {
2528:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2529:       const PetscInt cp = tmp[i];
2530:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2531:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2532:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2533:       PetscInt       co = tmpO ? tmpO[i] : 0;
2534:       PetscInt       c;

2536:       if (rev) {
2537:         PetscInt childSize, coff;
2538:         DMPlexGetConeSize(dm, cp, &childSize);
2539:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2540:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2541:       }
2542:       /* Check for duplicate */
2543:       for (c = 0; c < closureSize; c += 2) {
2544:         if (closure[c] == cp) break;
2545:       }
2546:       if (c == closureSize) {
2547:         closure[closureSize]   = cp;
2548:         closure[closureSize+1] = co;
2549:         fifo[fifoSize]         = cp;
2550:         fifo[fifoSize+1]       = co;
2551:         closureSize           += 2;
2552:         fifoSize              += 2;
2553:       }
2554:     }
2555:     fifoStart += 2;
2556:   }
2557:   if (numPoints) *numPoints = closureSize/2;
2558:   if (points)    *points    = closure;
2559:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2560:   return(0);
2561: }

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

2566:   Not collective

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

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

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

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

2584:   Level: beginner

2586: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2587: @*/
2588: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2589: {

2596:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2597:   if (numPoints) *numPoints = 0;
2598:   return(0);
2599: }

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

2604:   Not collective

2606:   Input Parameter:
2607: . mesh - The DMPlex

2609:   Output Parameters:
2610: + maxConeSize - The maximum number of in-edges
2611: - maxSupportSize - The maximum number of out-edges

2613:   Level: beginner

2615: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2616: @*/
2617: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2618: {
2619:   DM_Plex *mesh = (DM_Plex*) dm->data;

2623:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2624:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2625:   return(0);
2626: }

2628: PetscErrorCode DMSetUp_Plex(DM dm)
2629: {
2630:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2631:   PetscInt       size;

2636:   PetscSectionSetUp(mesh->coneSection);
2637:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2638:   PetscMalloc1(size, &mesh->cones);
2639:   PetscCalloc1(size, &mesh->coneOrientations);
2640:   if (mesh->maxSupportSize) {
2641:     PetscSectionSetUp(mesh->supportSection);
2642:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2643:     PetscMalloc1(size, &mesh->supports);
2644:   }
2645:   return(0);
2646: }

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

2653:   if (subdm) {DMClone(dm, subdm);}
2654:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2655:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2656:   if (dm->useNatural && dm->sfMigration) {
2657:     PetscSF        sfMigrationInv,sfNatural;
2658:     PetscSection   section, sectionSeq;

2660:     (*subdm)->sfMigration = dm->sfMigration;
2661:     PetscObjectReference((PetscObject) dm->sfMigration);
2662:     DMGetLocalSection((*subdm), &section);
2663:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2664:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2665:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2667:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2668:     (*subdm)->sfNatural = sfNatural;
2669:     PetscSectionDestroy(&sectionSeq);
2670:     PetscSFDestroy(&sfMigrationInv);
2671:   }
2672:   return(0);
2673: }

2675: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2676: {
2678:   PetscInt       i = 0;

2681:   DMClone(dms[0], superdm);
2682:   DMCreateSectionSuperDM(dms, len, is, superdm);
2683:   (*superdm)->useNatural = PETSC_FALSE;
2684:   for (i = 0; i < len; i++){
2685:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2686:       PetscSF        sfMigrationInv,sfNatural;
2687:       PetscSection   section, sectionSeq;

2689:       (*superdm)->sfMigration = dms[i]->sfMigration;
2690:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2691:       (*superdm)->useNatural = PETSC_TRUE;
2692:       DMGetLocalSection((*superdm), &section);
2693:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2694:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2695:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2697:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2698:       (*superdm)->sfNatural = sfNatural;
2699:       PetscSectionDestroy(&sectionSeq);
2700:       PetscSFDestroy(&sfMigrationInv);
2701:       break;
2702:     }
2703:   }
2704:   return(0);
2705: }

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

2710:   Not collective

2712:   Input Parameter:
2713: . mesh - The DMPlex

2715:   Output Parameter:

2717:   Note:
2718:   This should be called after all calls to DMPlexSetCone()

2720:   Level: beginner

2722: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2723: @*/
2724: PetscErrorCode DMPlexSymmetrize(DM dm)
2725: {
2726:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2727:   PetscInt      *offsets;
2728:   PetscInt       supportSize;
2729:   PetscInt       pStart, pEnd, p;

2734:   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2735:   PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);
2736:   /* Calculate support sizes */
2737:   DMPlexGetChart(dm, &pStart, &pEnd);
2738:   for (p = pStart; p < pEnd; ++p) {
2739:     PetscInt dof, off, c;

2741:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2742:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2743:     for (c = off; c < off+dof; ++c) {
2744:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2745:     }
2746:   }
2747:   for (p = pStart; p < pEnd; ++p) {
2748:     PetscInt dof;

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

2752:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2753:   }
2754:   PetscSectionSetUp(mesh->supportSection);
2755:   /* Calculate supports */
2756:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2757:   PetscMalloc1(supportSize, &mesh->supports);
2758:   PetscCalloc1(pEnd - pStart, &offsets);
2759:   for (p = pStart; p < pEnd; ++p) {
2760:     PetscInt dof, off, c;

2762:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2763:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2764:     for (c = off; c < off+dof; ++c) {
2765:       const PetscInt q = mesh->cones[c];
2766:       PetscInt       offS;

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

2770:       mesh->supports[offS+offsets[q]] = p;
2771:       ++offsets[q];
2772:     }
2773:   }
2774:   PetscFree(offsets);
2775:   PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);
2776:   return(0);
2777: }

2779: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
2780: {
2781:   IS             stratumIS;

2785:   if (pStart >= pEnd) return(0);
2786: #if defined(PETSC_USE_DEBUG)
2787:   {
2788:     PetscInt  qStart, qEnd, numLevels, level;
2789:     PetscBool overlap = PETSC_FALSE;
2790:     DMLabelGetNumValues(label, &numLevels);
2791:     for (level = 0; level < numLevels; level++) {
2792:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2793:       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
2794:     }
2795:     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);
2796:   }
2797: #endif
2798:   ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);
2799:   DMLabelSetStratumIS(label, depth, stratumIS);
2800:   ISDestroy(&stratumIS);
2801:   return(0);
2802: }

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

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

2812:   Collective on dm

2814:   Input Parameter:
2815: . mesh - The DMPlex

2817:   Output Parameter:

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

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

2827:   Level: beginner

2829: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2830: @*/
2831: PetscErrorCode DMPlexStratify(DM dm)
2832: {
2833:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2834:   DMLabel        label;
2835:   PetscInt       pStart, pEnd, p;
2836:   PetscInt       numRoots = 0, numLeaves = 0;
2837:   PetscInt       cMax, fMax, eMax, vMax;

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

2844:   /* Create depth label */
2845:   DMPlexGetChart(dm, &pStart, &pEnd);
2846:   DMCreateLabel(dm, "depth");
2847:   DMPlexGetDepthLabel(dm, &label);

2849:   {
2850:     /* Initialize roots and count leaves */
2851:     PetscInt sMin = PETSC_MAX_INT;
2852:     PetscInt sMax = PETSC_MIN_INT;
2853:     PetscInt coneSize, supportSize;

2855:     for (p = pStart; p < pEnd; ++p) {
2856:       DMPlexGetConeSize(dm, p, &coneSize);
2857:       DMPlexGetSupportSize(dm, p, &supportSize);
2858:       if (!coneSize && supportSize) {
2859:         sMin = PetscMin(p, sMin);
2860:         sMax = PetscMax(p, sMax);
2861:         ++numRoots;
2862:       } else if (!supportSize && coneSize) {
2863:         ++numLeaves;
2864:       } else if (!supportSize && !coneSize) {
2865:         /* Isolated points */
2866:         sMin = PetscMin(p, sMin);
2867:         sMax = PetscMax(p, sMax);
2868:       }
2869:     }
2870:     DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);
2871:   }

2873:   if (numRoots + numLeaves == (pEnd - pStart)) {
2874:     PetscInt sMin = PETSC_MAX_INT;
2875:     PetscInt sMax = PETSC_MIN_INT;
2876:     PetscInt coneSize, supportSize;

2878:     for (p = pStart; p < pEnd; ++p) {
2879:       DMPlexGetConeSize(dm, p, &coneSize);
2880:       DMPlexGetSupportSize(dm, p, &supportSize);
2881:       if (!supportSize && coneSize) {
2882:         sMin = PetscMin(p, sMin);
2883:         sMax = PetscMax(p, sMax);
2884:       }
2885:     }
2886:     DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);
2887:   } else {
2888:     PetscInt level = 0;
2889:     PetscInt qStart, qEnd, q;

2891:     DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2892:     while (qEnd > qStart) {
2893:       PetscInt sMin = PETSC_MAX_INT;
2894:       PetscInt sMax = PETSC_MIN_INT;

2896:       for (q = qStart; q < qEnd; ++q) {
2897:         const PetscInt *support;
2898:         PetscInt        supportSize, s;

2900:         DMPlexGetSupportSize(dm, q, &supportSize);
2901:         DMPlexGetSupport(dm, q, &support);
2902:         for (s = 0; s < supportSize; ++s) {
2903:           sMin = PetscMin(support[s], sMin);
2904:           sMax = PetscMax(support[s], sMax);
2905:         }
2906:       }
2907:       DMLabelGetNumValues(label, &level);
2908:       DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);
2909:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2910:     }
2911:   }
2912:   { /* just in case there is an empty process */
2913:     PetscInt numValues, maxValues = 0, v;

2915:     DMLabelGetNumValues(label, &numValues);
2916:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2917:     for (v = numValues; v < maxValues; v++) {
2918:       DMLabelAddStratum(label, v);
2919:     }
2920:   }
2921:   PetscObjectStateGet((PetscObject) label, &mesh->depthState);

2923:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2924:   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2925:     PetscInt dim;
2926:     DMLabel  dimLabel;

2928:     DMGetDimension(dm, &dim);
2929:     DMCreateLabel(dm, "dim");
2930:     DMGetLabel(dm, "dim", &dimLabel);
2931:     if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2932:     if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2933:     if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2934:     if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2935:   }
2936:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2937:   return(0);
2938: }

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

2943:   Not Collective

2945:   Input Parameters:
2946: + dm - The DMPlex object
2947: . numPoints - The number of input points for the join
2948: - points - The input points

2950:   Output Parameters:
2951: + numCoveredPoints - The number of points in the join
2952: - coveredPoints - The points in the join

2954:   Level: intermediate

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

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

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

2964: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2965: @*/
2966: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2967: {
2968:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2969:   PetscInt      *join[2];
2970:   PetscInt       joinSize, i = 0;
2971:   PetscInt       dof, off, p, c, m;

2979:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2980:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2981:   /* Copy in support of first point */
2982:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2983:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2984:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2985:     join[i][joinSize] = mesh->supports[off+joinSize];
2986:   }
2987:   /* Check each successive support */
2988:   for (p = 1; p < numPoints; ++p) {
2989:     PetscInt newJoinSize = 0;

2991:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2992:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2993:     for (c = 0; c < dof; ++c) {
2994:       const PetscInt point = mesh->supports[off+c];

2996:       for (m = 0; m < joinSize; ++m) {
2997:         if (point == join[i][m]) {
2998:           join[1-i][newJoinSize++] = point;
2999:           break;
3000:         }
3001:       }
3002:     }
3003:     joinSize = newJoinSize;
3004:     i        = 1-i;
3005:   }
3006:   *numCoveredPoints = joinSize;
3007:   *coveredPoints    = join[i];
3008:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3009:   return(0);
3010: }

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

3015:   Not Collective

3017:   Input Parameters:
3018: + dm - The DMPlex object
3019: . numPoints - The number of input points for the join
3020: - points - The input points

3022:   Output Parameters:
3023: + numCoveredPoints - The number of points in the join
3024: - coveredPoints - The points in the join

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

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

3032:   Level: intermediate

3034: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
3035: @*/
3036: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3037: {

3045:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3046:   if (numCoveredPoints) *numCoveredPoints = 0;
3047:   return(0);
3048: }

3050: /*@C
3051:   DMPlexGetFullJoin - Get 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(), DMPlexRestoreJoin(), DMPlexGetMeet()
3073: @*/
3074: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3075: {
3076:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3077:   PetscInt      *offsets, **closures;
3078:   PetscInt      *join[2];
3079:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
3080:   PetscInt       p, d, c, m, ms;


3089:   DMPlexGetDepth(dm, &depth);
3090:   PetscCalloc1(numPoints, &closures);
3091:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3092:   ms      = mesh->maxSupportSize;
3093:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
3094:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
3095:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

3097:   for (p = 0; p < numPoints; ++p) {
3098:     PetscInt closureSize;

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

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

3106:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
3107:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
3108:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3109:           offsets[p*(depth+2)+d+1] = i;
3110:           break;
3111:         }
3112:       }
3113:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
3114:     }
3115:     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);
3116:   }
3117:   for (d = 0; d < depth+1; ++d) {
3118:     PetscInt dof;

3120:     /* Copy in support of first point */
3121:     dof = offsets[d+1] - offsets[d];
3122:     for (joinSize = 0; joinSize < dof; ++joinSize) {
3123:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
3124:     }
3125:     /* Check each successive cone */
3126:     for (p = 1; p < numPoints && joinSize; ++p) {
3127:       PetscInt newJoinSize = 0;

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

3133:         for (m = 0; m < joinSize; ++m) {
3134:           if (point == join[i][m]) {
3135:             join[1-i][newJoinSize++] = point;
3136:             break;
3137:           }
3138:         }
3139:       }
3140:       joinSize = newJoinSize;
3141:       i        = 1-i;
3142:     }
3143:     if (joinSize) break;
3144:   }
3145:   *numCoveredPoints = joinSize;
3146:   *coveredPoints    = join[i];
3147:   for (p = 0; p < numPoints; ++p) {
3148:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
3149:   }
3150:   PetscFree(closures);
3151:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3152:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3153:   return(0);
3154: }

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

3159:   Not Collective

3161:   Input Parameters:
3162: + dm - The DMPlex object
3163: . numPoints - The number of input points for the meet
3164: - points - The input points

3166:   Output Parameters:
3167: + numCoveredPoints - The number of points in the meet
3168: - coveredPoints - The points in the meet

3170:   Level: intermediate

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

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

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

3180: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
3181: @*/
3182: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
3183: {
3184:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3185:   PetscInt      *meet[2];
3186:   PetscInt       meetSize, i = 0;
3187:   PetscInt       dof, off, p, c, m;

3195:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
3196:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
3197:   /* Copy in cone of first point */
3198:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
3199:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
3200:   for (meetSize = 0; meetSize < dof; ++meetSize) {
3201:     meet[i][meetSize] = mesh->cones[off+meetSize];
3202:   }
3203:   /* Check each successive cone */
3204:   for (p = 1; p < numPoints; ++p) {
3205:     PetscInt newMeetSize = 0;

3207:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
3208:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
3209:     for (c = 0; c < dof; ++c) {
3210:       const PetscInt point = mesh->cones[off+c];

3212:       for (m = 0; m < meetSize; ++m) {
3213:         if (point == meet[i][m]) {
3214:           meet[1-i][newMeetSize++] = point;
3215:           break;
3216:         }
3217:       }
3218:     }
3219:     meetSize = newMeetSize;
3220:     i        = 1-i;
3221:   }
3222:   *numCoveringPoints = meetSize;
3223:   *coveringPoints    = meet[i];
3224:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3225:   return(0);
3226: }

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

3231:   Not Collective

3233:   Input Parameters:
3234: + dm - The DMPlex object
3235: . numPoints - The number of input points for the meet
3236: - points - The input points

3238:   Output Parameters:
3239: + numCoveredPoints - The number of points in the meet
3240: - coveredPoints - The points in the meet

3242:   Level: intermediate

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

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

3250: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
3251: @*/
3252: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3253: {

3261:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3262:   if (numCoveredPoints) *numCoveredPoints = 0;
3263:   return(0);
3264: }

3266: /*@C
3267:   DMPlexGetFullMeet - Get 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(), DMPlexRestoreMeet(), DMPlexGetJoin()
3289: @*/
3290: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3291: {
3292:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3293:   PetscInt      *offsets, **closures;
3294:   PetscInt      *meet[2];
3295:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
3296:   PetscInt       p, h, c, m, mc;


3305:   DMPlexGetDepth(dm, &height);
3306:   PetscMalloc1(numPoints, &closures);
3307:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3308:   mc      = mesh->maxConeSize;
3309:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3310:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3311:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

3313:   for (p = 0; p < numPoints; ++p) {
3314:     PetscInt closureSize;

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

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

3322:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3323:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3324:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3325:           offsets[p*(height+2)+h+1] = i;
3326:           break;
3327:         }
3328:       }
3329:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3330:     }
3331:     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);
3332:   }
3333:   for (h = 0; h < height+1; ++h) {
3334:     PetscInt dof;

3336:     /* Copy in cone of first point */
3337:     dof = offsets[h+1] - offsets[h];
3338:     for (meetSize = 0; meetSize < dof; ++meetSize) {
3339:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3340:     }
3341:     /* Check each successive cone */
3342:     for (p = 1; p < numPoints && meetSize; ++p) {
3343:       PetscInt newMeetSize = 0;

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

3349:         for (m = 0; m < meetSize; ++m) {
3350:           if (point == meet[i][m]) {
3351:             meet[1-i][newMeetSize++] = point;
3352:             break;
3353:           }
3354:         }
3355:       }
3356:       meetSize = newMeetSize;
3357:       i        = 1-i;
3358:     }
3359:     if (meetSize) break;
3360:   }
3361:   *numCoveredPoints = meetSize;
3362:   *coveredPoints    = meet[i];
3363:   for (p = 0; p < numPoints; ++p) {
3364:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3365:   }
3366:   PetscFree(closures);
3367:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3368:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3369:   return(0);
3370: }

3372: /*@C
3373:   DMPlexEqual - Determine if two DMs have the same topology

3375:   Not Collective

3377:   Input Parameters:
3378: + dmA - A DMPlex object
3379: - dmB - A DMPlex object

3381:   Output Parameters:
3382: . equal - PETSC_TRUE if the topologies are identical

3384:   Level: intermediate

3386:   Notes:
3387:   We are not solving graph isomorphism, so we do not permutation.

3389: .seealso: DMPlexGetCone()
3390: @*/
3391: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3392: {
3393:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


3401:   *equal = PETSC_FALSE;
3402:   DMPlexGetDepth(dmA, &depth);
3403:   DMPlexGetDepth(dmB, &depthB);
3404:   if (depth != depthB) return(0);
3405:   DMPlexGetChart(dmA, &pStart,  &pEnd);
3406:   DMPlexGetChart(dmB, &pStartB, &pEndB);
3407:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3408:   for (p = pStart; p < pEnd; ++p) {
3409:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3410:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

3412:     DMPlexGetConeSize(dmA, p, &coneSize);
3413:     DMPlexGetCone(dmA, p, &cone);
3414:     DMPlexGetConeOrientation(dmA, p, &ornt);
3415:     DMPlexGetConeSize(dmB, p, &coneSizeB);
3416:     DMPlexGetCone(dmB, p, &coneB);
3417:     DMPlexGetConeOrientation(dmB, p, &orntB);
3418:     if (coneSize != coneSizeB) return(0);
3419:     for (c = 0; c < coneSize; ++c) {
3420:       if (cone[c] != coneB[c]) return(0);
3421:       if (ornt[c] != orntB[c]) return(0);
3422:     }
3423:     DMPlexGetSupportSize(dmA, p, &supportSize);
3424:     DMPlexGetSupport(dmA, p, &support);
3425:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
3426:     DMPlexGetSupport(dmB, p, &supportB);
3427:     if (supportSize != supportSizeB) return(0);
3428:     for (s = 0; s < supportSize; ++s) {
3429:       if (support[s] != supportB[s]) return(0);
3430:     }
3431:   }
3432:   *equal = PETSC_TRUE;
3433:   return(0);
3434: }

3436: /*@C
3437:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

3439:   Not Collective

3441:   Input Parameters:
3442: + dm         - The DMPlex
3443: . cellDim    - The cell dimension
3444: - numCorners - The number of vertices on a cell

3446:   Output Parameters:
3447: . numFaceVertices - The number of vertices on a face

3449:   Level: developer

3451:   Notes:
3452:   Of course this can only work for a restricted set of symmetric shapes

3454: .seealso: DMPlexGetCone()
3455: @*/
3456: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3457: {
3458:   MPI_Comm       comm;

3462:   PetscObjectGetComm((PetscObject)dm,&comm);
3464:   switch (cellDim) {
3465:   case 0:
3466:     *numFaceVertices = 0;
3467:     break;
3468:   case 1:
3469:     *numFaceVertices = 1;
3470:     break;
3471:   case 2:
3472:     switch (numCorners) {
3473:     case 3: /* triangle */
3474:       *numFaceVertices = 2; /* Edge has 2 vertices */
3475:       break;
3476:     case 4: /* quadrilateral */
3477:       *numFaceVertices = 2; /* Edge has 2 vertices */
3478:       break;
3479:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3480:       *numFaceVertices = 3; /* Edge has 3 vertices */
3481:       break;
3482:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3483:       *numFaceVertices = 3; /* Edge has 3 vertices */
3484:       break;
3485:     default:
3486:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3487:     }
3488:     break;
3489:   case 3:
3490:     switch (numCorners) {
3491:     case 4: /* tetradehdron */
3492:       *numFaceVertices = 3; /* Face has 3 vertices */
3493:       break;
3494:     case 6: /* tet cohesive cells */
3495:       *numFaceVertices = 4; /* Face has 4 vertices */
3496:       break;
3497:     case 8: /* hexahedron */
3498:       *numFaceVertices = 4; /* Face has 4 vertices */
3499:       break;
3500:     case 9: /* tet cohesive Lagrange cells */
3501:       *numFaceVertices = 6; /* Face has 6 vertices */
3502:       break;
3503:     case 10: /* quadratic tetrahedron */
3504:       *numFaceVertices = 6; /* Face has 6 vertices */
3505:       break;
3506:     case 12: /* hex cohesive Lagrange cells */
3507:       *numFaceVertices = 6; /* Face has 6 vertices */
3508:       break;
3509:     case 18: /* quadratic tet cohesive Lagrange cells */
3510:       *numFaceVertices = 6; /* Face has 6 vertices */
3511:       break;
3512:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3513:       *numFaceVertices = 9; /* Face has 9 vertices */
3514:       break;
3515:     default:
3516:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3517:     }
3518:     break;
3519:   default:
3520:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3521:   }
3522:   return(0);
3523: }

3525: /*@
3526:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3528:   Not Collective

3530:   Input Parameter:
3531: . dm    - The DMPlex object

3533:   Output Parameter:
3534: . depthLabel - The DMLabel recording point depth

3536:   Level: developer

3538: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3539: @*/
3540: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3541: {
3545:   *depthLabel = dm->depthLabel;
3546:   return(0);
3547: }

3549: /*@
3550:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3552:   Not Collective

3554:   Input Parameter:
3555: . dm    - The DMPlex object

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

3560:   Level: developer

3562: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3563: @*/
3564: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3565: {
3566:   DMLabel        label;
3567:   PetscInt       d = 0;

3573:   DMPlexGetDepthLabel(dm, &label);
3574:   if (label) {DMLabelGetNumValues(label, &d);}
3575:   *depth = d-1;
3576:   return(0);
3577: }

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

3582:   Not Collective

3584:   Input Parameters:
3585: + dm           - The DMPlex object
3586: - stratumValue - The requested depth

3588:   Output Parameters:
3589: + start - The first point at this depth
3590: - end   - One beyond the last point at this depth

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

3597:   Level: developer

3599: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3600: @*/
3601: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3602: {
3603:   DMLabel        label;
3604:   PetscInt       pStart, pEnd;

3611:   DMPlexGetChart(dm, &pStart, &pEnd);
3612:   if (pStart == pEnd) return(0);
3613:   if (stratumValue < 0) {
3614:     if (start) *start = pStart;
3615:     if (end)   *end   = pEnd;
3616:     return(0);
3617:   }
3618:   DMPlexGetDepthLabel(dm, &label);
3619:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3620:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3621:   return(0);
3622: }

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

3627:   Not Collective

3629:   Input Parameters:
3630: + dm           - The DMPlex object
3631: - stratumValue - The requested height

3633:   Output Parameters:
3634: + start - The first point at this height
3635: - end   - One beyond the last point at this height

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

3642:   Level: developer

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

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

3670: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3671: {
3672:   PetscSection   section, s;
3673:   Mat            m;
3674:   PetscInt       maxHeight;

3678:   DMClone(dm, cdm);
3679:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3680:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3681:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3682:   DMSetLocalSection(*cdm, section);
3683:   PetscSectionDestroy(&section);
3684:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3685:   MatCreate(PETSC_COMM_SELF, &m);
3686:   DMSetDefaultConstraints(*cdm, s, m);
3687:   PetscSectionDestroy(&s);
3688:   MatDestroy(&m);

3690:   DMSetNumFields(*cdm, 1);
3691:   DMCreateDS(*cdm);
3692:   return(0);
3693: }

3695: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3696: {
3697:   Vec            coordsLocal;
3698:   DM             coordsDM;

3702:   *field = NULL;
3703:   DMGetCoordinatesLocal(dm,&coordsLocal);
3704:   DMGetCoordinateDM(dm,&coordsDM);
3705:   if (coordsLocal && coordsDM) {
3706:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3707:   }
3708:   return(0);
3709: }

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

3714:   Not Collective

3716:   Input Parameters:
3717: . dm        - The DMPlex object

3719:   Output Parameter:
3720: . section - The PetscSection object

3722:   Level: developer

3724: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3725: @*/
3726: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3727: {
3728:   DM_Plex *mesh = (DM_Plex*) dm->data;

3732:   if (section) *section = mesh->coneSection;
3733:   return(0);
3734: }

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

3739:   Not Collective

3741:   Input Parameters:
3742: . dm        - The DMPlex object

3744:   Output Parameter:
3745: . section - The PetscSection object

3747:   Level: developer

3749: .seealso: DMPlexGetConeSection()
3750: @*/
3751: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3752: {
3753:   DM_Plex *mesh = (DM_Plex*) dm->data;

3757:   if (section) *section = mesh->supportSection;
3758:   return(0);
3759: }

3761: /*@C
3762:   DMPlexGetCones - Return cone data

3764:   Not Collective

3766:   Input Parameters:
3767: . dm        - The DMPlex object

3769:   Output Parameter:
3770: . cones - The cone for each point

3772:   Level: developer

3774: .seealso: DMPlexGetConeSection()
3775: @*/
3776: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3777: {
3778:   DM_Plex *mesh = (DM_Plex*) dm->data;

3782:   if (cones) *cones = mesh->cones;
3783:   return(0);
3784: }

3786: /*@C
3787:   DMPlexGetConeOrientations - Return cone orientation data

3789:   Not Collective

3791:   Input Parameters:
3792: . dm        - The DMPlex object

3794:   Output Parameter:
3795: . coneOrientations - The cone orientation for each point

3797:   Level: developer

3799: .seealso: DMPlexGetConeSection()
3800: @*/
3801: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3802: {
3803:   DM_Plex *mesh = (DM_Plex*) dm->data;

3807:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3808:   return(0);
3809: }

3811: /******************************** FEM Support **********************************/

3813: /*
3814:  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
3815:  representing a line in the section.
3816: */
3817: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
3818: {

3822:   PetscSectionGetFieldComponents(section, field, Nc);
3823:   if (line < 0) {
3824:     *k = 0;
3825:     *Nc = 0;
3826:   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
3827:     *k = 1;
3828:   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
3829:     /* An order k SEM disc has k-1 dofs on an edge */
3830:     PetscSectionGetFieldDof(section, line, field, k);
3831:     *k = *k / *Nc + 1;
3832:   }
3833:   return(0);
3834: }

3836: /*@

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

3842:   Input Parameters:
3843: + dm      - The DM
3844: . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
3845: - section - The PetscSection to reorder, or NULL for the default section

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

3850:   Example:
3851:   A typical interpolated single-quad mesh might order points as
3852: .vb
3853:   [c0, v1, v2, v3, v4, e5, e6, e7, e8]

3855:   v4 -- e6 -- v3
3856:   |           |
3857:   e7    c0    e8
3858:   |           |
3859:   v1 -- e5 -- v2
3860: .ve

3862:   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
3863:   dofs in the order of points, e.g.,
3864: .vb
3865:     c0 -> [0,1,2,3]
3866:     v1 -> [4]
3867:     ...
3868:     e5 -> [8, 9]
3869: .ve

3871:   which corresponds to the dofs
3872: .vb
3873:     6   10  11  7
3874:     13  2   3   15
3875:     12  0   1   14
3876:     4   8   9   5
3877: .ve

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

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

3889:   Level: developer

3891: .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlocalSection()
3892: @*/
3893: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
3894: {
3895:   DMLabel        label;
3896:   PetscInt      *perm;
3897:   PetscInt       dim, depth = -1, eStart = -1, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3898:   PetscBool      vertexchart;

3902:   DMGetDimension(dm, &dim);
3903:   if (dim < 1) return(0);
3904:   if (point < 0) {
3905:     PetscInt sStart,sEnd;

3907:     DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);
3908:     point = sEnd-sStart ? sStart : point;
3909:   }
3910:   DMPlexGetDepthLabel(dm, &label);
3911:   if (point >= 0) { DMLabelGetValue(label, point, &depth); }
3912:   if (!section) {DMGetLocalSection(dm, &section);}
3913:   if (depth == 1) {eStart = point;}
3914:   else if  (depth == dim) {
3915:     const PetscInt *cone;

3917:     DMPlexGetCone(dm, point, &cone);
3918:     if (dim == 2) eStart = cone[0];
3919:     else if (dim == 3) {
3920:       const PetscInt *cone2;
3921:       DMPlexGetCone(dm, cone[0], &cone2);
3922:       eStart = cone2[0];
3923:     } 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);
3924:   } 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);
3925:   {                             /* Determine whether the chart covers all points or just vertices. */
3926:     PetscInt pStart,pEnd,cStart,cEnd;
3927:     DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);
3928:     PetscSectionGetChart(section,&cStart,&cEnd);
3929:     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
3930:     else vertexchart = PETSC_FALSE;                                 /* Assume all interpolated points are in chart */
3931:   }
3932:   PetscSectionGetNumFields(section, &Nf);
3933:   for (f = 0; f < Nf; ++f) {
3934:     PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3935:     size += PetscPowInt(k+1, dim)*Nc;
3936:   }
3937:   PetscMalloc1(size, &perm);
3938:   for (f = 0; f < Nf; ++f) {
3939:     switch (dim) {
3940:     case 1:
3941:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3942:       /*
3943:         Original ordering is [ edge of length k-1; vtx0; vtx1 ]
3944:         We want              [ vtx0; edge of length k-1; vtx1 ]
3945:       */
3946:       for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
3947:       for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
3948:       for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
3949:       foffset = offset;
3950:       break;
3951:     case 2:
3952:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3953:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3954:       /* The SEM order is

3956:          v_lb, {e_b}, v_rb,
3957:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3958:          v_lt, reverse {e_t}, v_rt
3959:       */
3960:       {
3961:         const PetscInt of   = 0;
3962:         const PetscInt oeb  = of   + PetscSqr(k-1);
3963:         const PetscInt oer  = oeb  + (k-1);
3964:         const PetscInt oet  = oer  + (k-1);
3965:         const PetscInt oel  = oet  + (k-1);
3966:         const PetscInt ovlb = oel  + (k-1);
3967:         const PetscInt ovrb = ovlb + 1;
3968:         const PetscInt ovrt = ovrb + 1;
3969:         const PetscInt ovlt = ovrt + 1;
3970:         PetscInt       o;

3972:         /* bottom */
3973:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3974:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3975:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3976:         /* middle */
3977:         for (i = 0; i < k-1; ++i) {
3978:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3979:           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;
3980:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3981:         }
3982:         /* top */
3983:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3984:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3985:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3986:         foffset = offset;
3987:       }
3988:       break;
3989:     case 3:
3990:       /* The original hex closure is

3992:          {c,
3993:           f_b, f_t, f_f, f_b, f_r, f_l,
3994:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3995:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3996:       */
3997:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3998:       /* The SEM order is
3999:          Bottom Slice
4000:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
4001:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
4002:          v_blb, {e_bb}, v_brb,

4004:          Middle Slice (j)
4005:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
4006:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
4007:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

4009:          Top Slice
4010:          v_tlf, {e_tf}, v_trf,
4011:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
4012:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
4013:       */
4014:       {
4015:         const PetscInt oc    = 0;
4016:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
4017:         const PetscInt oft   = ofb   + PetscSqr(k-1);
4018:         const PetscInt off   = oft   + PetscSqr(k-1);
4019:         const PetscInt ofk   = off   + PetscSqr(k-1);
4020:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
4021:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
4022:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
4023:         const PetscInt oebb  = oebl  + (k-1);
4024:         const PetscInt oebr  = oebb  + (k-1);
4025:         const PetscInt oebf  = oebr  + (k-1);
4026:         const PetscInt oetf  = oebf  + (k-1);
4027:         const PetscInt oetr  = oetf  + (k-1);
4028:         const PetscInt oetb  = oetr  + (k-1);
4029:         const PetscInt oetl  = oetb  + (k-1);
4030:         const PetscInt oerf  = oetl  + (k-1);
4031:         const PetscInt oelf  = oerf  + (k-1);
4032:         const PetscInt oelb  = oelf  + (k-1);
4033:         const PetscInt oerb  = oelb  + (k-1);
4034:         const PetscInt ovblf = oerb  + (k-1);
4035:         const PetscInt ovblb = ovblf + 1;
4036:         const PetscInt ovbrb = ovblb + 1;
4037:         const PetscInt ovbrf = ovbrb + 1;
4038:         const PetscInt ovtlf = ovbrf + 1;
4039:         const PetscInt ovtrf = ovtlf + 1;
4040:         const PetscInt ovtrb = ovtrf + 1;
4041:         const PetscInt ovtlb = ovtrb + 1;
4042:         PetscInt       o, n;

4044:         /* Bottom Slice */
4045:         /*   bottom */
4046:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
4047:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4048:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
4049:         /*   middle */
4050:         for (i = 0; i < k-1; ++i) {
4051:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
4052:           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;}
4053:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
4054:         }
4055:         /*   top */
4056:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
4057:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4058:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

4060:         /* Middle Slice */
4061:         for (j = 0; j < k-1; ++j) {
4062:           /*   bottom */
4063:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
4064:           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;
4065:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
4066:           /*   middle */
4067:           for (i = 0; i < k-1; ++i) {
4068:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
4069:             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;
4070:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
4071:           }
4072:           /*   top */
4073:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
4074:           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;
4075:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
4076:         }

4078:         /* Top Slice */
4079:         /*   bottom */
4080:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
4081:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4082:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
4083:         /*   middle */
4084:         for (i = 0; i < k-1; ++i) {
4085:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
4086:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
4087:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
4088:         }
4089:         /*   top */
4090:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
4091:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4092:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

4094:         foffset = offset;
4095:       }
4096:       break;
4097:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
4098:     }
4099:   }
4100:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
4101:   /* Check permutation */
4102:   {
4103:     PetscInt *check;

4105:     PetscMalloc1(size, &check);
4106:     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]);}
4107:     for (i = 0; i < size; ++i) check[perm[i]] = i;
4108:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
4109:     PetscFree(check);
4110:   }
4111:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
4112:   return(0);
4113: }

4115: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
4116: {
4117:   PetscDS        prob;
4118:   PetscInt       depth, Nf, h;
4119:   DMLabel        label;

4123:   DMGetDS(dm, &prob);
4124:   Nf      = prob->Nf;
4125:   label   = dm->depthLabel;
4126:   *dspace = NULL;
4127:   if (field < Nf) {
4128:     PetscObject disc = prob->disc[field];

4130:     if (disc->classid == PETSCFE_CLASSID) {
4131:       PetscDualSpace dsp;

4133:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
4134:       DMLabelGetNumValues(label,&depth);
4135:       DMLabelGetValue(label,point,&h);
4136:       h    = depth - 1 - h;
4137:       if (h) {
4138:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
4139:       } else {
4140:         *dspace = dsp;
4141:       }
4142:     }
4143:   }
4144:   return(0);
4145: }


4148: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4149: {
4150:   PetscScalar    *array, *vArray;
4151:   const PetscInt *cone, *coneO;
4152:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
4153:   PetscErrorCode  ierr;

4156:   PetscSectionGetChart(section, &pStart, &pEnd);
4157:   DMPlexGetConeSize(dm, point, &numPoints);
4158:   DMPlexGetCone(dm, point, &cone);
4159:   DMPlexGetConeOrientation(dm, point, &coneO);
4160:   if (!values || !*values) {
4161:     if ((point >= pStart) && (point < pEnd)) {
4162:       PetscInt dof;

4164:       PetscSectionGetDof(section, point, &dof);
4165:       size += dof;
4166:     }
4167:     for (p = 0; p < numPoints; ++p) {
4168:       const PetscInt cp = cone[p];
4169:       PetscInt       dof;

4171:       if ((cp < pStart) || (cp >= pEnd)) continue;
4172:       PetscSectionGetDof(section, cp, &dof);
4173:       size += dof;
4174:     }
4175:     if (!values) {
4176:       if (csize) *csize = size;
4177:       return(0);
4178:     }
4179:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
4180:   } else {
4181:     array = *values;
4182:   }
4183:   size = 0;
4184:   VecGetArray(v, &vArray);
4185:   if ((point >= pStart) && (point < pEnd)) {
4186:     PetscInt     dof, off, d;
4187:     PetscScalar *varr;

4189:     PetscSectionGetDof(section, point, &dof);
4190:     PetscSectionGetOffset(section, point, &off);
4191:     varr = &vArray[off];
4192:     for (d = 0; d < dof; ++d, ++offset) {
4193:       array[offset] = varr[d];
4194:     }
4195:     size += dof;
4196:   }
4197:   for (p = 0; p < numPoints; ++p) {
4198:     const PetscInt cp = cone[p];
4199:     PetscInt       o  = coneO[p];
4200:     PetscInt       dof, off, d;
4201:     PetscScalar   *varr;

4203:     if ((cp < pStart) || (cp >= pEnd)) continue;
4204:     PetscSectionGetDof(section, cp, &dof);
4205:     PetscSectionGetOffset(section, cp, &off);
4206:     varr = &vArray[off];
4207:     if (o >= 0) {
4208:       for (d = 0; d < dof; ++d, ++offset) {
4209:         array[offset] = varr[d];
4210:       }
4211:     } else {
4212:       for (d = dof-1; d >= 0; --d, ++offset) {
4213:         array[offset] = varr[d];
4214:       }
4215:     }
4216:     size += dof;
4217:   }
4218:   VecRestoreArray(v, &vArray);
4219:   if (!*values) {
4220:     if (csize) *csize = size;
4221:     *values = array;
4222:   } else {
4223:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4224:     *csize = size;
4225:   }
4226:   return(0);
4227: }

4229: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4230: {
4231:   const PetscInt *cla;
4232:   PetscInt       np, *pts = NULL;

4236:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
4237:   if (!*clPoints) {
4238:     PetscInt pStart, pEnd, p, q;

4240:     PetscSectionGetChart(section, &pStart, &pEnd);
4241:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
4242:     /* Compress out points not in the section */
4243:     for (p = 0, q = 0; p < np; p++) {
4244:       PetscInt r = pts[2*p];
4245:       if ((r >= pStart) && (r < pEnd)) {
4246:         pts[q*2]   = r;
4247:         pts[q*2+1] = pts[2*p+1];
4248:         ++q;
4249:       }
4250:     }
4251:     np = q;
4252:     cla = NULL;
4253:   } else {
4254:     PetscInt dof, off;

4256:     PetscSectionGetDof(*clSec, point, &dof);
4257:     PetscSectionGetOffset(*clSec, point, &off);
4258:     ISGetIndices(*clPoints, &cla);
4259:     np   = dof/2;
4260:     pts  = (PetscInt *) &cla[off];
4261:   }
4262:   *numPoints = np;
4263:   *points    = pts;
4264:   *clp       = cla;

4266:   return(0);
4267: }

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

4274:   if (!*clPoints) {
4275:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
4276:   } else {
4277:     ISRestoreIndices(*clPoints, clp);
4278:   }
4279:   *numPoints = 0;
4280:   *points    = NULL;
4281:   *clSec     = NULL;
4282:   *clPoints  = NULL;
4283:   *clp       = NULL;
4284:   return(0);
4285: }

4287: 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[])
4288: {
4289:   PetscInt          offset = 0, p;
4290:   const PetscInt    **perms = NULL;
4291:   const PetscScalar **flips = NULL;
4292:   PetscErrorCode    ierr;

4295:   *size = 0;
4296:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4297:   for (p = 0; p < numPoints; p++) {
4298:     const PetscInt    point = points[2*p];
4299:     const PetscInt    *perm = perms ? perms[p] : NULL;
4300:     const PetscScalar *flip = flips ? flips[p] : NULL;
4301:     PetscInt          dof, off, d;
4302:     const PetscScalar *varr;

4304:     PetscSectionGetDof(section, point, &dof);
4305:     PetscSectionGetOffset(section, point, &off);
4306:     varr = &vArray[off];
4307:     if (clperm) {
4308:       if (perm) {
4309:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4310:       } else {
4311:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4312:       }
4313:       if (flip) {
4314:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4315:       }
4316:     } else {
4317:       if (perm) {
4318:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4319:       } else {
4320:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4321:       }
4322:       if (flip) {
4323:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4324:       }
4325:     }
4326:     offset += dof;
4327:   }
4328:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4329:   *size = offset;
4330:   return(0);
4331: }

4333: 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[])
4334: {
4335:   PetscInt          offset = 0, f;
4336:   PetscErrorCode    ierr;

4339:   *size = 0;
4340:   for (f = 0; f < numFields; ++f) {
4341:     PetscInt          p;
4342:     const PetscInt    **perms = NULL;
4343:     const PetscScalar **flips = NULL;

4345:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4346:     for (p = 0; p < numPoints; p++) {
4347:       const PetscInt    point = points[2*p];
4348:       PetscInt          fdof, foff, b;
4349:       const PetscScalar *varr;
4350:       const PetscInt    *perm = perms ? perms[p] : NULL;
4351:       const PetscScalar *flip = flips ? flips[p] : NULL;

4353:       PetscSectionGetFieldDof(section, point, f, &fdof);
4354:       PetscSectionGetFieldOffset(section, point, f, &foff);
4355:       varr = &vArray[foff];
4356:       if (clperm) {
4357:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4358:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4359:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4360:       } else {
4361:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4362:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4363:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4364:       }
4365:       offset += fdof;
4366:     }
4367:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4368:   }
4369:   *size = offset;
4370:   return(0);
4371: }

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

4376:   Not collective

4378:   Input Parameters:
4379: + dm - The DM
4380: . section - The section describing the layout in v, or NULL to use the default section
4381: . v - The local vector
4382: . point - The point in the DM
4383: . csize - The size of the input values array, or NULL
4384: - values - An array to use for the values, or NULL to have it allocated automatically

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

4390: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4391: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4392: $ assembly function, and a user may already have allocated storage for this operation.
4393: $
4394: $ A typical use could be
4395: $
4396: $  values = NULL;
4397: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4398: $  for (cl = 0; cl < clSize; ++cl) {
4399: $    <Compute on closure>
4400: $  }
4401: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4402: $
4403: $ or
4404: $
4405: $  PetscMalloc1(clMaxSize, &values);
4406: $  for (p = pStart; p < pEnd; ++p) {
4407: $    clSize = clMaxSize;
4408: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4409: $    for (cl = 0; cl < clSize; ++cl) {
4410: $      <Compute on closure>
4411: $    }
4412: $  }
4413: $  PetscFree(values);

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

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

4421:   Level: intermediate

4423: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4424: @*/
4425: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4426: {
4427:   PetscSection       clSection;
4428:   IS                 clPoints;
4429:   PetscScalar       *array;
4430:   const PetscScalar *vArray;
4431:   PetscInt          *points = NULL;
4432:   const PetscInt    *clp, *perm;
4433:   PetscInt           depth, numFields, numPoints, size;
4434:   PetscErrorCode     ierr;

4438:   if (!section) {DMGetLocalSection(dm, &section);}
4441:   DMPlexGetDepth(dm, &depth);
4442:   PetscSectionGetNumFields(section, &numFields);
4443:   if (depth == 1 && numFields < 2) {
4444:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4445:     return(0);
4446:   }
4447:   /* Get points */
4448:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4449:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4450:   /* Get array */
4451:   if (!values || !*values) {
4452:     PetscInt asize = 0, dof, p;

4454:     for (p = 0; p < numPoints*2; p += 2) {
4455:       PetscSectionGetDof(section, points[p], &dof);
4456:       asize += dof;
4457:     }
4458:     if (!values) {
4459:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4460:       if (csize) *csize = asize;
4461:       return(0);
4462:     }
4463:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4464:   } else {
4465:     array = *values;
4466:   }
4467:   VecGetArrayRead(v, &vArray);
4468:   /* Get values */
4469:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4470:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4471:   /* Cleanup points */
4472:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4473:   /* Cleanup array */
4474:   VecRestoreArrayRead(v, &vArray);
4475:   if (!*values) {
4476:     if (csize) *csize = size;
4477:     *values = array;
4478:   } else {
4479:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4480:     *csize = size;
4481:   }
4482:   return(0);
4483: }

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

4488:   Not collective

4490:   Input Parameters:
4491: + dm - The DM
4492: . section - The section describing the layout in v, or NULL to use the default section
4493: . v - The local vector
4494: . point - The point in the DM
4495: . csize - The number of values in the closure, or NULL
4496: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

4506:   Level: intermediate

4508: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4509: @*/
4510: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4511: {
4512:   PetscInt       size = 0;

4516:   /* Should work without recalculating size */
4517:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4518:   *values = NULL;
4519:   return(0);
4520: }

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

4525: 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[])
4526: {
4527:   PetscInt        cdof;   /* The number of constraints on this point */
4528:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4529:   PetscScalar    *a;
4530:   PetscInt        off, cind = 0, k;
4531:   PetscErrorCode  ierr;

4534:   PetscSectionGetConstraintDof(section, point, &cdof);
4535:   PetscSectionGetOffset(section, point, &off);
4536:   a    = &array[off];
4537:   if (!cdof || setBC) {
4538:     if (clperm) {
4539:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4540:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4541:     } else {
4542:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4543:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4544:     }
4545:   } else {
4546:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4547:     if (clperm) {
4548:       if (perm) {for (k = 0; k < dof; ++k) {
4549:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4550:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4551:         }
4552:       } else {
4553:         for (k = 0; k < dof; ++k) {
4554:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4555:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4556:         }
4557:       }
4558:     } else {
4559:       if (perm) {
4560:         for (k = 0; k < dof; ++k) {
4561:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4562:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4563:         }
4564:       } else {
4565:         for (k = 0; k < dof; ++k) {
4566:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4567:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4568:         }
4569:       }
4570:     }
4571:   }
4572:   return(0);
4573: }

4575: 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[])
4576: {
4577:   PetscInt        cdof;   /* The number of constraints on this point */
4578:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4579:   PetscScalar    *a;
4580:   PetscInt        off, cind = 0, k;
4581:   PetscErrorCode  ierr;

4584:   PetscSectionGetConstraintDof(section, point, &cdof);
4585:   PetscSectionGetOffset(section, point, &off);
4586:   a    = &array[off];
4587:   if (cdof) {
4588:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4589:     if (clperm) {
4590:       if (perm) {
4591:         for (k = 0; k < dof; ++k) {
4592:           if ((cind < cdof) && (k == cdofs[cind])) {
4593:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4594:             cind++;
4595:           }
4596:         }
4597:       } else {
4598:         for (k = 0; k < dof; ++k) {
4599:           if ((cind < cdof) && (k == cdofs[cind])) {
4600:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4601:             cind++;
4602:           }
4603:         }
4604:       }
4605:     } else {
4606:       if (perm) {
4607:         for (k = 0; k < dof; ++k) {
4608:           if ((cind < cdof) && (k == cdofs[cind])) {
4609:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4610:             cind++;
4611:           }
4612:         }
4613:       } else {
4614:         for (k = 0; k < dof; ++k) {
4615:           if ((cind < cdof) && (k == cdofs[cind])) {
4616:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4617:             cind++;
4618:           }
4619:         }
4620:       }
4621:     }
4622:   }
4623:   return(0);
4624: }

4626: 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[])
4627: {
4628:   PetscScalar    *a;
4629:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4630:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4631:   PetscInt        cind = 0, b;
4632:   PetscErrorCode  ierr;

4635:   PetscSectionGetFieldDof(section, point, f, &fdof);
4636:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4637:   PetscSectionGetFieldOffset(section, point, f, &foff);
4638:   a    = &array[foff];
4639:   if (!fcdof || setBC) {
4640:     if (clperm) {
4641:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4642:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4643:     } else {
4644:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4645:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4646:     }
4647:   } else {
4648:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4649:     if (clperm) {
4650:       if (perm) {
4651:         for (b = 0; b < fdof; b++) {
4652:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4653:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4654:         }
4655:       } else {
4656:         for (b = 0; b < fdof; b++) {
4657:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4658:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4659:         }
4660:       }
4661:     } else {
4662:       if (perm) {
4663:         for (b = 0; b < fdof; b++) {
4664:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4665:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4666:         }
4667:       } else {
4668:         for (b = 0; b < fdof; b++) {
4669:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4670:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4671:         }
4672:       }
4673:     }
4674:   }
4675:   *offset += fdof;
4676:   return(0);
4677: }

4679: 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[])
4680: {
4681:   PetscScalar    *a;
4682:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4683:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4684:   PetscInt        cind = 0, ncind = 0, b;
4685:   PetscBool       ncSet, fcSet;
4686:   PetscErrorCode  ierr;

4689:   PetscSectionGetFieldDof(section, point, f, &fdof);
4690:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4691:   PetscSectionGetFieldOffset(section, point, f, &foff);
4692:   a    = &array[foff];
4693:   if (fcdof) {
4694:     /* We just override fcdof and fcdofs with Ncc and comps */
4695:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4696:     if (clperm) {
4697:       if (perm) {
4698:         if (comps) {
4699:           for (b = 0; b < fdof; b++) {
4700:             ncSet = fcSet = PETSC_FALSE;
4701:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4702:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4703:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4704:           }
4705:         } else {
4706:           for (b = 0; b < fdof; b++) {
4707:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4708:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4709:               ++cind;
4710:             }
4711:           }
4712:         }
4713:       } else {
4714:         if (comps) {
4715:           for (b = 0; b < fdof; b++) {
4716:             ncSet = fcSet = PETSC_FALSE;
4717:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4718:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4719:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4720:           }
4721:         } else {
4722:           for (b = 0; b < fdof; b++) {
4723:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4724:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4725:               ++cind;
4726:             }
4727:           }
4728:         }
4729:       }
4730:     } else {
4731:       if (perm) {
4732:         if (comps) {
4733:           for (b = 0; b < fdof; b++) {
4734:             ncSet = fcSet = PETSC_FALSE;
4735:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4736:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4737:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4738:           }
4739:         } else {
4740:           for (b = 0; b < fdof; b++) {
4741:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4742:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4743:               ++cind;
4744:             }
4745:           }
4746:         }
4747:       } else {
4748:         if (comps) {
4749:           for (b = 0; b < fdof; b++) {
4750:             ncSet = fcSet = PETSC_FALSE;
4751:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4752:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4753:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4754:           }
4755:         } else {
4756:           for (b = 0; b < fdof; b++) {
4757:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4758:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4759:               ++cind;
4760:             }
4761:           }
4762:         }
4763:       }
4764:     }
4765:   }
4766:   *offset += fdof;
4767:   return(0);
4768: }

4770: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4771: {
4772:   PetscScalar    *array;
4773:   const PetscInt *cone, *coneO;
4774:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4775:   PetscErrorCode  ierr;

4778:   PetscSectionGetChart(section, &pStart, &pEnd);
4779:   DMPlexGetConeSize(dm, point, &numPoints);
4780:   DMPlexGetCone(dm, point, &cone);
4781:   DMPlexGetConeOrientation(dm, point, &coneO);
4782:   VecGetArray(v, &array);
4783:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4784:     const PetscInt cp = !p ? point : cone[p-1];
4785:     const PetscInt o  = !p ? 0     : coneO[p-1];

4787:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4788:     PetscSectionGetDof(section, cp, &dof);
4789:     /* ADD_VALUES */
4790:     {
4791:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4792:       PetscScalar    *a;
4793:       PetscInt        cdof, coff, cind = 0, k;

4795:       PetscSectionGetConstraintDof(section, cp, &cdof);
4796:       PetscSectionGetOffset(section, cp, &coff);
4797:       a    = &array[coff];
4798:       if (!cdof) {
4799:         if (o >= 0) {
4800:           for (k = 0; k < dof; ++k) {
4801:             a[k] += values[off+k];
4802:           }
4803:         } else {
4804:           for (k = 0; k < dof; ++k) {
4805:             a[k] += values[off+dof-k-1];
4806:           }
4807:         }
4808:       } else {
4809:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4810:         if (o >= 0) {
4811:           for (k = 0; k < dof; ++k) {
4812:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4813:             a[k] += values[off+k];
4814:           }
4815:         } else {
4816:           for (k = 0; k < dof; ++k) {
4817:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4818:             a[k] += values[off+dof-k-1];
4819:           }
4820:         }
4821:       }
4822:     }
4823:   }
4824:   VecRestoreArray(v, &array);
4825:   return(0);
4826: }

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

4831:   Not collective

4833:   Input Parameters:
4834: + dm - The DM
4835: . section - The section describing the layout in v, or NULL to use the default section
4836: . v - The local vector
4837: . point - The point in the DM
4838: . values - The array of values
4839: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4840:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4845:   Level: intermediate

4847: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4848: @*/
4849: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4850: {
4851:   PetscSection    clSection;
4852:   IS              clPoints;
4853:   PetscScalar    *array;
4854:   PetscInt       *points = NULL;
4855:   const PetscInt *clp, *clperm;
4856:   PetscInt        depth, numFields, numPoints, p;
4857:   PetscErrorCode  ierr;

4861:   if (!section) {DMGetLocalSection(dm, &section);}
4864:   DMPlexGetDepth(dm, &depth);
4865:   PetscSectionGetNumFields(section, &numFields);
4866:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4867:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4868:     return(0);
4869:   }
4870:   /* Get points */
4871:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4872:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4873:   /* Get array */
4874:   VecGetArray(v, &array);
4875:   /* Get values */
4876:   if (numFields > 0) {
4877:     PetscInt offset = 0, f;
4878:     for (f = 0; f < numFields; ++f) {
4879:       const PetscInt    **perms = NULL;
4880:       const PetscScalar **flips = NULL;

4882:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4883:       switch (mode) {
4884:       case INSERT_VALUES:
4885:         for (p = 0; p < numPoints; p++) {
4886:           const PetscInt    point = points[2*p];
4887:           const PetscInt    *perm = perms ? perms[p] : NULL;
4888:           const PetscScalar *flip = flips ? flips[p] : NULL;
4889:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4890:         } break;
4891:       case INSERT_ALL_VALUES:
4892:         for (p = 0; p < numPoints; p++) {
4893:           const PetscInt    point = points[2*p];
4894:           const PetscInt    *perm = perms ? perms[p] : NULL;
4895:           const PetscScalar *flip = flips ? flips[p] : NULL;
4896:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4897:         } break;
4898:       case INSERT_BC_VALUES:
4899:         for (p = 0; p < numPoints; p++) {
4900:           const PetscInt    point = points[2*p];
4901:           const PetscInt    *perm = perms ? perms[p] : NULL;
4902:           const PetscScalar *flip = flips ? flips[p] : NULL;
4903:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4904:         } break;
4905:       case ADD_VALUES:
4906:         for (p = 0; p < numPoints; p++) {
4907:           const PetscInt    point = points[2*p];
4908:           const PetscInt    *perm = perms ? perms[p] : NULL;
4909:           const PetscScalar *flip = flips ? flips[p] : NULL;
4910:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4911:         } break;
4912:       case ADD_ALL_VALUES:
4913:         for (p = 0; p < numPoints; p++) {
4914:           const PetscInt    point = points[2*p];
4915:           const PetscInt    *perm = perms ? perms[p] : NULL;
4916:           const PetscScalar *flip = flips ? flips[p] : NULL;
4917:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4918:         } break;
4919:       case ADD_BC_VALUES:
4920:         for (p = 0; p < numPoints; p++) {
4921:           const PetscInt    point = points[2*p];
4922:           const PetscInt    *perm = perms ? perms[p] : NULL;
4923:           const PetscScalar *flip = flips ? flips[p] : NULL;
4924:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4925:         } break;
4926:       default:
4927:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4928:       }
4929:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4930:     }
4931:   } else {
4932:     PetscInt dof, off;
4933:     const PetscInt    **perms = NULL;
4934:     const PetscScalar **flips = NULL;

4936:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4937:     switch (mode) {
4938:     case INSERT_VALUES:
4939:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4940:         const PetscInt    point = points[2*p];
4941:         const PetscInt    *perm = perms ? perms[p] : NULL;
4942:         const PetscScalar *flip = flips ? flips[p] : NULL;
4943:         PetscSectionGetDof(section, point, &dof);
4944:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4945:       } break;
4946:     case INSERT_ALL_VALUES:
4947:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4948:         const PetscInt    point = points[2*p];
4949:         const PetscInt    *perm = perms ? perms[p] : NULL;
4950:         const PetscScalar *flip = flips ? flips[p] : NULL;
4951:         PetscSectionGetDof(section, point, &dof);
4952:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4953:       } break;
4954:     case INSERT_BC_VALUES:
4955:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4956:         const PetscInt    point = points[2*p];
4957:         const PetscInt    *perm = perms ? perms[p] : NULL;
4958:         const PetscScalar *flip = flips ? flips[p] : NULL;
4959:         PetscSectionGetDof(section, point, &dof);
4960:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4961:       } break;
4962:     case ADD_VALUES:
4963:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4964:         const PetscInt    point = points[2*p];
4965:         const PetscInt    *perm = perms ? perms[p] : NULL;
4966:         const PetscScalar *flip = flips ? flips[p] : NULL;
4967:         PetscSectionGetDof(section, point, &dof);
4968:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4969:       } break;
4970:     case ADD_ALL_VALUES:
4971:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4972:         const PetscInt    point = points[2*p];
4973:         const PetscInt    *perm = perms ? perms[p] : NULL;
4974:         const PetscScalar *flip = flips ? flips[p] : NULL;
4975:         PetscSectionGetDof(section, point, &dof);
4976:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4977:       } break;
4978:     case ADD_BC_VALUES:
4979:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4980:         const PetscInt    point = points[2*p];
4981:         const PetscInt    *perm = perms ? perms[p] : NULL;
4982:         const PetscScalar *flip = flips ? flips[p] : NULL;
4983:         PetscSectionGetDof(section, point, &dof);
4984:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4985:       } break;
4986:     default:
4987:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4988:     }
4989:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4990:   }
4991:   /* Cleanup points */
4992:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4993:   /* Cleanup array */
4994:   VecRestoreArray(v, &array);
4995:   return(0);
4996: }

4998: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4999: {
5000:   PetscSection      clSection;
5001:   IS                clPoints;
5002:   PetscScalar       *array;
5003:   PetscInt          *points = NULL;
5004:   const PetscInt    *clp, *clperm;
5005:   PetscInt          numFields, numPoints, p;
5006:   PetscInt          offset = 0, f;
5007:   PetscErrorCode    ierr;

5011:   if (!section) {DMGetLocalSection(dm, &section);}
5014:   PetscSectionGetNumFields(section, &numFields);
5015:   /* Get points */
5016:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5017:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5018:   /* Get array */
5019:   VecGetArray(v, &array);
5020:   /* Get values */
5021:   for (f = 0; f < numFields; ++f) {
5022:     const PetscInt    **perms = NULL;
5023:     const PetscScalar **flips = NULL;

5025:     if (!fieldActive[f]) {
5026:       for (p = 0; p < numPoints*2; p += 2) {
5027:         PetscInt fdof;
5028:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
5029:         offset += fdof;
5030:       }
5031:       continue;
5032:     }
5033:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5034:     switch (mode) {
5035:     case INSERT_VALUES:
5036:       for (p = 0; p < numPoints; p++) {
5037:         const PetscInt    point = points[2*p];
5038:         const PetscInt    *perm = perms ? perms[p] : NULL;
5039:         const PetscScalar *flip = flips ? flips[p] : NULL;
5040:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5041:       } break;
5042:     case INSERT_ALL_VALUES:
5043:       for (p = 0; p < numPoints; p++) {
5044:         const PetscInt    point = points[2*p];
5045:         const PetscInt    *perm = perms ? perms[p] : NULL;
5046:         const PetscScalar *flip = flips ? flips[p] : NULL;
5047:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5048:         } break;
5049:     case INSERT_BC_VALUES:
5050:       for (p = 0; p < numPoints; p++) {
5051:         const PetscInt    point = points[2*p];
5052:         const PetscInt    *perm = perms ? perms[p] : NULL;
5053:         const PetscScalar *flip = flips ? flips[p] : NULL;
5054:         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
5055:       } break;
5056:     case ADD_VALUES:
5057:       for (p = 0; p < numPoints; p++) {
5058:         const PetscInt    point = points[2*p];
5059:         const PetscInt    *perm = perms ? perms[p] : NULL;
5060:         const PetscScalar *flip = flips ? flips[p] : NULL;
5061:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5062:       } break;
5063:     case ADD_ALL_VALUES:
5064:       for (p = 0; p < numPoints; p++) {
5065:         const PetscInt    point = points[2*p];
5066:         const PetscInt    *perm = perms ? perms[p] : NULL;
5067:         const PetscScalar *flip = flips ? flips[p] : NULL;
5068:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5069:       } break;
5070:     default:
5071:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5072:     }
5073:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5074:   }
5075:   /* Cleanup points */
5076:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5077:   /* Cleanup array */
5078:   VecRestoreArray(v, &array);
5079:   return(0);
5080: }

5082: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
5083: {
5084:   PetscMPIInt    rank;
5085:   PetscInt       i, j;

5089:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
5090:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
5091:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
5092:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
5093:   numCIndices = numCIndices ? numCIndices : numRIndices;
5094:   for (i = 0; i < numRIndices; i++) {
5095:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
5096:     for (j = 0; j < numCIndices; j++) {
5097: #if defined(PETSC_USE_COMPLEX)
5098:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
5099: #else
5100:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
5101: #endif
5102:     }
5103:     PetscViewerASCIIPrintf(viewer, "\n");
5104:   }
5105:   return(0);
5106: }

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

5111:   Input Parameters:
5112: + section - The section for this data layout
5113: . point   - The point contributing dofs with these indices
5114: . off     - The global offset of this point
5115: . loff    - The local offset of each field
5116: . setBC   - The flag determining whether to include indices of bounsary values
5117: . perm    - A permutation of the dofs on this point, or NULL
5118: - indperm - A permutation of the entire indices array, or NULL

5120:   Output Parameter:
5121: . indices - Indices for dofs on this point

5123:   Level: developer

5125:   Note: The indices could be local or global, depending on the value of 'off'.
5126: */
5127: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
5128: {
5129:   PetscInt        dof;   /* The number of unknowns on this point */
5130:   PetscInt        cdof;  /* The number of constraints on this point */
5131:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5132:   PetscInt        cind = 0, k;
5133:   PetscErrorCode  ierr;

5136:   PetscSectionGetDof(section, point, &dof);
5137:   PetscSectionGetConstraintDof(section, point, &cdof);
5138:   if (!cdof || setBC) {
5139:     for (k = 0; k < dof; ++k) {
5140:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5141:       const PetscInt ind    = indperm ? indperm[preind] : preind;

5143:       indices[ind] = off + k;
5144:     }
5145:   } else {
5146:     PetscSectionGetConstraintIndices(section, point, &cdofs);
5147:     for (k = 0; k < dof; ++k) {
5148:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5149:       const PetscInt ind    = indperm ? indperm[preind] : preind;

5151:       if ((cind < cdof) && (k == cdofs[cind])) {
5152:         /* Insert check for returning constrained indices */
5153:         indices[ind] = -(off+k+1);
5154:         ++cind;
5155:       } else {
5156:         indices[ind] = off+k-cind;
5157:       }
5158:     }
5159:   }
5160:   *loff += dof;
5161:   return(0);
5162: }

5164: /*
5165:   This version only believes the point offset from the globalSection

5167:  . off - The global offset of this point
5168: */
5169: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5170: {
5171:   PetscInt       numFields, foff, f;

5175:   PetscSectionGetNumFields(section, &numFields);
5176:   for (f = 0, foff = 0; f < numFields; ++f) {
5177:     PetscInt        fdof, cfdof;
5178:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5179:     PetscInt        cind = 0, b;
5180:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5182:     PetscSectionGetFieldDof(section, point, f, &fdof);
5183:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5184:     if (!cfdof || setBC) {
5185:       for (b = 0; b < fdof; ++b) {
5186:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5187:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5189:         indices[ind] = off+foff+b;
5190:       }
5191:     } else {
5192:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5193:       for (b = 0; b < fdof; ++b) {
5194:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5195:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5197:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5198:           indices[ind] = -(off+foff+b+1);
5199:           ++cind;
5200:         } else {
5201:           indices[ind] = off+foff+b-cind;
5202:         }
5203:       }
5204:     }
5205:     foff     += (setBC ? fdof : (fdof - cfdof));
5206:     foffs[f] += fdof;
5207:   }
5208:   return(0);
5209: }

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

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

5222:   PetscSectionGetNumFields(section, &numFields);
5223:   for (f = 0; f < numFields; ++f) {
5224:     PetscInt        fdof, cfdof;
5225:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5226:     PetscInt        cind = 0, b;
5227:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5229:     PetscSectionGetFieldDof(section, point, f, &fdof);
5230:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5231:     PetscSectionGetFieldOffset(globalSection, point, f, &foff);
5232:     if (!cfdof || setBC) {
5233:       for (b = 0; b < fdof; ++b) {
5234:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5235:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5237:         indices[ind] = foff+b;
5238:       }
5239:     } else {
5240:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5241:       for (b = 0; b < fdof; ++b) {
5242:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5243:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5245:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5246:           indices[ind] = -(foff+b+1);
5247:           ++cind;
5248:         } else {
5249:           indices[ind] = foff+b-cind;
5250:         }
5251:       }
5252:     }
5253:     foffs[f] += fdof;
5254:   }
5255:   return(0);
5256: }

5258: 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)
5259: {
5260:   Mat             cMat;
5261:   PetscSection    aSec, cSec;
5262:   IS              aIS;
5263:   PetscInt        aStart = -1, aEnd = -1;
5264:   const PetscInt  *anchors;
5265:   PetscInt        numFields, f, p, q, newP = 0;
5266:   PetscInt        newNumPoints = 0, newNumIndices = 0;
5267:   PetscInt        *newPoints, *indices, *newIndices;
5268:   PetscInt        maxAnchor, maxDof;
5269:   PetscInt        newOffsets[32];
5270:   PetscInt        *pointMatOffsets[32];
5271:   PetscInt        *newPointOffsets[32];
5272:   PetscScalar     *pointMat[32];
5273:   PetscScalar     *newValues=NULL,*tmpValues;
5274:   PetscBool       anyConstrained = PETSC_FALSE;
5275:   PetscErrorCode  ierr;

5280:   PetscSectionGetNumFields(section, &numFields);

5282:   DMPlexGetAnchors(dm,&aSec,&aIS);
5283:   /* if there are point-to-point constraints */
5284:   if (aSec) {
5285:     PetscArrayzero(newOffsets, 32);
5286:     ISGetIndices(aIS,&anchors);
5287:     PetscSectionGetChart(aSec,&aStart,&aEnd);
5288:     /* figure out how many points are going to be in the new element matrix
5289:      * (we allow double counting, because it's all just going to be summed
5290:      * into the global matrix anyway) */
5291:     for (p = 0; p < 2*numPoints; p+=2) {
5292:       PetscInt b    = points[p];
5293:       PetscInt bDof = 0, bSecDof;

5295:       PetscSectionGetDof(section,b,&bSecDof);
5296:       if (!bSecDof) {
5297:         continue;
5298:       }
5299:       if (b >= aStart && b < aEnd) {
5300:         PetscSectionGetDof(aSec,b,&bDof);
5301:       }
5302:       if (bDof) {
5303:         /* this point is constrained */
5304:         /* it is going to be replaced by its anchors */
5305:         PetscInt bOff, q;

5307:         anyConstrained = PETSC_TRUE;
5308:         newNumPoints  += bDof;
5309:         PetscSectionGetOffset(aSec,b,&bOff);
5310:         for (q = 0; q < bDof; q++) {
5311:           PetscInt a = anchors[bOff + q];
5312:           PetscInt aDof;

5314:           PetscSectionGetDof(section,a,&aDof);
5315:           newNumIndices += aDof;
5316:           for (f = 0; f < numFields; ++f) {
5317:             PetscInt fDof;

5319:             PetscSectionGetFieldDof(section, a, f, &fDof);
5320:             newOffsets[f+1] += fDof;
5321:           }
5322:         }
5323:       }
5324:       else {
5325:         /* this point is not constrained */
5326:         newNumPoints++;
5327:         newNumIndices += bSecDof;
5328:         for (f = 0; f < numFields; ++f) {
5329:           PetscInt fDof;

5331:           PetscSectionGetFieldDof(section, b, f, &fDof);
5332:           newOffsets[f+1] += fDof;
5333:         }
5334:       }
5335:     }
5336:   }
5337:   if (!anyConstrained) {
5338:     if (outNumPoints)  *outNumPoints  = 0;
5339:     if (outNumIndices) *outNumIndices = 0;
5340:     if (outPoints)     *outPoints     = NULL;
5341:     if (outValues)     *outValues     = NULL;
5342:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5343:     return(0);
5344:   }

5346:   if (outNumPoints)  *outNumPoints  = newNumPoints;
5347:   if (outNumIndices) *outNumIndices = newNumIndices;

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

5351:   if (!outPoints && !outValues) {
5352:     if (offsets) {
5353:       for (f = 0; f <= numFields; f++) {
5354:         offsets[f] = newOffsets[f];
5355:       }
5356:     }
5357:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5358:     return(0);
5359:   }

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

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

5365:   /* workspaces */
5366:   if (numFields) {
5367:     for (f = 0; f < numFields; f++) {
5368:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5369:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5370:     }
5371:   }
5372:   else {
5373:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5374:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5375:   }

5377:   /* get workspaces for the point-to-point matrices */
5378:   if (numFields) {
5379:     PetscInt totalOffset, totalMatOffset;

5381:     for (p = 0; p < numPoints; p++) {
5382:       PetscInt b    = points[2*p];
5383:       PetscInt bDof = 0, bSecDof;

5385:       PetscSectionGetDof(section,b,&bSecDof);
5386:       if (!bSecDof) {
5387:         for (f = 0; f < numFields; f++) {
5388:           newPointOffsets[f][p + 1] = 0;
5389:           pointMatOffsets[f][p + 1] = 0;
5390:         }
5391:         continue;
5392:       }
5393:       if (b >= aStart && b < aEnd) {
5394:         PetscSectionGetDof(aSec, b, &bDof);
5395:       }
5396:       if (bDof) {
5397:         for (f = 0; f < numFields; f++) {
5398:           PetscInt fDof, q, bOff, allFDof = 0;

5400:           PetscSectionGetFieldDof(section, b, f, &fDof);
5401:           PetscSectionGetOffset(aSec, b, &bOff);
5402:           for (q = 0; q < bDof; q++) {
5403:             PetscInt a = anchors[bOff + q];
5404:             PetscInt aFDof;

5406:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5407:             allFDof += aFDof;
5408:           }
5409:           newPointOffsets[f][p+1] = allFDof;
5410:           pointMatOffsets[f][p+1] = fDof * allFDof;
5411:         }
5412:       }
5413:       else {
5414:         for (f = 0; f < numFields; f++) {
5415:           PetscInt fDof;

5417:           PetscSectionGetFieldDof(section, b, f, &fDof);
5418:           newPointOffsets[f][p+1] = fDof;
5419:           pointMatOffsets[f][p+1] = 0;
5420:         }
5421:       }
5422:     }
5423:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5424:       newPointOffsets[f][0] = totalOffset;
5425:       pointMatOffsets[f][0] = totalMatOffset;
5426:       for (p = 0; p < numPoints; p++) {
5427:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5428:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5429:       }
5430:       totalOffset    = newPointOffsets[f][numPoints];
5431:       totalMatOffset = pointMatOffsets[f][numPoints];
5432:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5433:     }
5434:   }
5435:   else {
5436:     for (p = 0; p < numPoints; p++) {
5437:       PetscInt b    = points[2*p];
5438:       PetscInt bDof = 0, bSecDof;

5440:       PetscSectionGetDof(section,b,&bSecDof);
5441:       if (!bSecDof) {
5442:         newPointOffsets[0][p + 1] = 0;
5443:         pointMatOffsets[0][p + 1] = 0;
5444:         continue;
5445:       }
5446:       if (b >= aStart && b < aEnd) {
5447:         PetscSectionGetDof(aSec, b, &bDof);
5448:       }
5449:       if (bDof) {
5450:         PetscInt bOff, q, allDof = 0;

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

5456:           PetscSectionGetDof(section, a, &aDof);
5457:           allDof += aDof;
5458:         }
5459:         newPointOffsets[0][p+1] = allDof;
5460:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5461:       }
5462:       else {
5463:         newPointOffsets[0][p+1] = bSecDof;
5464:         pointMatOffsets[0][p+1] = 0;
5465:       }
5466:     }
5467:     newPointOffsets[0][0] = 0;
5468:     pointMatOffsets[0][0] = 0;
5469:     for (p = 0; p < numPoints; p++) {
5470:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5471:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5472:     }
5473:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5474:   }

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

5479:   /* get the point-to-point matrices; construct newPoints */
5480:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5481:   PetscSectionGetMaxDof(section, &maxDof);
5482:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5483:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5484:   if (numFields) {
5485:     for (p = 0, newP = 0; p < numPoints; p++) {
5486:       PetscInt b    = points[2*p];
5487:       PetscInt o    = points[2*p+1];
5488:       PetscInt bDof = 0, bSecDof;

5490:       PetscSectionGetDof(section, b, &bSecDof);
5491:       if (!bSecDof) {
5492:         continue;
5493:       }
5494:       if (b >= aStart && b < aEnd) {
5495:         PetscSectionGetDof(aSec, b, &bDof);
5496:       }
5497:       if (bDof) {
5498:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5500:         fStart[0] = 0;
5501:         fEnd[0]   = 0;
5502:         for (f = 0; f < numFields; f++) {
5503:           PetscInt fDof;

5505:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5506:           fStart[f+1] = fStart[f] + fDof;
5507:           fEnd[f+1]   = fStart[f+1];
5508:         }
5509:         PetscSectionGetOffset(cSec, b, &bOff);
5510:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);

5512:         fAnchorStart[0] = 0;
5513:         fAnchorEnd[0]   = 0;
5514:         for (f = 0; f < numFields; f++) {
5515:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5517:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5518:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5519:         }
5520:         PetscSectionGetOffset(aSec, b, &bOff);
5521:         for (q = 0; q < bDof; q++) {
5522:           PetscInt a = anchors[bOff + q], aOff;

5524:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5525:           newPoints[2*(newP + q)]     = a;
5526:           newPoints[2*(newP + q) + 1] = 0;
5527:           PetscSectionGetOffset(section, a, &aOff);
5528:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);
5529:         }
5530:         newP += bDof;

5532:         if (outValues) {
5533:           /* get the point-to-point submatrix */
5534:           for (f = 0; f < numFields; f++) {
5535:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5536:           }
5537:         }
5538:       }
5539:       else {
5540:         newPoints[2 * newP]     = b;
5541:         newPoints[2 * newP + 1] = o;
5542:         newP++;
5543:       }
5544:     }
5545:   } else {
5546:     for (p = 0; p < numPoints; p++) {
5547:       PetscInt b    = points[2*p];
5548:       PetscInt o    = points[2*p+1];
5549:       PetscInt bDof = 0, bSecDof;

5551:       PetscSectionGetDof(section, b, &bSecDof);
5552:       if (!bSecDof) {
5553:         continue;
5554:       }
5555:       if (b >= aStart && b < aEnd) {
5556:         PetscSectionGetDof(aSec, b, &bDof);
5557:       }
5558:       if (bDof) {
5559:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5570:           newPoints[2*(newP + q)]     = a;
5571:           newPoints[2*(newP + q) + 1] = 0;
5572:           PetscSectionGetOffset(section, a, &aOff);
5573:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);
5574:         }
5575:         newP += bDof;

5577:         /* get the point-to-point submatrix */
5578:         if (outValues) {
5579:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5580:         }
5581:       }
5582:       else {
5583:         newPoints[2 * newP]     = b;
5584:         newPoints[2 * newP + 1] = o;
5585:         newP++;
5586:       }
5587:     }
5588:   }

5590:   if (outValues) {
5591:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5592:     PetscArrayzero(tmpValues,newNumIndices*numIndices);
5593:     /* multiply constraints on the right */
5594:     if (numFields) {
5595:       for (f = 0; f < numFields; f++) {
5596:         PetscInt oldOff = offsets[f];

5598:         for (p = 0; p < numPoints; p++) {
5599:           PetscInt cStart = newPointOffsets[f][p];
5600:           PetscInt b      = points[2 * p];
5601:           PetscInt c, r, k;
5602:           PetscInt dof;

5604:           PetscSectionGetFieldDof(section,b,f,&dof);
5605:           if (!dof) {
5606:             continue;
5607:           }
5608:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5609:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5610:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5612:             for (r = 0; r < numIndices; r++) {
5613:               for (c = 0; c < nCols; c++) {
5614:                 for (k = 0; k < dof; k++) {
5615:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5616:                 }
5617:               }
5618:             }
5619:           }
5620:           else {
5621:             /* copy this column as is */
5622:             for (r = 0; r < numIndices; r++) {
5623:               for (c = 0; c < dof; c++) {
5624:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5625:               }
5626:             }
5627:           }
5628:           oldOff += dof;
5629:         }
5630:       }
5631:     }
5632:     else {
5633:       PetscInt oldOff = 0;
5634:       for (p = 0; p < numPoints; p++) {
5635:         PetscInt cStart = newPointOffsets[0][p];
5636:         PetscInt b      = points[2 * p];
5637:         PetscInt c, r, k;
5638:         PetscInt dof;

5640:         PetscSectionGetDof(section,b,&dof);
5641:         if (!dof) {
5642:           continue;
5643:         }
5644:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5645:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5646:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5648:           for (r = 0; r < numIndices; r++) {
5649:             for (c = 0; c < nCols; c++) {
5650:               for (k = 0; k < dof; k++) {
5651:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5652:               }
5653:             }
5654:           }
5655:         }
5656:         else {
5657:           /* copy this column as is */
5658:           for (r = 0; r < numIndices; r++) {
5659:             for (c = 0; c < dof; c++) {
5660:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5661:             }
5662:           }
5663:         }
5664:         oldOff += dof;
5665:       }
5666:     }

5668:     if (multiplyLeft) {
5669:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5670:       PetscArrayzero(newValues,newNumIndices*newNumIndices);
5671:       /* multiply constraints transpose on the left */
5672:       if (numFields) {
5673:         for (f = 0; f < numFields; f++) {
5674:           PetscInt oldOff = offsets[f];

5676:           for (p = 0; p < numPoints; p++) {
5677:             PetscInt rStart = newPointOffsets[f][p];
5678:             PetscInt b      = points[2 * p];
5679:             PetscInt c, r, k;
5680:             PetscInt dof;

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

5687:               for (r = 0; r < nRows; r++) {
5688:                 for (c = 0; c < newNumIndices; c++) {
5689:                   for (k = 0; k < dof; k++) {
5690:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5691:                   }
5692:                 }
5693:               }
5694:             }
5695:             else {
5696:               /* copy this row as is */
5697:               for (r = 0; r < dof; r++) {
5698:                 for (c = 0; c < newNumIndices; c++) {
5699:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5700:                 }
5701:               }
5702:             }
5703:             oldOff += dof;
5704:           }
5705:         }
5706:       }
5707:       else {
5708:         PetscInt oldOff = 0;

5710:         for (p = 0; p < numPoints; p++) {
5711:           PetscInt rStart = newPointOffsets[0][p];
5712:           PetscInt b      = points[2 * p];
5713:           PetscInt c, r, k;
5714:           PetscInt dof;

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

5721:             for (r = 0; r < nRows; r++) {
5722:               for (c = 0; c < newNumIndices; c++) {
5723:                 for (k = 0; k < dof; k++) {
5724:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5725:                 }
5726:               }
5727:             }
5728:           }
5729:           else {
5730:             /* copy this row as is */
5731:             for (r = 0; r < dof; r++) {
5732:               for (c = 0; c < newNumIndices; c++) {
5733:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5734:               }
5735:             }
5736:           }
5737:           oldOff += dof;
5738:         }
5739:       }

5741:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5742:     }
5743:     else {
5744:       newValues = tmpValues;
5745:     }
5746:   }

5748:   /* clean up */
5749:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5750:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5752:   if (numFields) {
5753:     for (f = 0; f < numFields; f++) {
5754:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5755:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5756:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5757:     }
5758:   }
5759:   else {
5760:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5761:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5762:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5763:   }
5764:   ISRestoreIndices(aIS,&anchors);

5766:   /* output */
5767:   if (outPoints) {
5768:     *outPoints = newPoints;
5769:   }
5770:   else {
5771:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5772:   }
5773:   if (outValues) {
5774:     *outValues = newValues;
5775:   }
5776:   for (f = 0; f <= numFields; f++) {
5777:     offsets[f] = newOffsets[f];
5778:   }
5779:   return(0);
5780: }

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

5785:   Not collective

5787:   Input Parameters:
5788: + dm - The DM
5789: . section - The section describing the local layout
5790: . globalSection - The section describing the parallel layout
5791: - point - The mesh point

5793:   Output parameters:
5794: + numIndices - The number of indices
5795: . indices - The indices
5796: - outOffsets - Field offset if not NULL

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

5800:   Level: advanced

5802: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5803: @*/
5804: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5805: {
5806:   PetscSection    clSection;
5807:   IS              clPoints;
5808:   const PetscInt *clp, *clperm;
5809:   const PetscInt  **perms[32] = {NULL};
5810:   PetscInt       *points = NULL, *pointsNew;
5811:   PetscInt        numPoints, numPointsNew;
5812:   PetscInt        offsets[32];
5813:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5814:   PetscErrorCode  ierr;

5822:   PetscSectionGetNumFields(section, &Nf);
5823:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5824:   PetscArrayzero(offsets, 32);
5825:   /* Get points in closure */
5826:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5827:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5828:   /* Get number of indices and indices per field */
5829:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5830:     PetscInt dof, fdof;

5832:     PetscSectionGetDof(section, points[p], &dof);
5833:     for (f = 0; f < Nf; ++f) {
5834:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5835:       offsets[f+1] += fdof;
5836:     }
5837:     Nind += dof;
5838:   }
5839:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5840:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5841:   if (!Nf) offsets[1] = Nind;
5842:   /* Get dual space symmetries */
5843:   for (f = 0; f < PetscMax(1,Nf); f++) {
5844:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5845:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5846:   }
5847:   /* Correct for hanging node constraints */
5848:   {
5849:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5850:     if (numPointsNew) {
5851:       for (f = 0; f < PetscMax(1,Nf); f++) {
5852:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5853:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5854:       }
5855:       for (f = 0; f < PetscMax(1,Nf); f++) {
5856:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5857:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5858:       }
5859:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5860:       numPoints = numPointsNew;
5861:       Nind      = NindNew;
5862:       points    = pointsNew;
5863:     }
5864:   }
5865:   /* Calculate indices */
5866:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5867:   if (Nf) {
5868:     if (outOffsets) {
5869:       PetscInt f;

5871:       for (f = 0; f <= Nf; f++) {
5872:         outOffsets[f] = offsets[f];
5873:       }
5874:     }
5875:     for (p = 0; p < numPoints; p++) {
5876:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5877:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);
5878:     }
5879:   } else {
5880:     for (p = 0, off = 0; p < numPoints; p++) {
5881:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5883:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5884:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);
5885:     }
5886:   }
5887:   /* Cleanup points */
5888:   for (f = 0; f < PetscMax(1,Nf); f++) {
5889:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5890:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5891:   }
5892:   if (numPointsNew) {
5893:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5894:   } else {
5895:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5896:   }
5897:   if (numIndices) *numIndices = Nind;
5898:   return(0);
5899: }

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

5904:   Not collective

5906:   Input Parameters:
5907: + dm - The DM
5908: . section - The section describing the layout in v, or NULL to use the default section
5909: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5910: . point - The mesh point
5911: . numIndices - The number of indices
5912: . indices - The indices
5913: - outOffsets - Field offset if not NULL

5915:   Level: advanced

5917: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5918: @*/
5919: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5920: {

5926:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5927:   return(0);
5928: }

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

5933:   Not collective

5935:   Input Parameters:
5936: + dm - The DM
5937: . section - The section describing the layout in v, or NULL to use the default section
5938: . globalSection - The section describing the layout in v, or NULL to use the default global section
5939: . A - The matrix
5940: . point - The point in the DM
5941: . values - The array of values
5942: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5947:   Level: intermediate

5949: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5950: @*/
5951: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5952: {
5953:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5954:   PetscSection        clSection;
5955:   IS                  clPoints;
5956:   PetscInt           *points = NULL, *newPoints;
5957:   const PetscInt     *clp, *clperm;
5958:   PetscInt           *indices;
5959:   PetscInt            offsets[32];
5960:   const PetscInt    **perms[32] = {NULL};
5961:   const PetscScalar **flips[32] = {NULL};
5962:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5963:   PetscScalar        *valCopy = NULL;
5964:   PetscScalar        *newValues;
5965:   PetscErrorCode      ierr;

5969:   if (!section) {DMGetLocalSection(dm, &section);}
5971:   if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5974:   PetscSectionGetNumFields(section, &numFields);
5975:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5976:   PetscArrayzero(offsets, 32);
5977:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5978:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5979:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5980:     PetscInt fdof;

5982:     PetscSectionGetDof(section, points[p], &dof);
5983:     for (f = 0; f < numFields; ++f) {
5984:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5985:       offsets[f+1] += fdof;
5986:     }
5987:     numIndices += dof;
5988:   }
5989:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

6003:         if (!numFields) {
6004:           PetscSectionGetDof(section,point,&fdof);
6005:         } else {
6006:           PetscSectionGetFieldDof(section,point,f,&fdof);
6007:         }
6008:         if (flip) {
6009:           PetscInt i, j, k;

6011:           if (!valCopy) {
6012:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6013:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
6014:             values = valCopy;
6015:           }
6016:           for (i = 0; i < fdof; i++) {
6017:             PetscScalar fval = flip[i];

6019:             for (k = 0; k < numIndices; k++) {
6020:               valCopy[numIndices * (foffset + i) + k] *= fval;
6021:               valCopy[numIndices * k + (foffset + i)] *= fval;
6022:             }
6023:           }
6024:         }
6025:         foffset += fdof;
6026:       }
6027:     }
6028:   }
6029:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
6030:   if (newNumPoints) {
6031:     if (valCopy) {
6032:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6033:     }
6034:     for (f = 0; f < PetscMax(1,numFields); f++) {
6035:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6036:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6037:     }
6038:     for (f = 0; f < PetscMax(1,numFields); f++) {
6039:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
6040:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
6041:     }
6042:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6043:     numPoints  = newNumPoints;
6044:     numIndices = newNumIndices;
6045:     points     = newPoints;
6046:     values     = newValues;
6047:   }
6048:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
6049:   if (numFields) {
6050:     PetscBool useFieldOffsets;

6052:     PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
6053:     if (useFieldOffsets) {
6054:       for (p = 0; p < numPoints; p++) {
6055:         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices);
6056:       }
6057:     } else {
6058:       for (p = 0; p < numPoints; p++) {
6059:         PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6060:         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);
6061:       }
6062:     }
6063:   } else {
6064:     for (p = 0, off = 0; p < numPoints; p++) {
6065:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
6066:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6067:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);
6068:     }
6069:   }
6070:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
6071:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6072:   if (mesh->printFEM > 1) {
6073:     PetscInt i;
6074:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
6075:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
6076:     PetscPrintf(PETSC_COMM_SELF, "\n");
6077:   }
6078:   if (ierr) {
6079:     PetscMPIInt    rank;
6080:     PetscErrorCode ierr2;

6082:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6083:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6084:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
6085:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
6086: 
6087:   }
6088:   for (f = 0; f < PetscMax(1,numFields); f++) {
6089:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6090:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6091:   }
6092:   if (newNumPoints) {
6093:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
6094:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
6095:   }
6096:   else {
6097:     if (valCopy) {
6098:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6099:     }
6100:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6101:   }
6102:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
6103:   return(0);
6104: }

6106: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6107: {
6108:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
6109:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
6110:   PetscInt       *cpoints = NULL;
6111:   PetscInt       *findices, *cindices;
6112:   const PetscInt *fclperm, *cclperm;
6113:   PetscInt        foffsets[32], coffsets[32];
6114:   CellRefiner     cellRefiner;
6115:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6116:   PetscErrorCode  ierr;

6121:   if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6123:   if (!csection) {DMGetLocalSection(dmc, &csection);}
6125:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6127:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6130:   PetscSectionGetNumFields(fsection, &numFields);
6131:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6132:   PetscArrayzero(foffsets, 32);
6133:   PetscArrayzero(coffsets, 32);
6134:   PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6135:   PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6136:   /* Column indices */
6137:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6138:   maxFPoints = numCPoints;
6139:   /* Compress out points not in the section */
6140:   /*   TODO: Squeeze out points with 0 dof as well */
6141:   PetscSectionGetChart(csection, &pStart, &pEnd);
6142:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6143:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6144:       cpoints[q*2]   = cpoints[p];
6145:       cpoints[q*2+1] = cpoints[p+1];
6146:       ++q;
6147:     }
6148:   }
6149:   numCPoints = q;
6150:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6151:     PetscInt fdof;

6153:     PetscSectionGetDof(csection, cpoints[p], &dof);
6154:     if (!dof) continue;
6155:     for (f = 0; f < numFields; ++f) {
6156:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6157:       coffsets[f+1] += fdof;
6158:     }
6159:     numCIndices += dof;
6160:   }
6161:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6162:   /* Row indices */
6163:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6164:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6165:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6166:   for (r = 0, q = 0; r < numSubcells; ++r) {
6167:     /* TODO Map from coarse to fine cells */
6168:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6169:     /* Compress out points not in the section */
6170:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6171:     for (p = 0; p < numFPoints*2; p += 2) {
6172:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6173:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6174:         if (!dof) continue;
6175:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6176:         if (s < q) continue;
6177:         ftotpoints[q*2]   = fpoints[p];
6178:         ftotpoints[q*2+1] = fpoints[p+1];
6179:         ++q;
6180:       }
6181:     }
6182:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6183:   }
6184:   numFPoints = q;
6185:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6186:     PetscInt fdof;

6188:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6189:     if (!dof) continue;
6190:     for (f = 0; f < numFields; ++f) {
6191:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6192:       foffsets[f+1] += fdof;
6193:     }
6194:     numFIndices += dof;
6195:   }
6196:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

6198:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6199:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6200:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6201:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6202:   if (numFields) {
6203:     const PetscInt **permsF[32] = {NULL};
6204:     const PetscInt **permsC[32] = {NULL};

6206:     for (f = 0; f < numFields; f++) {
6207:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6208:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6209:     }
6210:     for (p = 0; p < numFPoints; p++) {
6211:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6212:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6213:     }
6214:     for (p = 0; p < numCPoints; p++) {
6215:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6216:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6217:     }
6218:     for (f = 0; f < numFields; f++) {
6219:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6220:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6221:     }
6222:   } else {
6223:     const PetscInt **permsF = NULL;
6224:     const PetscInt **permsC = NULL;

6226:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6227:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6228:     for (p = 0, off = 0; p < numFPoints; p++) {
6229:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6231:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6232:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6233:     }
6234:     for (p = 0, off = 0; p < numCPoints; p++) {
6235:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6237:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6238:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6239:     }
6240:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6241:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6242:   }
6243:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
6244:   /* TODO: flips */
6245:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6246:   if (ierr) {
6247:     PetscMPIInt    rank;
6248:     PetscErrorCode ierr2;

6250:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6251:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6252:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6253:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6254:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6255: 
6256:   }
6257:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6258:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6259:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6260:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6261:   return(0);
6262: }

6264: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6265: {
6266:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6267:   PetscInt      *cpoints = NULL;
6268:   PetscInt       foffsets[32], coffsets[32];
6269:   const PetscInt *fclperm, *cclperm;
6270:   CellRefiner    cellRefiner;
6271:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

6277:   if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6279:   if (!csection) {DMGetLocalSection(dmc, &csection);}
6281:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6283:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6285:   PetscSectionGetNumFields(fsection, &numFields);
6286:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6287:   PetscArrayzero(foffsets, 32);
6288:   PetscArrayzero(coffsets, 32);
6289:   PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6290:   PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6291:   /* Column indices */
6292:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6293:   maxFPoints = numCPoints;
6294:   /* Compress out points not in the section */
6295:   /*   TODO: Squeeze out points with 0 dof as well */
6296:   PetscSectionGetChart(csection, &pStart, &pEnd);
6297:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6298:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6299:       cpoints[q*2]   = cpoints[p];
6300:       cpoints[q*2+1] = cpoints[p+1];
6301:       ++q;
6302:     }
6303:   }
6304:   numCPoints = q;
6305:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6306:     PetscInt fdof;

6308:     PetscSectionGetDof(csection, cpoints[p], &dof);
6309:     if (!dof) continue;
6310:     for (f = 0; f < numFields; ++f) {
6311:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6312:       coffsets[f+1] += fdof;
6313:     }
6314:     numCIndices += dof;
6315:   }
6316:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6317:   /* Row indices */
6318:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6319:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6320:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6321:   for (r = 0, q = 0; r < numSubcells; ++r) {
6322:     /* TODO Map from coarse to fine cells */
6323:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6324:     /* Compress out points not in the section */
6325:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6326:     for (p = 0; p < numFPoints*2; p += 2) {
6327:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6328:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6329:         if (!dof) continue;
6330:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6331:         if (s < q) continue;
6332:         ftotpoints[q*2]   = fpoints[p];
6333:         ftotpoints[q*2+1] = fpoints[p+1];
6334:         ++q;
6335:       }
6336:     }
6337:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6338:   }
6339:   numFPoints = q;
6340:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6341:     PetscInt fdof;

6343:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6344:     if (!dof) continue;
6345:     for (f = 0; f < numFields; ++f) {
6346:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6347:       foffsets[f+1] += fdof;
6348:     }
6349:     numFIndices += dof;
6350:   }
6351:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

6359:     for (f = 0; f < numFields; f++) {
6360:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6361:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6362:     }
6363:     for (p = 0; p < numFPoints; p++) {
6364:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6365:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6366:     }
6367:     for (p = 0; p < numCPoints; p++) {
6368:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6369:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6370:     }
6371:     for (f = 0; f < numFields; f++) {
6372:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6373:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6374:     }
6375:   } else {
6376:     const PetscInt **permsF = NULL;
6377:     const PetscInt **permsC = NULL;

6379:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6380:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6381:     for (p = 0, off = 0; p < numFPoints; p++) {
6382:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6384:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6385:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6386:     }
6387:     for (p = 0, off = 0; p < numCPoints; p++) {
6388:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6390:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6391:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6392:     }
6393:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6394:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6395:   }
6396:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6397:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6398:   return(0);
6399: }

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

6404:   Input Parameter:
6405: . dm - The DMPlex object

6407:   Output Parameters:
6408: + cMax - The first hybrid cell
6409: . fMax - The first hybrid face
6410: . eMax - The first hybrid edge
6411: - vMax - The first hybrid vertex

6413:   Level: developer

6415: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6416: @*/
6417: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6418: {
6419:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6420:   PetscInt       dim;

6425:   DMGetDimension(dm, &dim);
6426:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6427:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6428:   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6429:   if (eMax) *eMax = mesh->hybridPointMax[1];
6430:   if (vMax) *vMax = mesh->hybridPointMax[0];
6431:   return(0);
6432: }

6434: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6435: {
6436:   IS             is, his;
6437:   PetscInt       first = 0, stride;
6438:   PetscBool      isStride;

6442:   DMLabelGetStratumIS(depthLabel, d, &is);
6443:   PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6444:   if (isStride) {
6445:     ISStrideGetInfo(is, &first, &stride);
6446:   }
6447:   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6448:   ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6449:   DMLabelSetStratumIS(dimLabel, d, his);
6450:   ISDestroy(&his);
6451:   ISDestroy(&is);
6452:   return(0);
6453: }

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

6458:   Input Parameters:
6459: + dm   - The DMPlex object
6460: . cMax - The first hybrid cell
6461: . fMax - The first hybrid face
6462: . eMax - The first hybrid edge
6463: - vMax - The first hybrid vertex

6465:   Level: developer

6467: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6468: @*/
6469: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6470: {
6471:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6472:   PetscInt       dim;

6477:   DMGetDimension(dm, &dim);
6478:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6479:   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6480:   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6481:   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6482:   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6483:   return(0);
6484: }

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

6489:   Input Parameter:
6490: . dm   - The DMPlex object

6492:   Output Parameter:
6493: . cellHeight - The height of a cell

6495:   Level: developer

6497: .seealso DMPlexSetVTKCellHeight()
6498: @*/
6499: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6500: {
6501:   DM_Plex *mesh = (DM_Plex*) dm->data;

6506:   *cellHeight = mesh->vtkCellHeight;
6507:   return(0);
6508: }

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

6513:   Input Parameters:
6514: + dm   - The DMPlex object
6515: - cellHeight - The height of a cell

6517:   Level: developer

6519: .seealso DMPlexGetVTKCellHeight()
6520: @*/
6521: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6522: {
6523:   DM_Plex *mesh = (DM_Plex*) dm->data;

6527:   mesh->vtkCellHeight = cellHeight;
6528:   return(0);
6529: }

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

6534:   Input Parameter:
6535: . dm - The DMPlex object

6537:   Output Parameters:
6538: + gcStart - The first ghost cell, or NULL
6539: - gcEnd   - The upper bound on ghost cells, or NULL

6541:   Level: advanced

6543: .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds()
6544: @*/
6545: PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
6546: {
6547:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6548:   PetscInt       dim;

6553:   DMGetDimension(dm, &dim);
6554:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6556:   if (gcEnd)   {
6558:     if (mesh->ghostCellStart >= 0) {DMPlexGetHeightStratum(dm, 0, NULL, gcEnd);}
6559:     else                           {*gcEnd = -1;}
6560:   }
6561:   return(0);
6562: }

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

6567:   Input Parameters:
6568: + dm      - The DMPlex object
6569: . gcStart - The first ghost cell, or PETSC_DETERMINE
6570: - gcEnd   - The upper bound on ghost cells, or PETSC_DETERMINE

6572:   Level: advanced

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

6576: .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum(), DMPlexSetHybridBounds()
6577: @*/
6578: PetscErrorCode DMPlexSetGhostCellStratum(DM dm, PetscInt gcStart, PetscInt gcEnd)
6579: {
6580:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6581:   PetscInt       dim;

6586:   DMGetDimension(dm, &dim);
6587:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6588:   mesh->ghostCellStart = gcStart;
6589:   if (gcEnd >= 0) {
6590:     PetscInt cEnd;
6591:     DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);
6592:     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);
6593:   }
6594:   return(0);
6595: }

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

6600:   Input Parameter:
6601: . dm - The DMPlex object

6603:   Output Parameters:
6604: + cStartInterior - The first ghost cell
6605: - cEndInterior   - The upper bound on ghost cells

6607:   Level: developer

6609: .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds()
6610: @*/
6611: PetscErrorCode DMPlexGetInteriorCellStratum(DM dm, PetscInt *cStartInterior, PetscInt *cEndInterior)
6612: {
6613:   PetscInt       gcEnd, cMax;

6617:   DMPlexGetHeightStratum(dm, 0, cStartInterior, cEndInterior);
6618:   DMPlexGetGhostCellStratum(dm, &gcEnd, NULL);
6619:   *cEndInterior = gcEnd < 0 ? *cEndInterior : gcEnd;
6620:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6621:   *cEndInterior = cMax  < 0 ? *cEndInterior : cMax;
6622:   return(0);
6623: }

6625: /* We can easily have a form that takes an IS instead */
6626: PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6627: {
6628:   PetscSection   section, globalSection;
6629:   PetscInt      *numbers, p;

6633:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6634:   PetscSectionSetChart(section, pStart, pEnd);
6635:   for (p = pStart; p < pEnd; ++p) {
6636:     PetscSectionSetDof(section, p, 1);
6637:   }
6638:   PetscSectionSetUp(section);
6639:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6640:   PetscMalloc1(pEnd - pStart, &numbers);
6641:   for (p = pStart; p < pEnd; ++p) {
6642:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6643:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6644:     else                       numbers[p-pStart] += shift;
6645:   }
6646:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6647:   if (globalSize) {
6648:     PetscLayout layout;
6649:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6650:     PetscLayoutGetSize(layout, globalSize);
6651:     PetscLayoutDestroy(&layout);
6652:   }
6653:   PetscSectionDestroy(&section);
6654:   PetscSectionDestroy(&globalSection);
6655:   return(0);
6656: }

6658: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6659: {
6660:   PetscInt       cellHeight, cStart, cEnd, cMax;

6664:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6665:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6666:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6667:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6668:   DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6669:   return(0);
6670: }

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

6675:   Input Parameter:
6676: . dm   - The DMPlex object

6678:   Output Parameter:
6679: . globalCellNumbers - Global cell numbers for all cells on this process

6681:   Level: developer

6683: .seealso DMPlexGetVertexNumbering()
6684: @*/
6685: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6686: {
6687:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6692:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6693:   *globalCellNumbers = mesh->globalCellNumbers;
6694:   return(0);
6695: }

6697: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6698: {
6699:   PetscInt       vStart, vEnd, vMax;

6704:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6705:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6706:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6707:   DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6708:   return(0);
6709: }

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

6714:   Input Parameter:
6715: . dm   - The DMPlex object

6717:   Output Parameter:
6718: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6720:   Level: developer

6722: .seealso DMPlexGetCellNumbering()
6723: @*/
6724: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6725: {
6726:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6731:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6732:   *globalVertexNumbers = mesh->globalVertexNumbers;
6733:   return(0);
6734: }

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

6739:   Input Parameter:
6740: . dm   - The DMPlex object

6742:   Output Parameter:
6743: . globalPointNumbers - Global numbers for all points on this process

6745:   Level: developer

6747: .seealso DMPlexGetCellNumbering()
6748: @*/
6749: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6750: {
6751:   IS             nums[4];
6752:   PetscInt       depths[4], gdepths[4], starts[4];
6753:   PetscInt       depth, d, shift = 0;

6758:   DMPlexGetDepth(dm, &depth);
6759:   /* For unstratified meshes use dim instead of depth */
6760:   if (depth < 0) {DMGetDimension(dm, &depth);}
6761:   for (d = 0; d <= depth; ++d) {
6762:     PetscInt end;

6764:     depths[d] = depth-d;
6765:     DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6766:     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6767:   }
6768:   PetscSortIntWithArray(depth+1, starts, depths);
6769:   MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6770:   for (d = 0; d <= depth; ++d) {
6771:     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6772:   }
6773:   for (d = 0; d <= depth; ++d) {
6774:     PetscInt pStart, pEnd, gsize;

6776:     DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6777:     DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6778:     shift += gsize;
6779:   }
6780:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6781:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6782:   return(0);
6783: }


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

6789:   Input Parameter:
6790: . dm - The DMPlex object

6792:   Output Parameter:
6793: . ranks - The rank field

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

6798:   Level: intermediate

6800: .seealso: DMView()
6801: @*/
6802: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6803: {
6804:   DM             rdm;
6805:   PetscFE        fe;
6806:   PetscScalar   *r;
6807:   PetscMPIInt    rank;
6808:   PetscInt       dim, cStart, cEnd, c;

6814:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6815:   DMClone(dm, &rdm);
6816:   DMGetDimension(rdm, &dim);
6817:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6818:   PetscObjectSetName((PetscObject) fe, "rank");
6819:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6820:   PetscFEDestroy(&fe);
6821:   DMCreateDS(rdm);
6822:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6823:   DMCreateGlobalVector(rdm, ranks);
6824:   PetscObjectSetName((PetscObject) *ranks, "partition");
6825:   VecGetArray(*ranks, &r);
6826:   for (c = cStart; c < cEnd; ++c) {
6827:     PetscScalar *lr;

6829:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6830:     *lr = rank;
6831:   }
6832:   VecRestoreArray(*ranks, &r);
6833:   DMDestroy(&rdm);
6834:   return(0);
6835: }

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

6840:   Input Parameters:
6841: + dm    - The DMPlex
6842: - label - The DMLabel

6844:   Output Parameter:
6845: . val - The label value field

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

6850:   Level: intermediate

6852: .seealso: DMView()
6853: @*/
6854: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6855: {
6856:   DM             rdm;
6857:   PetscFE        fe;
6858:   PetscScalar   *v;
6859:   PetscInt       dim, cStart, cEnd, c;

6866:   DMClone(dm, &rdm);
6867:   DMGetDimension(rdm, &dim);
6868:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6869:   PetscObjectSetName((PetscObject) fe, "label_value");
6870:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6871:   PetscFEDestroy(&fe);
6872:   DMCreateDS(rdm);
6873:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6874:   DMCreateGlobalVector(rdm, val);
6875:   PetscObjectSetName((PetscObject) *val, "label_value");
6876:   VecGetArray(*val, &v);
6877:   for (c = cStart; c < cEnd; ++c) {
6878:     PetscScalar *lv;
6879:     PetscInt     cval;

6881:     DMPlexPointGlobalRef(rdm, c, v, &lv);
6882:     DMLabelGetValue(label, c, &cval);
6883:     *lv = cval;
6884:   }
6885:   VecRestoreArray(*val, &v);
6886:   DMDestroy(&rdm);
6887:   return(0);
6888: }

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

6893:   Input Parameter:
6894: . dm - The DMPlex object

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

6898:   Level: developer

6900: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6901: @*/
6902: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6903: {
6904:   PetscSection    coneSection, supportSection;
6905:   const PetscInt *cone, *support;
6906:   PetscInt        coneSize, c, supportSize, s;
6907:   PetscInt        pStart, pEnd, p, pp, csize, ssize;
6908:   PetscBool       storagecheck = PETSC_TRUE;
6909:   PetscErrorCode  ierr;

6913:   DMPlexGetConeSection(dm, &coneSection);
6914:   DMPlexGetSupportSection(dm, &supportSection);
6915:   /* Check that point p is found in the support of its cone points, and vice versa */
6916:   DMPlexGetChart(dm, &pStart, &pEnd);
6917:   for (p = pStart; p < pEnd; ++p) {
6918:     DMPlexGetConeSize(dm, p, &coneSize);
6919:     DMPlexGetCone(dm, p, &cone);
6920:     for (c = 0; c < coneSize; ++c) {
6921:       PetscBool dup = PETSC_FALSE;
6922:       PetscInt  d;
6923:       for (d = c-1; d >= 0; --d) {
6924:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6925:       }
6926:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6927:       DMPlexGetSupport(dm, cone[c], &support);
6928:       for (s = 0; s < supportSize; ++s) {
6929:         if (support[s] == p) break;
6930:       }
6931:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6932:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6933:         for (s = 0; s < coneSize; ++s) {
6934:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6935:         }
6936:         PetscPrintf(PETSC_COMM_SELF, "\n");
6937:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6938:         for (s = 0; s < supportSize; ++s) {
6939:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6940:         }
6941:         PetscPrintf(PETSC_COMM_SELF, "\n");
6942:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6943:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6944:       }
6945:     }
6946:     DMPlexGetTreeParent(dm, p, &pp, NULL);
6947:     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6948:     DMPlexGetSupportSize(dm, p, &supportSize);
6949:     DMPlexGetSupport(dm, p, &support);
6950:     for (s = 0; s < supportSize; ++s) {
6951:       DMPlexGetConeSize(dm, support[s], &coneSize);
6952:       DMPlexGetCone(dm, support[s], &cone);
6953:       for (c = 0; c < coneSize; ++c) {
6954:         DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
6955:         if (cone[c] != pp) { c = 0; break; }
6956:         if (cone[c] == p) break;
6957:       }
6958:       if (c >= coneSize) {
6959:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6960:         for (c = 0; c < supportSize; ++c) {
6961:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6962:         }
6963:         PetscPrintf(PETSC_COMM_SELF, "\n");
6964:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6965:         for (c = 0; c < coneSize; ++c) {
6966:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6967:         }
6968:         PetscPrintf(PETSC_COMM_SELF, "\n");
6969:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6970:       }
6971:     }
6972:   }
6973:   if (storagecheck) {
6974:     PetscSectionGetStorageSize(coneSection, &csize);
6975:     PetscSectionGetStorageSize(supportSection, &ssize);
6976:     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6977:   }
6978:   return(0);
6979: }

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

6984:   Input Parameters:
6985: + dm - The DMPlex object
6986: - cellHeight - Normally 0

6988:   Note: This is a useful diagnostic when creating meshes programmatically.
6989:   Currently applicable only to homogeneous simplex or tensor meshes.

6991:   Level: developer

6993: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6994: @*/
6995: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
6996: {
6997:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6998:   PetscBool      isSimplex = PETSC_FALSE;

7003:   DMGetDimension(dm, &dim);
7004:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
7005:   if (cStart < cEnd) {
7006:     DMPlexGetConeSize(dm, cStart, &c);
7007:     isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE;
7008:   }
7009:   switch (dim) {
7010:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
7011:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
7012:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
7013:   default:
7014:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
7015:   }
7016:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7017:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
7018:   cMax = cMax >= 0 ? cMax : cEnd;
7019:   for (c = cStart; c < cMax; ++c) {
7020:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

7022:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7023:     for (cl = 0; cl < closureSize*2; cl += 2) {
7024:       const PetscInt p = closure[cl];
7025:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
7026:     }
7027:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7028:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
7029:   }
7030:   for (c = cMax; c < cEnd; ++c) {
7031:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

7033:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7034:     for (cl = 0; cl < closureSize*2; cl += 2) {
7035:       const PetscInt p = closure[cl];
7036:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
7037:     }
7038:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7039:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
7040:   }
7041:   return(0);
7042: }

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

7047:   Input Parameters:
7048: + dm - The DMPlex object
7049: - cellHeight - Normally 0

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

7053:   Level: developer

7055: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
7056: @*/
7057: PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
7058: {
7059:   PetscInt       pMax[4];
7060:   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;

7065:   DMGetDimension(dm, &dim);
7066:   DMPlexGetDepth(dm, &depth);
7067:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7068:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
7069:   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
7070:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
7071:     for (c = cStart; c < cEnd; ++c) {
7072:       const PetscInt *cone, *ornt, *faces;
7073:       PetscInt        numFaces, faceSize, coneSize,f;
7074:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

7076:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
7077:       DMPlexGetConeSize(dm, c, &coneSize);
7078:       DMPlexGetCone(dm, c, &cone);
7079:       DMPlexGetConeOrientation(dm, c, &ornt);
7080:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7081:       for (cl = 0; cl < closureSize*2; cl += 2) {
7082:         const PetscInt p = closure[cl];
7083:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
7084:       }
7085:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
7086:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
7087:       for (f = 0; f < numFaces; ++f) {
7088:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

7090:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
7091:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
7092:           const PetscInt p = fclosure[cl];
7093:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
7094:         }
7095:         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);
7096:         for (v = 0; v < fnumCorners; ++v) {
7097:           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]);
7098:         }
7099:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
7100:       }
7101:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
7102:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7103:     }
7104:   }
7105:   return(0);
7106: }

7108: /*@
7109:   DMPlexCheckGeometry - Check the geometry of mesh cells

7111:   Input Parameter:
7112: . dm - The DMPlex object

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

7116:   Level: developer

7118: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
7119: @*/
7120: PetscErrorCode DMPlexCheckGeometry(DM dm)
7121: {
7122:   PetscReal      detJ, J[9], refVol = 1.0;
7123:   PetscReal      vol;
7124:   PetscInt       dim, depth, d, cStart, cEnd, c, cMax;

7128:   DMGetDimension(dm, &dim);
7129:   DMPlexGetDepth(dm, &depth);
7130:   for (d = 0; d < dim; ++d) refVol *= 2.0;
7131:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7132:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
7133:   cMax = cMax < 0 ? cEnd : cMax;
7134:   for (c = cStart; c < cMax; ++c) {
7135:     DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
7136:     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
7137:     PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
7138:     if (depth > 1) {
7139:       DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
7140:       if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
7141:       PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
7142:     }
7143:   }
7144:   return(0);
7145: }

7147: static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
7148: {
7149:   PetscInt i,l,n;
7150:   const PetscInt *cone;

7154:   *missingPoint = -1;
7155:   DMPlexGetConeSize(dm, p, &n);
7156:   DMPlexGetCone(dm, p, &cone);
7157:   for (i=0; i<n; i++) {
7158:     PetscFindInt(cone[i], npoints, points, &l);
7159:     if (l < 0) {
7160:       *missingPoint = cone[i];
7161:       break;
7162:     }
7163:   }
7164:   return(0);
7165: }

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

7170:   Input Parameters:
7171: . dm - The DMPlex object

7173:   Notes:
7174:   This is mainly intended for debugging/testing purposes.
7175:   It currently checks only meshes with no partition overlapping.

7177:   Level: developer

7179: .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
7180: @*/
7181: PetscErrorCode DMPlexCheckPointSF(DM dm)
7182: {
7183:   PetscSF         sf;
7184:   PetscInt        d,depth,i,nleaves,p,plo,phi,missingPoint;
7185:   const PetscInt *locals;
7186:   PetscErrorCode  ierr;

7190:   DMPlexGetDepth(dm, &depth);
7191:   DMGetPointSF(dm, &sf);
7192:   DMPlexGetOverlap(dm, &d);
7193:   if (d) {
7194:     PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");
7195:     return(0);
7196:   }
7197:   PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);

7199:   /* 1) check there are no faces in 2D, cells in 3D, in interface */
7200:   DMPlexGetVTKCellHeight(dm, &d);
7201:   DMPlexGetHeightStratum(dm, d, &plo, &phi);
7202:   for (i=0; i<nleaves; i++) {
7203:     p = locals[i];
7204:     if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
7205:   }

7207:   /* 2) if some point is in interface, then all its cone points must be also in interface  */
7208:   for (i=0; i<nleaves; i++) {
7209:     p = locals[i];
7210:     DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);
7211:     if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
7212:   }
7213:   return(0);
7214: }

7216: typedef struct cell_stats
7217: {
7218:   PetscReal min, max, sum, squaresum;
7219:   PetscInt  count;
7220: } cell_stats_t;

7222: static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
7223: {
7224:   PetscInt i, N = *len;

7226:   for (i = 0; i < N; i++) {
7227:     cell_stats_t *A = (cell_stats_t *) a;
7228:     cell_stats_t *B = (cell_stats_t *) b;

7230:     B->min = PetscMin(A->min,B->min);
7231:     B->max = PetscMax(A->max,B->max);
7232:     B->sum += A->sum;
7233:     B->squaresum += A->squaresum;
7234:     B->count += A->count;
7235:   }
7236: }

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

7241:   Collective on dm

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

7248:   Note: This is mainly intended for debugging/testing purposes.

7250:   Level: developer

7252: .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
7253: @*/
7254: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
7255: {
7256:   DM             dmCoarse;
7257:   cell_stats_t   stats, globalStats;
7258:   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
7259:   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
7260:   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
7261:   PetscInt       cdim, cStart, cEnd, cMax, c, eStart, eEnd, count = 0;
7262:   PetscMPIInt    rank,size;

7267:   stats.min   = PETSC_MAX_REAL;
7268:   stats.max   = PETSC_MIN_REAL;
7269:   stats.sum   = stats.squaresum = 0.;
7270:   stats.count = 0;

7272:   MPI_Comm_size(comm, &size);
7273:   MPI_Comm_rank(comm, &rank);
7274:   DMGetCoordinateDim(dm,&cdim);
7275:   PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);
7276:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
7277:   DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);
7278:   DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
7279:   cMax = cMax < 0 ? cEnd : cMax;
7280:   for (c = cStart; c < cMax; c++) {
7281:     PetscInt  i;
7282:     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;

7284:     DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
7285:     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
7286:     for (i = 0; i < PetscSqr(cdim); ++i) {
7287:       frobJ    += J[i] * J[i];
7288:       frobInvJ += invJ[i] * invJ[i];
7289:     }
7290:     cond2 = frobJ * frobInvJ;
7291:     cond  = PetscSqrtReal(cond2);

7293:     stats.min        = PetscMin(stats.min,cond);
7294:     stats.max        = PetscMax(stats.max,cond);
7295:     stats.sum       += cond;
7296:     stats.squaresum += cond2;
7297:     stats.count++;
7298:     if (output && cond > limit) {
7299:       PetscSection coordSection;
7300:       Vec          coordsLocal;
7301:       PetscScalar *coords = NULL;
7302:       PetscInt     Nv, d, clSize, cl, *closure = NULL;

7304:       DMGetCoordinatesLocal(dm, &coordsLocal);
7305:       DMGetCoordinateSection(dm, &coordSection);
7306:       DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7307:       PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);
7308:       for (i = 0; i < Nv/cdim; ++i) {
7309:         PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);
7310:         for (d = 0; d < cdim; ++d) {
7311:           if (d > 0) {PetscSynchronizedPrintf(comm, ", ");}
7312:           PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));
7313:         }
7314:         PetscSynchronizedPrintf(comm, ")\n");
7315:       }
7316:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7317:       for (cl = 0; cl < clSize*2; cl += 2) {
7318:         const PetscInt edge = closure[cl];

7320:         if ((edge >= eStart) && (edge < eEnd)) {
7321:           PetscReal len;

7323:           DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);
7324:           PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);
7325:         }
7326:       }
7327:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7328:       DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7329:     }
7330:   }
7331:   if (output) {PetscSynchronizedFlush(comm, NULL);}

7333:   if (size > 1) {
7334:     PetscMPIInt   blockLengths[2] = {4,1};
7335:     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
7336:     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
7337:     MPI_Op        statReduce;

7339:     MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
7340:     MPI_Type_commit(&statType);
7341:     MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
7342:     MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
7343:     MPI_Op_free(&statReduce);
7344:     MPI_Type_free(&statType);
7345:   } else {
7346:     PetscArraycpy(&globalStats,&stats,1);
7347:   }
7348:   if (!rank) {
7349:     count = globalStats.count;
7350:     min   = globalStats.min;
7351:     max   = globalStats.max;
7352:     mean  = globalStats.sum / globalStats.count;
7353:     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
7354:   }

7356:   if (output) {
7357:     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);
7358:   }
7359:   PetscFree2(J,invJ);

7361:   DMGetCoarseDM(dm,&dmCoarse);
7362:   if (dmCoarse) {
7363:     PetscBool isplex;

7365:     PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
7366:     if (isplex) {
7367:       DMPlexCheckCellShape(dmCoarse,output,condLimit);
7368:     }
7369:   }
7370:   return(0);
7371: }

7373: /* Pointwise interpolation
7374:      Just code FEM for now
7375:      u^f = I u^c
7376:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
7377:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
7378:      I_{ij} = psi^f_i phi^c_j
7379: */
7380: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
7381: {
7382:   PetscSection   gsc, gsf;
7383:   PetscInt       m, n;
7384:   void          *ctx;
7385:   DM             cdm;
7386:   PetscBool      regular, ismatis;

7390:   DMGetGlobalSection(dmFine, &gsf);
7391:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7392:   DMGetGlobalSection(dmCoarse, &gsc);
7393:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7395:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
7396:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
7397:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7398:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
7399:   DMGetApplicationContext(dmFine, &ctx);

7401:   DMGetCoarseDM(dmFine, &cdm);
7402:   DMPlexGetRegularRefinement(dmFine, &regular);
7403:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
7404:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
7405:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
7406:   if (scaling) {
7407:     /* Use naive scaling */
7408:     DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
7409:   }
7410:   return(0);
7411: }

7413: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
7414: {
7416:   VecScatter     ctx;

7419:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
7420:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
7421:   VecScatterDestroy(&ctx);
7422:   return(0);
7423: }

7425: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
7426: {
7427:   PetscSection   gsc, gsf;
7428:   PetscInt       m, n;
7429:   void          *ctx;
7430:   DM             cdm;
7431:   PetscBool      regular;

7435:   DMGetGlobalSection(dmFine, &gsf);
7436:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7437:   DMGetGlobalSection(dmCoarse, &gsc);
7438:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7440:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
7441:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7442:   MatSetType(*mass, dmCoarse->mattype);
7443:   DMGetApplicationContext(dmFine, &ctx);

7445:   DMGetCoarseDM(dmFine, &cdm);
7446:   DMPlexGetRegularRefinement(dmFine, &regular);
7447:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
7448:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
7449:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
7450:   return(0);
7451: }

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

7456:   Input Parameter:
7457: . dm - The DMPlex object

7459:   Output Parameter:
7460: . regular - The flag

7462:   Level: intermediate

7464: .seealso: DMPlexSetRegularRefinement()
7465: @*/
7466: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7467: {
7471:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7472:   return(0);
7473: }

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

7478:   Input Parameters:
7479: + dm - The DMPlex object
7480: - regular - The flag

7482:   Level: intermediate

7484: .seealso: DMPlexGetRegularRefinement()
7485: @*/
7486: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7487: {
7490:   ((DM_Plex *) dm->data)->regularRefinement = regular;
7491:   return(0);
7492: }

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

7499:   not collective

7501:   Input Parameters:
7502: . dm - The DMPlex object

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


7509:   Level: intermediate

7511: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7512: @*/
7513: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7514: {
7515:   DM_Plex *plex = (DM_Plex *)dm->data;

7520:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7521:   if (anchorSection) *anchorSection = plex->anchorSection;
7522:   if (anchorIS) *anchorIS = plex->anchorIS;
7523:   return(0);
7524: }

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

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

7534:   collective on dm

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

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

7543:   Level: intermediate

7545: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7546: @*/
7547: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7548: {
7549:   DM_Plex        *plex = (DM_Plex *)dm->data;
7550:   PetscMPIInt    result;

7555:   if (anchorSection) {
7557:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7558:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7559:   }
7560:   if (anchorIS) {
7562:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7563:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7564:   }

7566:   PetscObjectReference((PetscObject)anchorSection);
7567:   PetscSectionDestroy(&plex->anchorSection);
7568:   plex->anchorSection = anchorSection;

7570:   PetscObjectReference((PetscObject)anchorIS);
7571:   ISDestroy(&plex->anchorIS);
7572:   plex->anchorIS = anchorIS;

7574: #if defined(PETSC_USE_DEBUG)
7575:   if (anchorIS && anchorSection) {
7576:     PetscInt size, a, pStart, pEnd;
7577:     const PetscInt *anchors;

7579:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7580:     ISGetLocalSize(anchorIS,&size);
7581:     ISGetIndices(anchorIS,&anchors);
7582:     for (a = 0; a < size; a++) {
7583:       PetscInt p;

7585:       p = anchors[a];
7586:       if (p >= pStart && p < pEnd) {
7587:         PetscInt dof;

7589:         PetscSectionGetDof(anchorSection,p,&dof);
7590:         if (dof) {
7591:           PetscErrorCode ierr2;

7593:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7594:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7595:         }
7596:       }
7597:     }
7598:     ISRestoreIndices(anchorIS,&anchors);
7599:   }
7600: #endif
7601:   /* reset the generic constraints */
7602:   DMSetDefaultConstraints(dm,NULL,NULL);
7603:   return(0);
7604: }

7606: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7607: {
7608:   PetscSection anchorSection;
7609:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

7614:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7615:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
7616:   PetscSectionGetNumFields(section,&numFields);
7617:   if (numFields) {
7618:     PetscInt f;
7619:     PetscSectionSetNumFields(*cSec,numFields);

7621:     for (f = 0; f < numFields; f++) {
7622:       PetscInt numComp;

7624:       PetscSectionGetFieldComponents(section,f,&numComp);
7625:       PetscSectionSetFieldComponents(*cSec,f,numComp);
7626:     }
7627:   }
7628:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7629:   PetscSectionGetChart(section,&sStart,&sEnd);
7630:   pStart = PetscMax(pStart,sStart);
7631:   pEnd   = PetscMin(pEnd,sEnd);
7632:   pEnd   = PetscMax(pStart,pEnd);
7633:   PetscSectionSetChart(*cSec,pStart,pEnd);
7634:   for (p = pStart; p < pEnd; p++) {
7635:     PetscSectionGetDof(anchorSection,p,&dof);
7636:     if (dof) {
7637:       PetscSectionGetDof(section,p,&dof);
7638:       PetscSectionSetDof(*cSec,p,dof);
7639:       for (f = 0; f < numFields; f++) {
7640:         PetscSectionGetFieldDof(section,p,f,&dof);
7641:         PetscSectionSetFieldDof(*cSec,p,f,dof);
7642:       }
7643:     }
7644:   }
7645:   PetscSectionSetUp(*cSec);
7646:   return(0);
7647: }

7649: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7650: {
7651:   PetscSection aSec;
7652:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7653:   const PetscInt *anchors;
7654:   PetscInt numFields, f;
7655:   IS aIS;

7660:   PetscSectionGetStorageSize(cSec, &m);
7661:   PetscSectionGetStorageSize(section, &n);
7662:   MatCreate(PETSC_COMM_SELF,cMat);
7663:   MatSetSizes(*cMat,m,n,m,n);
7664:   MatSetType(*cMat,MATSEQAIJ);
7665:   DMPlexGetAnchors(dm,&aSec,&aIS);
7666:   ISGetIndices(aIS,&anchors);
7667:   /* cSec will be a subset of aSec and section */
7668:   PetscSectionGetChart(cSec,&pStart,&pEnd);
7669:   PetscMalloc1(m+1,&i);
7670:   i[0] = 0;
7671:   PetscSectionGetNumFields(section,&numFields);
7672:   for (p = pStart; p < pEnd; p++) {
7673:     PetscInt rDof, rOff, r;

7675:     PetscSectionGetDof(aSec,p,&rDof);
7676:     if (!rDof) continue;
7677:     PetscSectionGetOffset(aSec,p,&rOff);
7678:     if (numFields) {
7679:       for (f = 0; f < numFields; f++) {
7680:         annz = 0;
7681:         for (r = 0; r < rDof; r++) {
7682:           a = anchors[rOff + r];
7683:           PetscSectionGetFieldDof(section,a,f,&aDof);
7684:           annz += aDof;
7685:         }
7686:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7687:         PetscSectionGetFieldOffset(cSec,p,f,&off);
7688:         for (q = 0; q < dof; q++) {
7689:           i[off + q + 1] = i[off + q] + annz;
7690:         }
7691:       }
7692:     }
7693:     else {
7694:       annz = 0;
7695:       for (q = 0; q < dof; q++) {
7696:         a = anchors[off + q];
7697:         PetscSectionGetDof(section,a,&aDof);
7698:         annz += aDof;
7699:       }
7700:       PetscSectionGetDof(cSec,p,&dof);
7701:       PetscSectionGetOffset(cSec,p,&off);
7702:       for (q = 0; q < dof; q++) {
7703:         i[off + q + 1] = i[off + q] + annz;
7704:       }
7705:     }
7706:   }
7707:   nnz = i[m];
7708:   PetscMalloc1(nnz,&j);
7709:   offset = 0;
7710:   for (p = pStart; p < pEnd; p++) {
7711:     if (numFields) {
7712:       for (f = 0; f < numFields; f++) {
7713:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7714:         for (q = 0; q < dof; q++) {
7715:           PetscInt rDof, rOff, r;
7716:           PetscSectionGetDof(aSec,p,&rDof);
7717:           PetscSectionGetOffset(aSec,p,&rOff);
7718:           for (r = 0; r < rDof; r++) {
7719:             PetscInt s;

7721:             a = anchors[rOff + r];
7722:             PetscSectionGetFieldDof(section,a,f,&aDof);
7723:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7724:             for (s = 0; s < aDof; s++) {
7725:               j[offset++] = aOff + s;
7726:             }
7727:           }
7728:         }
7729:       }
7730:     }
7731:     else {
7732:       PetscSectionGetDof(cSec,p,&dof);
7733:       for (q = 0; q < dof; q++) {
7734:         PetscInt rDof, rOff, r;
7735:         PetscSectionGetDof(aSec,p,&rDof);
7736:         PetscSectionGetOffset(aSec,p,&rOff);
7737:         for (r = 0; r < rDof; r++) {
7738:           PetscInt s;

7740:           a = anchors[rOff + r];
7741:           PetscSectionGetDof(section,a,&aDof);
7742:           PetscSectionGetOffset(section,a,&aOff);
7743:           for (s = 0; s < aDof; s++) {
7744:             j[offset++] = aOff + s;
7745:           }
7746:         }
7747:       }
7748:     }
7749:   }
7750:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7751:   PetscFree(i);
7752:   PetscFree(j);
7753:   ISRestoreIndices(aIS,&anchors);
7754:   return(0);
7755: }

7757: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7758: {
7759:   DM_Plex        *plex = (DM_Plex *)dm->data;
7760:   PetscSection   anchorSection, section, cSec;
7761:   Mat            cMat;

7766:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7767:   if (anchorSection) {
7768:     PetscInt Nf;

7770:     DMGetLocalSection(dm,&section);
7771:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7772:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7773:     DMGetNumFields(dm,&Nf);
7774:     if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7775:     DMSetDefaultConstraints(dm,cSec,cMat);
7776:     PetscSectionDestroy(&cSec);
7777:     MatDestroy(&cMat);
7778:   }
7779:   return(0);
7780: }

7782: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7783: {
7784:   IS             subis;
7785:   PetscSection   section, subsection;

7789:   DMGetLocalSection(dm, &section);
7790:   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7791:   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7792:   /* Create subdomain */
7793:   DMPlexFilter(dm, label, value, subdm);
7794:   /* Create submodel */
7795:   DMPlexCreateSubpointIS(*subdm, &subis);
7796:   PetscSectionCreateSubmeshSection(section, subis, &subsection);
7797:   ISDestroy(&subis);
7798:   DMSetLocalSection(*subdm, subsection);
7799:   PetscSectionDestroy(&subsection);
7800:   DMCopyDisc(dm, *subdm);
7801:   /* Create map from submodel to global model */
7802:   if (is) {
7803:     PetscSection    sectionGlobal, subsectionGlobal;
7804:     IS              spIS;
7805:     const PetscInt *spmap;
7806:     PetscInt       *subIndices;
7807:     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
7808:     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];

7810:     DMPlexCreateSubpointIS(*subdm, &spIS);
7811:     ISGetIndices(spIS, &spmap);
7812:     PetscSectionGetNumFields(section, &Nf);
7813:     DMGetGlobalSection(dm, &sectionGlobal);
7814:     DMGetGlobalSection(*subdm, &subsectionGlobal);
7815:     PetscSectionGetChart(subsection, &pStart, &pEnd);
7816:     for (p = pStart; p < pEnd; ++p) {
7817:       PetscInt gdof, pSubSize  = 0;

7819:       PetscSectionGetDof(sectionGlobal, p, &gdof);
7820:       if (gdof > 0) {
7821:         for (f = 0; f < Nf; ++f) {
7822:           PetscInt fdof, fcdof;

7824:           PetscSectionGetFieldDof(subsection, p, f, &fdof);
7825:           PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7826:           pSubSize += fdof-fcdof;
7827:         }
7828:         subSize += pSubSize;
7829:         if (pSubSize) {
7830:           if (bs < 0) {
7831:             bs = pSubSize;
7832:           } else if (bs != pSubSize) {
7833:             /* Layout does not admit a pointwise block size */
7834:             bs = 1;
7835:           }
7836:         }
7837:       }
7838:     }
7839:     /* Must have same blocksize on all procs (some might have no points) */
7840:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7841:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7842:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7843:     else                            {bs = bsMinMax[0];}
7844:     PetscMalloc1(subSize, &subIndices);
7845:     for (p = pStart; p < pEnd; ++p) {
7846:       PetscInt gdof, goff;

7848:       PetscSectionGetDof(subsectionGlobal, p, &gdof);
7849:       if (gdof > 0) {
7850:         const PetscInt point = spmap[p];

7852:         PetscSectionGetOffset(sectionGlobal, point, &goff);
7853:         for (f = 0; f < Nf; ++f) {
7854:           PetscInt fdof, fcdof, fc, f2, poff = 0;

7856:           /* Can get rid of this loop by storing field information in the global section */
7857:           for (f2 = 0; f2 < f; ++f2) {
7858:             PetscSectionGetFieldDof(section, p, f2, &fdof);
7859:             PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7860:             poff += fdof-fcdof;
7861:           }
7862:           PetscSectionGetFieldDof(section, p, f, &fdof);
7863:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7864:           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7865:             subIndices[subOff] = goff+poff+fc;
7866:           }
7867:         }
7868:       }
7869:     }
7870:     ISRestoreIndices(spIS, &spmap);
7871:     ISDestroy(&spIS);
7872:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7873:     if (bs > 1) {
7874:       /* We need to check that the block size does not come from non-contiguous fields */
7875:       PetscInt i, j, set = 1;
7876:       for (i = 0; i < subSize; i += bs) {
7877:         for (j = 0; j < bs; ++j) {
7878:           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7879:         }
7880:       }
7881:       if (set) {ISSetBlockSize(*is, bs);}
7882:     }
7883:     /* Attach nullspace */
7884:     for (f = 0; f < Nf; ++f) {
7885:       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7886:       if ((*subdm)->nullspaceConstructors[f]) break;
7887:     }
7888:     if (f < Nf) {
7889:       MatNullSpace nullSpace;

7891:       (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7892:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7893:       MatNullSpaceDestroy(&nullSpace);
7894:     }
7895:   }
7896:   return(0);
7897: }