Actual source code: plex.c

petsc-master 2019-07-18
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, cEndInterior;
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, &cEndInterior, NULL, NULL, NULL);
114:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
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:   DMGetSection(dm, &s);
164:   PetscSectionGetNumFields(s, &Nf);
165:   DMGetCoarsenLevel(dm, &level);
166:   DMGetCoordinateDM(dm, &cdm);
167:   DMGetSection(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:   DMGetSection(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", 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:   DMGetSection(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", 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", 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", 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_SHARED_COMM)
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_SHARED_COMM)
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;
1036:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
1037:     PetscInt    pStart, pEnd, p;
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:     PetscCalloc2(size,&sizes,size,&hybsizes);
1054:     if (depth == 1) {
1055:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
1056:       pEnd = pEnd - pStart;
1057:       pMax[0] -= pStart;
1058:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1059:       MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1060:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
1061:       for (p = 0; p < size; ++p) {
1062:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1063:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1064:       }
1065:       PetscViewerASCIIPrintf(viewer, "\n");
1066:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
1067:       pEnd = pEnd - pStart;
1068:       pMax[depth] -= pStart;
1069:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1070:       MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1071:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
1072:       for (p = 0; p < size; ++p) {
1073:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1074:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1075:       }
1076:       PetscViewerASCIIPrintf(viewer, "\n");
1077:     } else {
1078:       PetscMPIInt rank;
1079:       MPI_Comm_rank(comm, &rank);
1080:       for (d = 0; d <= dim; d++) {
1081:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
1082:         pEnd    -= pStart;
1083:         pMax[d] -= pStart;
1084:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1085:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1086:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
1087:         for (p = 0; p < size; ++p) {
1088:           if (!rank) {
1089:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1090:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1091:           }
1092:         }
1093:         PetscViewerASCIIPrintf(viewer, "\n");
1094:       }
1095:     }
1096:     PetscFree2(sizes,hybsizes);
1097:     DMGetNumLabels(dm, &numLabels);
1098:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
1099:     for (l = 0; l < numLabels; ++l) {
1100:       DMLabel         label;
1101:       const char     *name;
1102:       IS              valueIS;
1103:       const PetscInt *values;
1104:       PetscInt        numValues, v;

1106:       DMGetLabelName(dm, l, &name);
1107:       DMGetLabel(dm, name, &label);
1108:       DMLabelGetNumValues(label, &numValues);
1109:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
1110:       DMLabelGetValueIS(label, &valueIS);
1111:       ISGetIndices(valueIS, &values);
1112:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
1113:       for (v = 0; v < numValues; ++v) {
1114:         PetscInt size;

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

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

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

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

1170:   DMGetCoordinateDim(dm, &dim);
1171:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1172:   DMGetCoordinateDM(dm, &cdm);
1173:   DMGetSection(cdm, &coordSection);
1174:   DMGetCoordinatesLocal(dm, &coordinates);
1175:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1176:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

1178:   PetscViewerDrawGetDraw(viewer, 0, &draw);
1179:   PetscDrawIsNull(draw, &isnull);
1180:   if (isnull) return(0);
1181:   PetscDrawSetTitle(draw, "Mesh");

1183:   VecGetLocalSize(coordinates, &N);
1184:   VecGetArrayRead(coordinates, &coords);
1185:   for (c = 0; c < N; c += dim) {
1186:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1187:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1188:   }
1189:   VecRestoreArrayRead(coordinates, &coords);
1190:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1191:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1192:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1193:   PetscDrawClear(draw);

1195:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1196:   for (c = cStart; c < cEnd; ++c) {
1197:     PetscScalar *coords = NULL;
1198:     PetscInt     numCoords,coneSize;

1200:     DMPlexGetConeSize(dm, c, &coneSize);
1201:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1202:     switch (coneSize) {
1203:     case 3:
1204:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1205:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1206:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1207:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1208:       break;
1209:     case 4:
1210:       PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), 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:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1215:       break;
1216:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1217:     }
1218:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1219:   }
1220:   for (c = cStart; c < cEnd; ++c) {
1221:     PetscScalar *coords = NULL;
1222:     PetscInt     numCoords,coneSize;

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

1248: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1249: {
1250:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1251:   char           name[PETSC_MAX_PATH_LEN];

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

1299:     DMGetLabel(dm, name, &label);
1300:     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1301:     DMPlexCreateLabelField(dm, label, &val);
1302:     VecView(val, viewer);
1303:     VecDestroy(&val);
1304:   }
1305:   return(0);
1306: }

1308: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1309: {
1310:   PetscBool      ishdf5;

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

1335: PetscErrorCode DMDestroy_Plex(DM dm)
1336: {
1337:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1371: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1372: {
1373:   PetscSection           sectionGlobal;
1374:   PetscInt               bs = -1, mbs;
1375:   PetscInt               localSize;
1376:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1377:   PetscErrorCode         ierr;
1378:   MatType                mtype;
1379:   ISLocalToGlobalMapping ltog;

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

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

1412:       DMGetSection(dm, &section);
1413:       PetscSectionGetStorageSize(section, &size);
1414:       PetscMalloc1(size,&ltogidx);
1415:       DMPlexGetSubdomainSection(dm, &subSection);
1416:     } else {
1417:       DMGetLocalToGlobalMapping(dm,&ltog);
1418:     }
1419:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1420:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1421:       PetscInt bdof;

1423:       PetscSectionGetDof(sectionGlobal, p, &dof);
1424:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1425:       dof  = dof < 0 ? -(dof+1) : dof;
1426:       bdof = cdof && (dof-cdof) ? 1 : dof;
1427:       if (dof) {
1428:         if (bs < 0)          {bs = bdof;}
1429:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1430:       }
1431:       if (isMatIS) {
1432:         PetscInt loff,c,off;
1433:         PetscSectionGetOffset(subSection, p, &loff);
1434:         PetscSectionGetOffset(sectionGlobal, p, &off);
1435:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1436:       }
1437:     }
1438:     /* Must have same blocksize on all procs (some might have no points) */
1439:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1440:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1441:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1442:     else                            {bs = bsMinMax[0];}
1443:     bs = bs < 0 ? 1 : bs;
1444:     if (isMatIS) {
1445:       PetscInt l;
1446:       /* Must reduce indices by blocksize */
1447:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1448:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1449:     }
1450:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1451:     if (isMatIS) {
1452:       ISLocalToGlobalMappingDestroy(&ltog);
1453:     }
1454:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1455:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1456:     PetscFree4(dnz, onz, dnzu, onzu);
1457:   }
1458:   MatSetDM(*J, dm);
1459:   return(0);
1460: }

1462: /*@
1463:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1465:   Not collective

1467:   Input Parameter:
1468: . mesh - The DMPlex

1470:   Output Parameters:
1471: . subsection - The subdomain section

1473:   Level: developer

1475: .seealso:
1476: @*/
1477: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1478: {
1479:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1484:   if (!mesh->subdomainSection) {
1485:     PetscSection section;
1486:     PetscSF      sf;

1488:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1489:     DMGetSection(dm,&section);
1490:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1491:     PetscSFDestroy(&sf);
1492:   }
1493:   *subsection = mesh->subdomainSection;
1494:   return(0);
1495: }

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

1500:   Not collective

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

1505:   Output Parameters:
1506: + pStart - The first mesh point
1507: - pEnd   - The upper bound for mesh points

1509:   Level: beginner

1511: .seealso: DMPlexCreate(), DMPlexSetChart()
1512: @*/
1513: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1514: {
1515:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1520:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1521:   return(0);
1522: }

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

1527:   Not collective

1529:   Input Parameters:
1530: + mesh - The DMPlex
1531: . pStart - The first mesh point
1532: - pEnd   - The upper bound for mesh points

1534:   Output Parameters:

1536:   Level: beginner

1538: .seealso: DMPlexCreate(), DMPlexGetChart()
1539: @*/
1540: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1541: {
1542:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1547:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1548:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1549:   return(0);
1550: }

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

1555:   Not collective

1557:   Input Parameters:
1558: + mesh - The DMPlex
1559: - p - The point, which must lie in the chart set with DMPlexSetChart()

1561:   Output Parameter:
1562: . size - The cone size for point p

1564:   Level: beginner

1566: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1567: @*/
1568: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1569: {
1570:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1576:   PetscSectionGetDof(mesh->coneSection, p, size);
1577:   return(0);
1578: }

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

1583:   Not collective

1585:   Input Parameters:
1586: + mesh - The DMPlex
1587: . p - The point, which must lie in the chart set with DMPlexSetChart()
1588: - size - The cone size for point p

1590:   Output Parameter:

1592:   Note:
1593:   This should be called after DMPlexSetChart().

1595:   Level: beginner

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

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

1608:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1609:   return(0);
1610: }

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

1615:   Not collective

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

1622:   Output Parameter:

1624:   Note:
1625:   This should be called after DMPlexSetChart().

1627:   Level: beginner

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

1639:   PetscSectionAddDof(mesh->coneSection, p, size);
1640:   PetscSectionGetDof(mesh->coneSection, p, &csize);

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

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

1649:   Not collective

1651:   Input Parameters:
1652: + dm - The DMPlex
1653: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1658:   Level: beginner

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

1666: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1667: @*/
1668: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1669: {
1670:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1671:   PetscInt       off;

1677:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1678:   *cone = &mesh->cones[off];
1679:   return(0);
1680: }

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

1685:   Not collective

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

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

1695:   Level: intermediate

1697: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1698: @*/
1699: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1700: {
1701:   PetscSection        cs, newcs;
1702:   PetscInt            *cones;
1703:   PetscInt            *newarr=NULL;
1704:   PetscInt            n;
1705:   PetscErrorCode      ierr;

1708:   DMPlexGetCones(dm, &cones);
1709:   DMPlexGetConeSection(dm, &cs);
1710:   PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1711:   if (pConesSection) *pConesSection = newcs;
1712:   if (pCones) {
1713:     PetscSectionGetStorageSize(newcs, &n);
1714:     ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1715:   }
1716:   return(0);
1717: }

1719: static PetscErrorCode DMPlexGetConeRecursive_Private(DM dm, PetscInt *n_inout, const PetscInt points[], PetscInt *offset_inout, PetscInt buf[])
1720: {
1721:   PetscInt p, n, cn, i;
1722:   const PetscInt *cone;

1726:   n = *n_inout;
1727:   *n_inout = 0;
1728:   for (i=0; i<n; i++) {
1729:     p = points[i];
1730:     DMPlexGetConeSize(dm, p, &cn);
1731:     if (!cn) {
1732:       cn = 1;
1733:       if (buf) {
1734:         buf[*offset_inout] = p;
1735:         ++(*offset_inout);
1736:       }
1737:     } else {
1738:       DMPlexGetCone(dm, p, &cone);
1739:       DMPlexGetConeRecursive_Private(dm, &cn, cone, offset_inout, buf);
1740:     }
1741:     *n_inout += cn;
1742:   }
1743:   return(0);
1744: }

1746: /*@C
1747:   DMPlexGetConeRecursive - Like DMPlexGetConeTuple() but recursive, i.e. each cone point is expanded into a set of its own cone points until a vertex (DAG point with no cone) is reached.

1749:   Not collective

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

1755:   Output Parameter:
1756: . pCones - An array of recursively expanded cones, i.e. containing only vertices, and each of them can be present multiple times

1758:   Level: advanced

1760: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple()
1761: @*/
1762: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS p, IS *pCones)
1763: {
1764:   const PetscInt      *arr=NULL;
1765:   PetscInt            *cpoints=NULL;
1766:   PetscInt            n, cn;
1767:   PetscInt            zero;
1768:   PetscErrorCode      ierr;

1771:   ISGetLocalSize(p, &n);
1772:   ISGetIndices(p, &arr);
1773:   zero = 0;
1774:   /* first figure out the total number of returned points */
1775:   cn = n;
1776:   DMPlexGetConeRecursive_Private(dm, &cn, arr, &zero, NULL);
1777:   PetscMalloc1(cn, &cpoints);
1778:   /* now get recursive cones themselves */
1779:   DMPlexGetConeRecursive_Private(dm, &n, arr, &zero, cpoints);
1780:   ISCreateGeneral(PetscObjectComm((PetscObject)p), n, cpoints, PETSC_OWN_POINTER, pCones);
1781:   ISRestoreIndices(p, &arr);
1782:   return(0);
1783: }

1785: /*@
1786:   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

1788:   Not collective

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

1795:   Output Parameter:

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

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

1802:   Level: beginner

1804: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1805: @*/
1806: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1807: {
1808:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1809:   PetscInt       pStart, pEnd;
1810:   PetscInt       dof, off, c;

1815:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1816:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1818:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1819:   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);
1820:   for (c = 0; c < dof; ++c) {
1821:     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);
1822:     mesh->cones[off+c] = cone[c];
1823:   }
1824:   return(0);
1825: }

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

1830:   Not collective

1832:   Input Parameters:
1833: + mesh - The DMPlex
1834: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1842:   Level: beginner

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

1850: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1851: @*/
1852: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1853: {
1854:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1855:   PetscInt       off;

1860: #if defined(PETSC_USE_DEBUG)
1861:   {
1862:     PetscInt dof;
1863:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1865:   }
1866: #endif
1867:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1869:   *coneOrientation = &mesh->coneOrientations[off];
1870:   return(0);
1871: }

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

1876:   Not collective

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

1886:   Output Parameter:

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

1891:   Level: beginner

1893: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1894: @*/
1895: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1896: {
1897:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1898:   PetscInt       pStart, pEnd;
1899:   PetscInt       dof, off, c;

1904:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1905:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1907:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1908:   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);
1909:   for (c = 0; c < dof; ++c) {
1910:     PetscInt cdof, o = coneOrientation[c];

1912:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1913:     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);
1914:     mesh->coneOrientations[off+c] = o;
1915:   }
1916:   return(0);
1917: }

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

1922:   Not collective

1924:   Input Parameters:
1925: + mesh - The DMPlex
1926: . p - The point, which must lie in the chart set with DMPlexSetChart()
1927: . conePos - The local index in the cone where the point should be put
1928: - conePoint - The mesh point to insert

1930:   Level: beginner

1932: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1933: @*/
1934: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1935: {
1936:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1937:   PetscInt       pStart, pEnd;
1938:   PetscInt       dof, off;

1943:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1944:   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);
1945:   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);
1946:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1947:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1948:   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);
1949:   mesh->cones[off+conePos] = conePoint;
1950:   return(0);
1951: }

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

1956:   Not collective

1958:   Input Parameters:
1959: + mesh - The DMPlex
1960: . p - The point, which must lie in the chart set with DMPlexSetChart()
1961: . conePos - The local index in the cone where the point should be put
1962: - coneOrientation - The point orientation to insert

1964:   Level: beginner

1966: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1967: @*/
1968: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1969: {
1970:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1971:   PetscInt       pStart, pEnd;
1972:   PetscInt       dof, off;

1977:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1978:   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);
1979:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1980:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1981:   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);
1982:   mesh->coneOrientations[off+conePos] = coneOrientation;
1983:   return(0);
1984: }

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

1989:   Not collective

1991:   Input Parameters:
1992: + mesh - The DMPlex
1993: - p - The point, which must lie in the chart set with DMPlexSetChart()

1995:   Output Parameter:
1996: . size - The support size for point p

1998:   Level: beginner

2000: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
2001: @*/
2002: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
2003: {
2004:   DM_Plex       *mesh = (DM_Plex*) dm->data;

2010:   PetscSectionGetDof(mesh->supportSection, p, size);
2011:   return(0);
2012: }

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

2017:   Not collective

2019:   Input Parameters:
2020: + mesh - The DMPlex
2021: . p - The point, which must lie in the chart set with DMPlexSetChart()
2022: - size - The support size for point p

2024:   Output Parameter:

2026:   Note:
2027:   This should be called after DMPlexSetChart().

2029:   Level: beginner

2031: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
2032: @*/
2033: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
2034: {
2035:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

2042:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
2043:   return(0);
2044: }

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

2049:   Not collective

2051:   Input Parameters:
2052: + mesh - The DMPlex
2053: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

2058:   Level: beginner

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

2066: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2067: @*/
2068: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
2069: {
2070:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2071:   PetscInt       off;

2077:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2078:   *support = &mesh->supports[off];
2079:   return(0);
2080: }

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

2085:   Not collective

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

2092:   Output Parameter:

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

2097:   Level: beginner

2099: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
2100: @*/
2101: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
2102: {
2103:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2104:   PetscInt       pStart, pEnd;
2105:   PetscInt       dof, off, c;

2110:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2111:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2113:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2114:   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);
2115:   for (c = 0; c < dof; ++c) {
2116:     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);
2117:     mesh->supports[off+c] = support[c];
2118:   }
2119:   return(0);
2120: }

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

2125:   Not collective

2127:   Input Parameters:
2128: + mesh - The DMPlex
2129: . p - The point, which must lie in the chart set with DMPlexSetChart()
2130: . supportPos - The local index in the cone where the point should be put
2131: - supportPoint - The mesh point to insert

2133:   Level: beginner

2135: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2136: @*/
2137: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
2138: {
2139:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2140:   PetscInt       pStart, pEnd;
2141:   PetscInt       dof, off;

2146:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2147:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2148:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2149:   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);
2150:   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);
2151:   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);
2152:   mesh->supports[off+supportPos] = supportPoint;
2153:   return(0);
2154: }

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

2159:   Not collective

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

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

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

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

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

2180:   Level: beginner

2182: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2183: @*/
2184: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2185: {
2186:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2187:   PetscInt       *closure, *fifo;
2188:   const PetscInt *tmp = NULL, *tmpO = NULL;
2189:   PetscInt        tmpSize, t;
2190:   PetscInt        depth       = 0, maxSize;
2191:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2192:   PetscErrorCode  ierr;

2196:   DMPlexGetDepth(dm, &depth);
2197:   /* This is only 1-level */
2198:   if (useCone) {
2199:     DMPlexGetConeSize(dm, p, &tmpSize);
2200:     DMPlexGetCone(dm, p, &tmp);
2201:     DMPlexGetConeOrientation(dm, p, &tmpO);
2202:   } else {
2203:     DMPlexGetSupportSize(dm, p, &tmpSize);
2204:     DMPlexGetSupport(dm, p, &tmp);
2205:   }
2206:   if (depth == 1) {
2207:     if (*points) {
2208:       closure = *points;
2209:     } else {
2210:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2211:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2212:     }
2213:     closure[0] = p; closure[1] = 0;
2214:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2215:       closure[closureSize]   = tmp[t];
2216:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2217:     }
2218:     if (numPoints) *numPoints = closureSize/2;
2219:     if (points)    *points    = closure;
2220:     return(0);
2221:   }
2222:   {
2223:     PetscInt c, coneSeries, s,supportSeries;

2225:     c = mesh->maxConeSize;
2226:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2227:     s = mesh->maxSupportSize;
2228:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2229:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2230:   }
2231:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2232:   if (*points) {
2233:     closure = *points;
2234:   } else {
2235:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2236:   }
2237:   closure[0] = p; closure[1] = 0;
2238:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2239:     const PetscInt cp = tmp[t];
2240:     const PetscInt co = tmpO ? tmpO[t] : 0;

2242:     closure[closureSize]   = cp;
2243:     closure[closureSize+1] = co;
2244:     fifo[fifoSize]         = cp;
2245:     fifo[fifoSize+1]       = co;
2246:   }
2247:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2248:   while (fifoSize - fifoStart) {
2249:     const PetscInt q   = fifo[fifoStart];
2250:     const PetscInt o   = fifo[fifoStart+1];
2251:     const PetscInt rev = o >= 0 ? 0 : 1;
2252:     const PetscInt off = rev ? -(o+1) : o;

2254:     if (useCone) {
2255:       DMPlexGetConeSize(dm, q, &tmpSize);
2256:       DMPlexGetCone(dm, q, &tmp);
2257:       DMPlexGetConeOrientation(dm, q, &tmpO);
2258:     } else {
2259:       DMPlexGetSupportSize(dm, q, &tmpSize);
2260:       DMPlexGetSupport(dm, q, &tmp);
2261:       tmpO = NULL;
2262:     }
2263:     for (t = 0; t < tmpSize; ++t) {
2264:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2265:       const PetscInt cp = tmp[i];
2266:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2267:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2268:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2269:       PetscInt       co = tmpO ? tmpO[i] : 0;
2270:       PetscInt       c;

2272:       if (rev) {
2273:         PetscInt childSize, coff;
2274:         DMPlexGetConeSize(dm, cp, &childSize);
2275:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2276:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2277:       }
2278:       /* Check for duplicate */
2279:       for (c = 0; c < closureSize; c += 2) {
2280:         if (closure[c] == cp) break;
2281:       }
2282:       if (c == closureSize) {
2283:         closure[closureSize]   = cp;
2284:         closure[closureSize+1] = co;
2285:         fifo[fifoSize]         = cp;
2286:         fifo[fifoSize+1]       = co;
2287:         closureSize           += 2;
2288:         fifoSize              += 2;
2289:       }
2290:     }
2291:     fifoStart += 2;
2292:   }
2293:   if (numPoints) *numPoints = closureSize/2;
2294:   if (points)    *points    = closure;
2295:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2296:   return(0);
2297: }

2299: /*@C
2300:   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

2302:   Not collective

2304:   Input Parameters:
2305: + mesh - The DMPlex
2306: . p - The point, which must lie in the chart set with DMPlexSetChart()
2307: . orientation - The orientation of the point
2308: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2309: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

2324:   Level: beginner

2326: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2327: @*/
2328: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2329: {
2330:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2331:   PetscInt       *closure, *fifo;
2332:   const PetscInt *tmp = NULL, *tmpO = NULL;
2333:   PetscInt        tmpSize, t;
2334:   PetscInt        depth       = 0, maxSize;
2335:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2336:   PetscErrorCode  ierr;

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

2370:     c = mesh->maxConeSize;
2371:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2372:     s = mesh->maxSupportSize;
2373:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2374:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2375:   }
2376:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2377:   if (*points) {
2378:     closure = *points;
2379:   } else {
2380:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2381:   }
2382:   closure[0] = p; closure[1] = ornt;
2383:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2384:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2385:     const PetscInt cp = tmp[i];
2386:     PetscInt       co = tmpO ? tmpO[i] : 0;

2388:     if (ornt < 0) {
2389:       PetscInt childSize, coff;
2390:       DMPlexGetConeSize(dm, cp, &childSize);
2391:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2392:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2393:     }
2394:     closure[closureSize]   = cp;
2395:     closure[closureSize+1] = co;
2396:     fifo[fifoSize]         = cp;
2397:     fifo[fifoSize+1]       = co;
2398:   }
2399:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2400:   while (fifoSize - fifoStart) {
2401:     const PetscInt q   = fifo[fifoStart];
2402:     const PetscInt o   = fifo[fifoStart+1];
2403:     const PetscInt rev = o >= 0 ? 0 : 1;
2404:     const PetscInt off = rev ? -(o+1) : o;

2406:     if (useCone) {
2407:       DMPlexGetConeSize(dm, q, &tmpSize);
2408:       DMPlexGetCone(dm, q, &tmp);
2409:       DMPlexGetConeOrientation(dm, q, &tmpO);
2410:     } else {
2411:       DMPlexGetSupportSize(dm, q, &tmpSize);
2412:       DMPlexGetSupport(dm, q, &tmp);
2413:       tmpO = NULL;
2414:     }
2415:     for (t = 0; t < tmpSize; ++t) {
2416:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2417:       const PetscInt cp = tmp[i];
2418:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2419:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2420:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2421:       PetscInt       co = tmpO ? tmpO[i] : 0;
2422:       PetscInt       c;

2424:       if (rev) {
2425:         PetscInt childSize, coff;
2426:         DMPlexGetConeSize(dm, cp, &childSize);
2427:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2428:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2429:       }
2430:       /* Check for duplicate */
2431:       for (c = 0; c < closureSize; c += 2) {
2432:         if (closure[c] == cp) break;
2433:       }
2434:       if (c == closureSize) {
2435:         closure[closureSize]   = cp;
2436:         closure[closureSize+1] = co;
2437:         fifo[fifoSize]         = cp;
2438:         fifo[fifoSize+1]       = co;
2439:         closureSize           += 2;
2440:         fifoSize              += 2;
2441:       }
2442:     }
2443:     fifoStart += 2;
2444:   }
2445:   if (numPoints) *numPoints = closureSize/2;
2446:   if (points)    *points    = closure;
2447:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2448:   return(0);
2449: }

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

2454:   Not collective

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

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

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

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

2472:   Level: beginner

2474: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2475: @*/
2476: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2477: {

2484:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2485:   if (numPoints) *numPoints = 0;
2486:   return(0);
2487: }

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

2492:   Not collective

2494:   Input Parameter:
2495: . mesh - The DMPlex

2497:   Output Parameters:
2498: + maxConeSize - The maximum number of in-edges
2499: - maxSupportSize - The maximum number of out-edges

2501:   Level: beginner

2503: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2504: @*/
2505: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2506: {
2507:   DM_Plex *mesh = (DM_Plex*) dm->data;

2511:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2512:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2513:   return(0);
2514: }

2516: PetscErrorCode DMSetUp_Plex(DM dm)
2517: {
2518:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2519:   PetscInt       size;

2524:   PetscSectionSetUp(mesh->coneSection);
2525:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2526:   PetscMalloc1(size, &mesh->cones);
2527:   PetscCalloc1(size, &mesh->coneOrientations);
2528:   if (mesh->maxSupportSize) {
2529:     PetscSectionSetUp(mesh->supportSection);
2530:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2531:     PetscMalloc1(size, &mesh->supports);
2532:   }
2533:   return(0);
2534: }

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

2541:   if (subdm) {DMClone(dm, subdm);}
2542:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2543:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2544:   if (dm->useNatural && dm->sfMigration) {
2545:     PetscSF        sfMigrationInv,sfNatural;
2546:     PetscSection   section, sectionSeq;

2548:     (*subdm)->sfMigration = dm->sfMigration;
2549:     PetscObjectReference((PetscObject) dm->sfMigration);
2550:     DMGetSection((*subdm), &section);
2551:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2552:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2553:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2555:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2556:     (*subdm)->sfNatural = sfNatural;
2557:     PetscSectionDestroy(&sectionSeq);
2558:     PetscSFDestroy(&sfMigrationInv);
2559:   }
2560:   return(0);
2561: }

2563: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2564: {
2566:   PetscInt       i = 0;

2569:   DMClone(dms[0], superdm);
2570:   DMCreateSectionSuperDM(dms, len, is, superdm);
2571:   (*superdm)->useNatural = PETSC_FALSE;
2572:   for (i = 0; i < len; i++){
2573:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2574:       PetscSF        sfMigrationInv,sfNatural;
2575:       PetscSection   section, sectionSeq;

2577:       (*superdm)->sfMigration = dms[i]->sfMigration;
2578:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2579:       (*superdm)->useNatural = PETSC_TRUE;
2580:       DMGetSection((*superdm), &section);
2581:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2582:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2583:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2585:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2586:       (*superdm)->sfNatural = sfNatural;
2587:       PetscSectionDestroy(&sectionSeq);
2588:       PetscSFDestroy(&sfMigrationInv);
2589:       break;
2590:     }
2591:   }
2592:   return(0);
2593: }

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

2598:   Not collective

2600:   Input Parameter:
2601: . mesh - The DMPlex

2603:   Output Parameter:

2605:   Note:
2606:   This should be called after all calls to DMPlexSetCone()

2608:   Level: beginner

2610: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2611: @*/
2612: PetscErrorCode DMPlexSymmetrize(DM dm)
2613: {
2614:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2615:   PetscInt      *offsets;
2616:   PetscInt       supportSize;
2617:   PetscInt       pStart, pEnd, p;

2622:   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2623:   PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);
2624:   /* Calculate support sizes */
2625:   DMPlexGetChart(dm, &pStart, &pEnd);
2626:   for (p = pStart; p < pEnd; ++p) {
2627:     PetscInt dof, off, c;

2629:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2630:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2631:     for (c = off; c < off+dof; ++c) {
2632:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2633:     }
2634:   }
2635:   for (p = pStart; p < pEnd; ++p) {
2636:     PetscInt dof;

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

2640:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2641:   }
2642:   PetscSectionSetUp(mesh->supportSection);
2643:   /* Calculate supports */
2644:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2645:   PetscMalloc1(supportSize, &mesh->supports);
2646:   PetscCalloc1(pEnd - pStart, &offsets);
2647:   for (p = pStart; p < pEnd; ++p) {
2648:     PetscInt dof, off, c;

2650:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2651:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2652:     for (c = off; c < off+dof; ++c) {
2653:       const PetscInt q = mesh->cones[c];
2654:       PetscInt       offS;

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

2658:       mesh->supports[offS+offsets[q]] = p;
2659:       ++offsets[q];
2660:     }
2661:   }
2662:   PetscFree(offsets);
2663:   PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);
2664:   return(0);
2665: }

2667: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
2668: {
2669:   IS             stratumIS;

2673:   if (pStart >= pEnd) return(0);
2674: #if defined(PETSC_USE_DEBUG)
2675:   {
2676:     PetscInt  qStart, qEnd, numLevels, level;
2677:     PetscBool overlap = PETSC_FALSE;
2678:     DMLabelGetNumValues(label, &numLevels);
2679:     for (level = 0; level < numLevels; level++) {
2680:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2681:       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
2682:     }
2683:     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);
2684:   }
2685: #endif
2686:   ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);
2687:   DMLabelSetStratumIS(label, depth, stratumIS);
2688:   ISDestroy(&stratumIS);
2689:   return(0);
2690: }

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

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

2700:   Collective on dm

2702:   Input Parameter:
2703: . mesh - The DMPlex

2705:   Output Parameter:

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

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

2715:   Level: beginner

2717: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2718: @*/
2719: PetscErrorCode DMPlexStratify(DM dm)
2720: {
2721:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2722:   DMLabel        label;
2723:   PetscInt       pStart, pEnd, p;
2724:   PetscInt       numRoots = 0, numLeaves = 0;
2725:   PetscInt       cMax, fMax, eMax, vMax;

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

2732:   /* Create depth label */
2733:   DMPlexGetChart(dm, &pStart, &pEnd);
2734:   DMCreateLabel(dm, "depth");
2735:   DMPlexGetDepthLabel(dm, &label);

2737:   {
2738:     /* Initialize roots and count leaves */
2739:     PetscInt sMin = PETSC_MAX_INT;
2740:     PetscInt sMax = PETSC_MIN_INT;
2741:     PetscInt coneSize, supportSize;

2743:     for (p = pStart; p < pEnd; ++p) {
2744:       DMPlexGetConeSize(dm, p, &coneSize);
2745:       DMPlexGetSupportSize(dm, p, &supportSize);
2746:       if (!coneSize && supportSize) {
2747:         sMin = PetscMin(p, sMin);
2748:         sMax = PetscMax(p, sMax);
2749:         ++numRoots;
2750:       } else if (!supportSize && coneSize) {
2751:         ++numLeaves;
2752:       } else if (!supportSize && !coneSize) {
2753:         /* Isolated points */
2754:         sMin = PetscMin(p, sMin);
2755:         sMax = PetscMax(p, sMax);
2756:       }
2757:     }
2758:     DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);
2759:   }

2761:   if (numRoots + numLeaves == (pEnd - pStart)) {
2762:     PetscInt sMin = PETSC_MAX_INT;
2763:     PetscInt sMax = PETSC_MIN_INT;
2764:     PetscInt coneSize, supportSize;

2766:     for (p = pStart; p < pEnd; ++p) {
2767:       DMPlexGetConeSize(dm, p, &coneSize);
2768:       DMPlexGetSupportSize(dm, p, &supportSize);
2769:       if (!supportSize && coneSize) {
2770:         sMin = PetscMin(p, sMin);
2771:         sMax = PetscMax(p, sMax);
2772:       }
2773:     }
2774:     DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);
2775:   } else {
2776:     PetscInt level = 0;
2777:     PetscInt qStart, qEnd, q;

2779:     DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2780:     while (qEnd > qStart) {
2781:       PetscInt sMin = PETSC_MAX_INT;
2782:       PetscInt sMax = PETSC_MIN_INT;

2784:       for (q = qStart; q < qEnd; ++q) {
2785:         const PetscInt *support;
2786:         PetscInt        supportSize, s;

2788:         DMPlexGetSupportSize(dm, q, &supportSize);
2789:         DMPlexGetSupport(dm, q, &support);
2790:         for (s = 0; s < supportSize; ++s) {
2791:           sMin = PetscMin(support[s], sMin);
2792:           sMax = PetscMax(support[s], sMax);
2793:         }
2794:       }
2795:       DMLabelGetNumValues(label, &level);
2796:       DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);
2797:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2798:     }
2799:   }
2800:   { /* just in case there is an empty process */
2801:     PetscInt numValues, maxValues = 0, v;

2803:     DMLabelGetNumValues(label, &numValues);
2804:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2805:     for (v = numValues; v < maxValues; v++) {
2806:       DMLabelAddStratum(label, v);
2807:     }
2808:   }
2809:   PetscObjectStateGet((PetscObject) label, &mesh->depthState);

2811:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2812:   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2813:     PetscInt dim;
2814:     DMLabel  dimLabel;

2816:     DMGetDimension(dm, &dim);
2817:     DMCreateLabel(dm, "dim");
2818:     DMGetLabel(dm, "dim", &dimLabel);
2819:     if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2820:     if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2821:     if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2822:     if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2823:   }
2824:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2825:   return(0);
2826: }

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

2831:   Not Collective

2833:   Input Parameters:
2834: + dm - The DMPlex object
2835: . numPoints - The number of input points for the join
2836: - points - The input points

2838:   Output Parameters:
2839: + numCoveredPoints - The number of points in the join
2840: - coveredPoints - The points in the join

2842:   Level: intermediate

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

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

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

2852: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2853: @*/
2854: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2855: {
2856:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2857:   PetscInt      *join[2];
2858:   PetscInt       joinSize, i = 0;
2859:   PetscInt       dof, off, p, c, m;

2867:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2868:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2869:   /* Copy in support of first point */
2870:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2871:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2872:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2873:     join[i][joinSize] = mesh->supports[off+joinSize];
2874:   }
2875:   /* Check each successive support */
2876:   for (p = 1; p < numPoints; ++p) {
2877:     PetscInt newJoinSize = 0;

2879:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2880:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2881:     for (c = 0; c < dof; ++c) {
2882:       const PetscInt point = mesh->supports[off+c];

2884:       for (m = 0; m < joinSize; ++m) {
2885:         if (point == join[i][m]) {
2886:           join[1-i][newJoinSize++] = point;
2887:           break;
2888:         }
2889:       }
2890:     }
2891:     joinSize = newJoinSize;
2892:     i        = 1-i;
2893:   }
2894:   *numCoveredPoints = joinSize;
2895:   *coveredPoints    = join[i];
2896:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2897:   return(0);
2898: }

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

2903:   Not Collective

2905:   Input Parameters:
2906: + dm - The DMPlex object
2907: . numPoints - The number of input points for the join
2908: - points - The input points

2910:   Output Parameters:
2911: + numCoveredPoints - The number of points in the join
2912: - coveredPoints - The points in the join

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

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

2920:   Level: intermediate

2922: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2923: @*/
2924: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2925: {

2933:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2934:   if (numCoveredPoints) *numCoveredPoints = 0;
2935:   return(0);
2936: }

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

2941:   Not Collective

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

2948:   Output Parameters:
2949: + numCoveredPoints - The number of points in the join
2950: - coveredPoints - The points in the join

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

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

2958:   Level: intermediate

2960: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2961: @*/
2962: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2963: {
2964:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2965:   PetscInt      *offsets, **closures;
2966:   PetscInt      *join[2];
2967:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2968:   PetscInt       p, d, c, m, ms;


2977:   DMPlexGetDepth(dm, &depth);
2978:   PetscCalloc1(numPoints, &closures);
2979:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2980:   ms      = mesh->maxSupportSize;
2981:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2982:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2983:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

2985:   for (p = 0; p < numPoints; ++p) {
2986:     PetscInt closureSize;

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

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

2994:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2995:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2996:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2997:           offsets[p*(depth+2)+d+1] = i;
2998:           break;
2999:         }
3000:       }
3001:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
3002:     }
3003:     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);
3004:   }
3005:   for (d = 0; d < depth+1; ++d) {
3006:     PetscInt dof;

3008:     /* Copy in support of first point */
3009:     dof = offsets[d+1] - offsets[d];
3010:     for (joinSize = 0; joinSize < dof; ++joinSize) {
3011:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
3012:     }
3013:     /* Check each successive cone */
3014:     for (p = 1; p < numPoints && joinSize; ++p) {
3015:       PetscInt newJoinSize = 0;

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

3021:         for (m = 0; m < joinSize; ++m) {
3022:           if (point == join[i][m]) {
3023:             join[1-i][newJoinSize++] = point;
3024:             break;
3025:           }
3026:         }
3027:       }
3028:       joinSize = newJoinSize;
3029:       i        = 1-i;
3030:     }
3031:     if (joinSize) break;
3032:   }
3033:   *numCoveredPoints = joinSize;
3034:   *coveredPoints    = join[i];
3035:   for (p = 0; p < numPoints; ++p) {
3036:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
3037:   }
3038:   PetscFree(closures);
3039:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3040:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3041:   return(0);
3042: }

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

3047:   Not Collective

3049:   Input Parameters:
3050: + dm - The DMPlex object
3051: . numPoints - The number of input points for the meet
3052: - points - The input points

3054:   Output Parameters:
3055: + numCoveredPoints - The number of points in the meet
3056: - coveredPoints - The points in the meet

3058:   Level: intermediate

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

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

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

3068: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
3069: @*/
3070: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
3071: {
3072:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3073:   PetscInt      *meet[2];
3074:   PetscInt       meetSize, i = 0;
3075:   PetscInt       dof, off, p, c, m;

3083:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
3084:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
3085:   /* Copy in cone of first point */
3086:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
3087:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
3088:   for (meetSize = 0; meetSize < dof; ++meetSize) {
3089:     meet[i][meetSize] = mesh->cones[off+meetSize];
3090:   }
3091:   /* Check each successive cone */
3092:   for (p = 1; p < numPoints; ++p) {
3093:     PetscInt newMeetSize = 0;

3095:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
3096:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
3097:     for (c = 0; c < dof; ++c) {
3098:       const PetscInt point = mesh->cones[off+c];

3100:       for (m = 0; m < meetSize; ++m) {
3101:         if (point == meet[i][m]) {
3102:           meet[1-i][newMeetSize++] = point;
3103:           break;
3104:         }
3105:       }
3106:     }
3107:     meetSize = newMeetSize;
3108:     i        = 1-i;
3109:   }
3110:   *numCoveringPoints = meetSize;
3111:   *coveringPoints    = meet[i];
3112:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3113:   return(0);
3114: }

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

3119:   Not Collective

3121:   Input Parameters:
3122: + dm - The DMPlex object
3123: . numPoints - The number of input points for the meet
3124: - points - The input points

3126:   Output Parameters:
3127: + numCoveredPoints - The number of points in the meet
3128: - coveredPoints - The points in the meet

3130:   Level: intermediate

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

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

3138: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
3139: @*/
3140: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3141: {

3149:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3150:   if (numCoveredPoints) *numCoveredPoints = 0;
3151:   return(0);
3152: }

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

3157:   Not Collective

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

3164:   Output Parameters:
3165: + numCoveredPoints - The number of points in the meet
3166: - coveredPoints - The points in the meet

3168:   Level: intermediate

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

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

3176: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3177: @*/
3178: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3179: {
3180:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3181:   PetscInt      *offsets, **closures;
3182:   PetscInt      *meet[2];
3183:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
3184:   PetscInt       p, h, c, m, mc;


3193:   DMPlexGetDepth(dm, &height);
3194:   PetscMalloc1(numPoints, &closures);
3195:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3196:   mc      = mesh->maxConeSize;
3197:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3198:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3199:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

3201:   for (p = 0; p < numPoints; ++p) {
3202:     PetscInt closureSize;

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

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

3210:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3211:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3212:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3213:           offsets[p*(height+2)+h+1] = i;
3214:           break;
3215:         }
3216:       }
3217:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3218:     }
3219:     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);
3220:   }
3221:   for (h = 0; h < height+1; ++h) {
3222:     PetscInt dof;

3224:     /* Copy in cone of first point */
3225:     dof = offsets[h+1] - offsets[h];
3226:     for (meetSize = 0; meetSize < dof; ++meetSize) {
3227:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3228:     }
3229:     /* Check each successive cone */
3230:     for (p = 1; p < numPoints && meetSize; ++p) {
3231:       PetscInt newMeetSize = 0;

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

3237:         for (m = 0; m < meetSize; ++m) {
3238:           if (point == meet[i][m]) {
3239:             meet[1-i][newMeetSize++] = point;
3240:             break;
3241:           }
3242:         }
3243:       }
3244:       meetSize = newMeetSize;
3245:       i        = 1-i;
3246:     }
3247:     if (meetSize) break;
3248:   }
3249:   *numCoveredPoints = meetSize;
3250:   *coveredPoints    = meet[i];
3251:   for (p = 0; p < numPoints; ++p) {
3252:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3253:   }
3254:   PetscFree(closures);
3255:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3256:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3257:   return(0);
3258: }

3260: /*@C
3261:   DMPlexEqual - Determine if two DMs have the same topology

3263:   Not Collective

3265:   Input Parameters:
3266: + dmA - A DMPlex object
3267: - dmB - A DMPlex object

3269:   Output Parameters:
3270: . equal - PETSC_TRUE if the topologies are identical

3272:   Level: intermediate

3274:   Notes:
3275:   We are not solving graph isomorphism, so we do not permutation.

3277: .seealso: DMPlexGetCone()
3278: @*/
3279: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3280: {
3281:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


3289:   *equal = PETSC_FALSE;
3290:   DMPlexGetDepth(dmA, &depth);
3291:   DMPlexGetDepth(dmB, &depthB);
3292:   if (depth != depthB) return(0);
3293:   DMPlexGetChart(dmA, &pStart,  &pEnd);
3294:   DMPlexGetChart(dmB, &pStartB, &pEndB);
3295:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3296:   for (p = pStart; p < pEnd; ++p) {
3297:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3298:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

3300:     DMPlexGetConeSize(dmA, p, &coneSize);
3301:     DMPlexGetCone(dmA, p, &cone);
3302:     DMPlexGetConeOrientation(dmA, p, &ornt);
3303:     DMPlexGetConeSize(dmB, p, &coneSizeB);
3304:     DMPlexGetCone(dmB, p, &coneB);
3305:     DMPlexGetConeOrientation(dmB, p, &orntB);
3306:     if (coneSize != coneSizeB) return(0);
3307:     for (c = 0; c < coneSize; ++c) {
3308:       if (cone[c] != coneB[c]) return(0);
3309:       if (ornt[c] != orntB[c]) return(0);
3310:     }
3311:     DMPlexGetSupportSize(dmA, p, &supportSize);
3312:     DMPlexGetSupport(dmA, p, &support);
3313:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
3314:     DMPlexGetSupport(dmB, p, &supportB);
3315:     if (supportSize != supportSizeB) return(0);
3316:     for (s = 0; s < supportSize; ++s) {
3317:       if (support[s] != supportB[s]) return(0);
3318:     }
3319:   }
3320:   *equal = PETSC_TRUE;
3321:   return(0);
3322: }

3324: /*@C
3325:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

3327:   Not Collective

3329:   Input Parameters:
3330: + dm         - The DMPlex
3331: . cellDim    - The cell dimension
3332: - numCorners - The number of vertices on a cell

3334:   Output Parameters:
3335: . numFaceVertices - The number of vertices on a face

3337:   Level: developer

3339:   Notes:
3340:   Of course this can only work for a restricted set of symmetric shapes

3342: .seealso: DMPlexGetCone()
3343: @*/
3344: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3345: {
3346:   MPI_Comm       comm;

3350:   PetscObjectGetComm((PetscObject)dm,&comm);
3352:   switch (cellDim) {
3353:   case 0:
3354:     *numFaceVertices = 0;
3355:     break;
3356:   case 1:
3357:     *numFaceVertices = 1;
3358:     break;
3359:   case 2:
3360:     switch (numCorners) {
3361:     case 3: /* triangle */
3362:       *numFaceVertices = 2; /* Edge has 2 vertices */
3363:       break;
3364:     case 4: /* quadrilateral */
3365:       *numFaceVertices = 2; /* Edge has 2 vertices */
3366:       break;
3367:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3368:       *numFaceVertices = 3; /* Edge has 3 vertices */
3369:       break;
3370:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3371:       *numFaceVertices = 3; /* Edge has 3 vertices */
3372:       break;
3373:     default:
3374:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3375:     }
3376:     break;
3377:   case 3:
3378:     switch (numCorners) {
3379:     case 4: /* tetradehdron */
3380:       *numFaceVertices = 3; /* Face has 3 vertices */
3381:       break;
3382:     case 6: /* tet cohesive cells */
3383:       *numFaceVertices = 4; /* Face has 4 vertices */
3384:       break;
3385:     case 8: /* hexahedron */
3386:       *numFaceVertices = 4; /* Face has 4 vertices */
3387:       break;
3388:     case 9: /* tet cohesive Lagrange cells */
3389:       *numFaceVertices = 6; /* Face has 6 vertices */
3390:       break;
3391:     case 10: /* quadratic tetrahedron */
3392:       *numFaceVertices = 6; /* Face has 6 vertices */
3393:       break;
3394:     case 12: /* hex cohesive Lagrange cells */
3395:       *numFaceVertices = 6; /* Face has 6 vertices */
3396:       break;
3397:     case 18: /* quadratic tet cohesive Lagrange cells */
3398:       *numFaceVertices = 6; /* Face has 6 vertices */
3399:       break;
3400:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3401:       *numFaceVertices = 9; /* Face has 9 vertices */
3402:       break;
3403:     default:
3404:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3405:     }
3406:     break;
3407:   default:
3408:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3409:   }
3410:   return(0);
3411: }

3413: /*@
3414:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3416:   Not Collective

3418:   Input Parameter:
3419: . dm    - The DMPlex object

3421:   Output Parameter:
3422: . depthLabel - The DMLabel recording point depth

3424:   Level: developer

3426: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3427: @*/
3428: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3429: {

3435:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3436:   *depthLabel = dm->depthLabel;
3437:   return(0);
3438: }

3440: /*@
3441:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3443:   Not Collective

3445:   Input Parameter:
3446: . dm    - The DMPlex object

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

3451:   Level: developer

3453: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3454: @*/
3455: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3456: {
3457:   DMLabel        label;
3458:   PetscInt       d = 0;

3464:   DMPlexGetDepthLabel(dm, &label);
3465:   if (label) {DMLabelGetNumValues(label, &d);}
3466:   *depth = d-1;
3467:   return(0);
3468: }

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

3473:   Not Collective

3475:   Input Parameters:
3476: + dm           - The DMPlex object
3477: - stratumValue - The requested depth

3479:   Output Parameters:
3480: + start - The first point at this depth
3481: - end   - One beyond the last point at this depth

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

3488:   Level: developer

3490: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3491: @*/
3492: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3493: {
3494:   DMLabel        label;
3495:   PetscInt       pStart, pEnd;

3502:   DMPlexGetChart(dm, &pStart, &pEnd);
3503:   if (pStart == pEnd) return(0);
3504:   if (stratumValue < 0) {
3505:     if (start) *start = pStart;
3506:     if (end)   *end   = pEnd;
3507:     return(0);
3508:   }
3509:   DMPlexGetDepthLabel(dm, &label);
3510:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3511:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3512:   return(0);
3513: }

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

3518:   Not Collective

3520:   Input Parameters:
3521: + dm           - The DMPlex object
3522: - stratumValue - The requested height

3524:   Output Parameters:
3525: + start - The first point at this height
3526: - end   - One beyond the last point at this height

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

3533:   Level: developer

3535: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3536: @*/
3537: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3538: {
3539:   DMLabel        label;
3540:   PetscInt       depth, pStart, pEnd;

3547:   DMPlexGetChart(dm, &pStart, &pEnd);
3548:   if (pStart == pEnd) return(0);
3549:   if (stratumValue < 0) {
3550:     if (start) *start = pStart;
3551:     if (end)   *end   = pEnd;
3552:     return(0);
3553:   }
3554:   DMPlexGetDepthLabel(dm, &label);
3555:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3556:   DMLabelGetNumValues(label, &depth);
3557:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3558:   return(0);
3559: }

3561: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3562: {
3563:   PetscSection   section, s;
3564:   Mat            m;
3565:   PetscInt       maxHeight;

3569:   DMClone(dm, cdm);
3570:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3571:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3572:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3573:   DMSetSection(*cdm, section);
3574:   PetscSectionDestroy(&section);
3575:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3576:   MatCreate(PETSC_COMM_SELF, &m);
3577:   DMSetDefaultConstraints(*cdm, s, m);
3578:   PetscSectionDestroy(&s);
3579:   MatDestroy(&m);

3581:   DMSetNumFields(*cdm, 1);
3582:   DMCreateDS(*cdm);
3583:   return(0);
3584: }

3586: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3587: {
3588:   Vec            coordsLocal;
3589:   DM             coordsDM;

3593:   *field = NULL;
3594:   DMGetCoordinatesLocal(dm,&coordsLocal);
3595:   DMGetCoordinateDM(dm,&coordsDM);
3596:   if (coordsLocal && coordsDM) {
3597:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3598:   }
3599:   return(0);
3600: }

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

3605:   Not Collective

3607:   Input Parameters:
3608: . dm        - The DMPlex object

3610:   Output Parameter:
3611: . section - The PetscSection object

3613:   Level: developer

3615: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3616: @*/
3617: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3618: {
3619:   DM_Plex *mesh = (DM_Plex*) dm->data;

3623:   if (section) *section = mesh->coneSection;
3624:   return(0);
3625: }

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

3630:   Not Collective

3632:   Input Parameters:
3633: . dm        - The DMPlex object

3635:   Output Parameter:
3636: . section - The PetscSection object

3638:   Level: developer

3640: .seealso: DMPlexGetConeSection()
3641: @*/
3642: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3643: {
3644:   DM_Plex *mesh = (DM_Plex*) dm->data;

3648:   if (section) *section = mesh->supportSection;
3649:   return(0);
3650: }

3652: /*@C
3653:   DMPlexGetCones - Return cone data

3655:   Not Collective

3657:   Input Parameters:
3658: . dm        - The DMPlex object

3660:   Output Parameter:
3661: . cones - The cone for each point

3663:   Level: developer

3665: .seealso: DMPlexGetConeSection()
3666: @*/
3667: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3668: {
3669:   DM_Plex *mesh = (DM_Plex*) dm->data;

3673:   if (cones) *cones = mesh->cones;
3674:   return(0);
3675: }

3677: /*@C
3678:   DMPlexGetConeOrientations - Return cone orientation data

3680:   Not Collective

3682:   Input Parameters:
3683: . dm        - The DMPlex object

3685:   Output Parameter:
3686: . coneOrientations - The cone orientation for each point

3688:   Level: developer

3690: .seealso: DMPlexGetConeSection()
3691: @*/
3692: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3693: {
3694:   DM_Plex *mesh = (DM_Plex*) dm->data;

3698:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3699:   return(0);
3700: }

3702: /******************************** FEM Support **********************************/

3704: /*
3705:  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
3706:  representing a line in the section.
3707: */
3708: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
3709: {

3713:   PetscSectionGetFieldComponents(section, field, Nc);
3714:   if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
3715:     *k = 1;
3716:   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
3717:     /* An order k SEM disc has k-1 dofs on an edge */
3718:     PetscSectionGetFieldDof(section, line, field, k);
3719:     *k = *k / *Nc + 1;
3720:   }
3721:   return(0);
3722: }

3724: /*@

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

3730:   Input Parameters:
3731: + dm      - The DM
3732: . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
3733: - section - The PetscSection to reorder, or NULL for the default section

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

3738:   Example:
3739:   A typical interpolated single-quad mesh might order points as
3740: .vb
3741:   [c0, v1, v2, v3, v4, e5, e6, e7, e8]

3743:   v4 -- e6 -- v3
3744:   |           |
3745:   e7    c0    e8
3746:   |           |
3747:   v1 -- e5 -- v2
3748: .ve

3750:   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
3751:   dofs in the order of points, e.g.,
3752: .vb
3753:     c0 -> [0,1,2,3]
3754:     v1 -> [4]
3755:     ...
3756:     e5 -> [8, 9]
3757: .ve

3759:   which corresponds to the dofs
3760: .vb
3761:     6   10  11  7
3762:     13  2   3   15
3763:     12  0   1   14
3764:     4   8   9   5
3765: .ve

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

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

3777:   Level: developer

3779: .seealso: DMGetSection(), PetscSectionSetClosurePermutation()
3780: @*/
3781: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
3782: {
3783:   DMLabel        label;
3784:   PetscInt      *perm;
3785:   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3786:   PetscBool      vertexchart;

3790:   if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3791:   DMGetDimension(dm, &dim);
3792:   DMPlexGetDepthLabel(dm, &label);
3793:   DMLabelGetValue(label, point, &depth);
3794:   if (depth == 1) {eStart = point;}
3795:   else if  (depth == dim) {
3796:     const PetscInt *cone;

3798:     DMPlexGetCone(dm, point, &cone);
3799:     if (dim == 2) eStart = cone[0];
3800:     else if (dim == 3) {
3801:       const PetscInt *cone2;
3802:       DMPlexGetCone(dm, cone[0], &cone2);
3803:       eStart = cone2[0];
3804:     } 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);
3805:   } 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);
3806:   if (!section) {DMGetSection(dm, &section);}
3807:   {                             /* Determine whether the chart covers all points or just vertices. */
3808:     PetscInt pStart,pEnd,cStart,cEnd;
3809:     DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);
3810:     PetscSectionGetChart(section,&cStart,&cEnd);
3811:     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
3812:     else vertexchart = PETSC_FALSE;                                 /* Assume all interpolated points are in chart */
3813:   }
3814:   PetscSectionGetNumFields(section, &Nf);
3815:   if (dim < 1) return(0);
3816:   for (f = 0; f < Nf; ++f) {
3817:     PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3818:     size += PetscPowInt(k+1, dim)*Nc;
3819:   }
3820:   PetscMalloc1(size, &perm);
3821:   for (f = 0; f < Nf; ++f) {
3822:     switch (dim) {
3823:     case 1:
3824:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3825:       /*
3826:         Original ordering is [ edge of length k-1; vtx0; vtx1 ]
3827:         We want              [ vtx0; edge of length k-1; vtx1 ]
3828:       */
3829:       for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
3830:       for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
3831:       for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
3832:       foffset = offset;
3833:       break;
3834:     case 2:
3835:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3836:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3837:       /* The SEM order is

3839:          v_lb, {e_b}, v_rb,
3840:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3841:          v_lt, reverse {e_t}, v_rt
3842:       */
3843:       {
3844:         const PetscInt of   = 0;
3845:         const PetscInt oeb  = of   + PetscSqr(k-1);
3846:         const PetscInt oer  = oeb  + (k-1);
3847:         const PetscInt oet  = oer  + (k-1);
3848:         const PetscInt oel  = oet  + (k-1);
3849:         const PetscInt ovlb = oel  + (k-1);
3850:         const PetscInt ovrb = ovlb + 1;
3851:         const PetscInt ovrt = ovrb + 1;
3852:         const PetscInt ovlt = ovrt + 1;
3853:         PetscInt       o;

3855:         /* bottom */
3856:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3857:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3858:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3859:         /* middle */
3860:         for (i = 0; i < k-1; ++i) {
3861:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3862:           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;
3863:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3864:         }
3865:         /* top */
3866:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3867:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3868:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3869:         foffset = offset;
3870:       }
3871:       break;
3872:     case 3:
3873:       /* The original hex closure is

3875:          {c,
3876:           f_b, f_t, f_f, f_b, f_r, f_l,
3877:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3878:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3879:       */
3880:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
3881:       /* The SEM order is
3882:          Bottom Slice
3883:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3884:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3885:          v_blb, {e_bb}, v_brb,

3887:          Middle Slice (j)
3888:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3889:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3890:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3892:          Top Slice
3893:          v_tlf, {e_tf}, v_trf,
3894:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3895:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3896:       */
3897:       {
3898:         const PetscInt oc    = 0;
3899:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3900:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3901:         const PetscInt off   = oft   + PetscSqr(k-1);
3902:         const PetscInt ofk   = off   + PetscSqr(k-1);
3903:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3904:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3905:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3906:         const PetscInt oebb  = oebl  + (k-1);
3907:         const PetscInt oebr  = oebb  + (k-1);
3908:         const PetscInt oebf  = oebr  + (k-1);
3909:         const PetscInt oetf  = oebf  + (k-1);
3910:         const PetscInt oetr  = oetf  + (k-1);
3911:         const PetscInt oetb  = oetr  + (k-1);
3912:         const PetscInt oetl  = oetb  + (k-1);
3913:         const PetscInt oerf  = oetl  + (k-1);
3914:         const PetscInt oelf  = oerf  + (k-1);
3915:         const PetscInt oelb  = oelf  + (k-1);
3916:         const PetscInt oerb  = oelb  + (k-1);
3917:         const PetscInt ovblf = oerb  + (k-1);
3918:         const PetscInt ovblb = ovblf + 1;
3919:         const PetscInt ovbrb = ovblb + 1;
3920:         const PetscInt ovbrf = ovbrb + 1;
3921:         const PetscInt ovtlf = ovbrf + 1;
3922:         const PetscInt ovtrf = ovtlf + 1;
3923:         const PetscInt ovtrb = ovtrf + 1;
3924:         const PetscInt ovtlb = ovtrb + 1;
3925:         PetscInt       o, n;

3927:         /* Bottom Slice */
3928:         /*   bottom */
3929:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3930:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3931:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3932:         /*   middle */
3933:         for (i = 0; i < k-1; ++i) {
3934:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3935:           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;}
3936:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3937:         }
3938:         /*   top */
3939:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3940:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3941:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3943:         /* Middle Slice */
3944:         for (j = 0; j < k-1; ++j) {
3945:           /*   bottom */
3946:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3947:           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;
3948:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3949:           /*   middle */
3950:           for (i = 0; i < k-1; ++i) {
3951:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3952:             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;
3953:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3954:           }
3955:           /*   top */
3956:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3957:           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;
3958:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3959:         }

3961:         /* Top Slice */
3962:         /*   bottom */
3963:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3964:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3965:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3966:         /*   middle */
3967:         for (i = 0; i < k-1; ++i) {
3968:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3969:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3970:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3971:         }
3972:         /*   top */
3973:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3974:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3975:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3977:         foffset = offset;
3978:       }
3979:       break;
3980:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3981:     }
3982:   }
3983:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3984:   /* Check permutation */
3985:   {
3986:     PetscInt *check;

3988:     PetscMalloc1(size, &check);
3989:     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]);}
3990:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3991:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3992:     PetscFree(check);
3993:   }
3994:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3995:   return(0);
3996: }

3998: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3999: {
4000:   PetscDS        prob;
4001:   PetscInt       depth, Nf, h;
4002:   DMLabel        label;

4006:   DMGetDS(dm, &prob);
4007:   Nf      = prob->Nf;
4008:   label   = dm->depthLabel;
4009:   *dspace = NULL;
4010:   if (field < Nf) {
4011:     PetscObject disc = prob->disc[field];

4013:     if (disc->classid == PETSCFE_CLASSID) {
4014:       PetscDualSpace dsp;

4016:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
4017:       DMLabelGetNumValues(label,&depth);
4018:       DMLabelGetValue(label,point,&h);
4019:       h    = depth - 1 - h;
4020:       if (h) {
4021:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
4022:       } else {
4023:         *dspace = dsp;
4024:       }
4025:     }
4026:   }
4027:   return(0);
4028: }


4031: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4032: {
4033:   PetscScalar    *array, *vArray;
4034:   const PetscInt *cone, *coneO;
4035:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
4036:   PetscErrorCode  ierr;

4039:   PetscSectionGetChart(section, &pStart, &pEnd);
4040:   DMPlexGetConeSize(dm, point, &numPoints);
4041:   DMPlexGetCone(dm, point, &cone);
4042:   DMPlexGetConeOrientation(dm, point, &coneO);
4043:   if (!values || !*values) {
4044:     if ((point >= pStart) && (point < pEnd)) {
4045:       PetscInt dof;

4047:       PetscSectionGetDof(section, point, &dof);
4048:       size += dof;
4049:     }
4050:     for (p = 0; p < numPoints; ++p) {
4051:       const PetscInt cp = cone[p];
4052:       PetscInt       dof;

4054:       if ((cp < pStart) || (cp >= pEnd)) continue;
4055:       PetscSectionGetDof(section, cp, &dof);
4056:       size += dof;
4057:     }
4058:     if (!values) {
4059:       if (csize) *csize = size;
4060:       return(0);
4061:     }
4062:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
4063:   } else {
4064:     array = *values;
4065:   }
4066:   size = 0;
4067:   VecGetArray(v, &vArray);
4068:   if ((point >= pStart) && (point < pEnd)) {
4069:     PetscInt     dof, off, d;
4070:     PetscScalar *varr;

4072:     PetscSectionGetDof(section, point, &dof);
4073:     PetscSectionGetOffset(section, point, &off);
4074:     varr = &vArray[off];
4075:     for (d = 0; d < dof; ++d, ++offset) {
4076:       array[offset] = varr[d];
4077:     }
4078:     size += dof;
4079:   }
4080:   for (p = 0; p < numPoints; ++p) {
4081:     const PetscInt cp = cone[p];
4082:     PetscInt       o  = coneO[p];
4083:     PetscInt       dof, off, d;
4084:     PetscScalar   *varr;

4086:     if ((cp < pStart) || (cp >= pEnd)) continue;
4087:     PetscSectionGetDof(section, cp, &dof);
4088:     PetscSectionGetOffset(section, cp, &off);
4089:     varr = &vArray[off];
4090:     if (o >= 0) {
4091:       for (d = 0; d < dof; ++d, ++offset) {
4092:         array[offset] = varr[d];
4093:       }
4094:     } else {
4095:       for (d = dof-1; d >= 0; --d, ++offset) {
4096:         array[offset] = varr[d];
4097:       }
4098:     }
4099:     size += dof;
4100:   }
4101:   VecRestoreArray(v, &vArray);
4102:   if (!*values) {
4103:     if (csize) *csize = size;
4104:     *values = array;
4105:   } else {
4106:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4107:     *csize = size;
4108:   }
4109:   return(0);
4110: }

4112: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4113: {
4114:   const PetscInt *cla;
4115:   PetscInt       np, *pts = NULL;

4119:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
4120:   if (!*clPoints) {
4121:     PetscInt pStart, pEnd, p, q;

4123:     PetscSectionGetChart(section, &pStart, &pEnd);
4124:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
4125:     /* Compress out points not in the section */
4126:     for (p = 0, q = 0; p < np; p++) {
4127:       PetscInt r = pts[2*p];
4128:       if ((r >= pStart) && (r < pEnd)) {
4129:         pts[q*2]   = r;
4130:         pts[q*2+1] = pts[2*p+1];
4131:         ++q;
4132:       }
4133:     }
4134:     np = q;
4135:     cla = NULL;
4136:   } else {
4137:     PetscInt dof, off;

4139:     PetscSectionGetDof(*clSec, point, &dof);
4140:     PetscSectionGetOffset(*clSec, point, &off);
4141:     ISGetIndices(*clPoints, &cla);
4142:     np   = dof/2;
4143:     pts  = (PetscInt *) &cla[off];
4144:   }
4145:   *numPoints = np;
4146:   *points    = pts;
4147:   *clp       = cla;

4149:   return(0);
4150: }

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

4157:   if (!*clPoints) {
4158:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
4159:   } else {
4160:     ISRestoreIndices(*clPoints, clp);
4161:   }
4162:   *numPoints = 0;
4163:   *points    = NULL;
4164:   *clSec     = NULL;
4165:   *clPoints  = NULL;
4166:   *clp       = NULL;
4167:   return(0);
4168: }

4170: 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[])
4171: {
4172:   PetscInt          offset = 0, p;
4173:   const PetscInt    **perms = NULL;
4174:   const PetscScalar **flips = NULL;
4175:   PetscErrorCode    ierr;

4178:   *size = 0;
4179:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4180:   for (p = 0; p < numPoints; p++) {
4181:     const PetscInt    point = points[2*p];
4182:     const PetscInt    *perm = perms ? perms[p] : NULL;
4183:     const PetscScalar *flip = flips ? flips[p] : NULL;
4184:     PetscInt          dof, off, d;
4185:     const PetscScalar *varr;

4187:     PetscSectionGetDof(section, point, &dof);
4188:     PetscSectionGetOffset(section, point, &off);
4189:     varr = &vArray[off];
4190:     if (clperm) {
4191:       if (perm) {
4192:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4193:       } else {
4194:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4195:       }
4196:       if (flip) {
4197:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4198:       }
4199:     } else {
4200:       if (perm) {
4201:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4202:       } else {
4203:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4204:       }
4205:       if (flip) {
4206:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4207:       }
4208:     }
4209:     offset += dof;
4210:   }
4211:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4212:   *size = offset;
4213:   return(0);
4214: }

4216: 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[])
4217: {
4218:   PetscInt          offset = 0, f;
4219:   PetscErrorCode    ierr;

4222:   *size = 0;
4223:   for (f = 0; f < numFields; ++f) {
4224:     PetscInt          p;
4225:     const PetscInt    **perms = NULL;
4226:     const PetscScalar **flips = NULL;

4228:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4229:     for (p = 0; p < numPoints; p++) {
4230:       const PetscInt    point = points[2*p];
4231:       PetscInt          fdof, foff, b;
4232:       const PetscScalar *varr;
4233:       const PetscInt    *perm = perms ? perms[p] : NULL;
4234:       const PetscScalar *flip = flips ? flips[p] : NULL;

4236:       PetscSectionGetFieldDof(section, point, f, &fdof);
4237:       PetscSectionGetFieldOffset(section, point, f, &foff);
4238:       varr = &vArray[foff];
4239:       if (clperm) {
4240:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4241:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4242:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4243:       } else {
4244:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4245:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4246:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4247:       }
4248:       offset += fdof;
4249:     }
4250:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4251:   }
4252:   *size = offset;
4253:   return(0);
4254: }

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

4259:   Not collective

4261:   Input Parameters:
4262: + dm - The DM
4263: . section - The section describing the layout in v, or NULL to use the default section
4264: . v - The local vector
4265: . point - The point in the DM
4266: . csize - The size of the input values array, or NULL
4267: - values - An array to use for the values, or NULL to have it allocated automatically

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

4273: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4274: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4275: $ assembly function, and a user may already have allocated storage for this operation.
4276: $
4277: $ A typical use could be
4278: $
4279: $  values = NULL;
4280: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4281: $  for (cl = 0; cl < clSize; ++cl) {
4282: $    <Compute on closure>
4283: $  }
4284: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4285: $
4286: $ or
4287: $
4288: $  PetscMalloc1(clMaxSize, &values);
4289: $  for (p = pStart; p < pEnd; ++p) {
4290: $    clSize = clMaxSize;
4291: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4292: $    for (cl = 0; cl < clSize; ++cl) {
4293: $      <Compute on closure>
4294: $    }
4295: $  }
4296: $  PetscFree(values);

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

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

4304:   Level: intermediate

4306: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4307: @*/
4308: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4309: {
4310:   PetscSection       clSection;
4311:   IS                 clPoints;
4312:   PetscScalar       *array;
4313:   const PetscScalar *vArray;
4314:   PetscInt          *points = NULL;
4315:   const PetscInt    *clp, *perm;
4316:   PetscInt           depth, numFields, numPoints, size;
4317:   PetscErrorCode     ierr;

4321:   if (!section) {DMGetSection(dm, &section);}
4324:   DMPlexGetDepth(dm, &depth);
4325:   PetscSectionGetNumFields(section, &numFields);
4326:   if (depth == 1 && numFields < 2) {
4327:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4328:     return(0);
4329:   }
4330:   /* Get points */
4331:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4332:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4333:   /* Get array */
4334:   if (!values || !*values) {
4335:     PetscInt asize = 0, dof, p;

4337:     for (p = 0; p < numPoints*2; p += 2) {
4338:       PetscSectionGetDof(section, points[p], &dof);
4339:       asize += dof;
4340:     }
4341:     if (!values) {
4342:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4343:       if (csize) *csize = asize;
4344:       return(0);
4345:     }
4346:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4347:   } else {
4348:     array = *values;
4349:   }
4350:   VecGetArrayRead(v, &vArray);
4351:   /* Get values */
4352:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4353:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4354:   /* Cleanup points */
4355:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4356:   /* Cleanup array */
4357:   VecRestoreArrayRead(v, &vArray);
4358:   if (!*values) {
4359:     if (csize) *csize = size;
4360:     *values = array;
4361:   } else {
4362:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4363:     *csize = size;
4364:   }
4365:   return(0);
4366: }

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

4371:   Not collective

4373:   Input Parameters:
4374: + dm - The DM
4375: . section - The section describing the layout in v, or NULL to use the default section
4376: . v - The local vector
4377: . point - The point in the DM
4378: . csize - The number of values in the closure, or NULL
4379: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

4389:   Level: intermediate

4391: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4392: @*/
4393: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4394: {
4395:   PetscInt       size = 0;

4399:   /* Should work without recalculating size */
4400:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4401:   *values = NULL;
4402:   return(0);
4403: }

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

4408: 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[])
4409: {
4410:   PetscInt        cdof;   /* The number of constraints on this point */
4411:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4412:   PetscScalar    *a;
4413:   PetscInt        off, cind = 0, k;
4414:   PetscErrorCode  ierr;

4417:   PetscSectionGetConstraintDof(section, point, &cdof);
4418:   PetscSectionGetOffset(section, point, &off);
4419:   a    = &array[off];
4420:   if (!cdof || setBC) {
4421:     if (clperm) {
4422:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4423:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4424:     } else {
4425:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4426:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4427:     }
4428:   } else {
4429:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4430:     if (clperm) {
4431:       if (perm) {for (k = 0; k < dof; ++k) {
4432:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4433:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4434:         }
4435:       } else {
4436:         for (k = 0; k < dof; ++k) {
4437:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4438:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4439:         }
4440:       }
4441:     } else {
4442:       if (perm) {
4443:         for (k = 0; k < dof; ++k) {
4444:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4445:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4446:         }
4447:       } else {
4448:         for (k = 0; k < dof; ++k) {
4449:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4450:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4451:         }
4452:       }
4453:     }
4454:   }
4455:   return(0);
4456: }

4458: 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[])
4459: {
4460:   PetscInt        cdof;   /* The number of constraints on this point */
4461:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4462:   PetscScalar    *a;
4463:   PetscInt        off, cind = 0, k;
4464:   PetscErrorCode  ierr;

4467:   PetscSectionGetConstraintDof(section, point, &cdof);
4468:   PetscSectionGetOffset(section, point, &off);
4469:   a    = &array[off];
4470:   if (cdof) {
4471:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4472:     if (clperm) {
4473:       if (perm) {
4474:         for (k = 0; k < dof; ++k) {
4475:           if ((cind < cdof) && (k == cdofs[cind])) {
4476:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4477:             cind++;
4478:           }
4479:         }
4480:       } else {
4481:         for (k = 0; k < dof; ++k) {
4482:           if ((cind < cdof) && (k == cdofs[cind])) {
4483:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4484:             cind++;
4485:           }
4486:         }
4487:       }
4488:     } else {
4489:       if (perm) {
4490:         for (k = 0; k < dof; ++k) {
4491:           if ((cind < cdof) && (k == cdofs[cind])) {
4492:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4493:             cind++;
4494:           }
4495:         }
4496:       } else {
4497:         for (k = 0; k < dof; ++k) {
4498:           if ((cind < cdof) && (k == cdofs[cind])) {
4499:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4500:             cind++;
4501:           }
4502:         }
4503:       }
4504:     }
4505:   }
4506:   return(0);
4507: }

4509: 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[])
4510: {
4511:   PetscScalar    *a;
4512:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4513:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4514:   PetscInt        cind = 0, b;
4515:   PetscErrorCode  ierr;

4518:   PetscSectionGetFieldDof(section, point, f, &fdof);
4519:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4520:   PetscSectionGetFieldOffset(section, point, f, &foff);
4521:   a    = &array[foff];
4522:   if (!fcdof || setBC) {
4523:     if (clperm) {
4524:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4525:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4526:     } else {
4527:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4528:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4529:     }
4530:   } else {
4531:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4532:     if (clperm) {
4533:       if (perm) {
4534:         for (b = 0; b < fdof; b++) {
4535:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4536:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4537:         }
4538:       } else {
4539:         for (b = 0; b < fdof; b++) {
4540:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4541:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4542:         }
4543:       }
4544:     } else {
4545:       if (perm) {
4546:         for (b = 0; b < fdof; b++) {
4547:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4548:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4549:         }
4550:       } else {
4551:         for (b = 0; b < fdof; b++) {
4552:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4553:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4554:         }
4555:       }
4556:     }
4557:   }
4558:   *offset += fdof;
4559:   return(0);
4560: }

4562: 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[])
4563: {
4564:   PetscScalar    *a;
4565:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4566:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4567:   PetscInt        cind = 0, ncind = 0, b;
4568:   PetscBool       ncSet, fcSet;
4569:   PetscErrorCode  ierr;

4572:   PetscSectionGetFieldDof(section, point, f, &fdof);
4573:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4574:   PetscSectionGetFieldOffset(section, point, f, &foff);
4575:   a    = &array[foff];
4576:   if (fcdof) {
4577:     /* We just override fcdof and fcdofs with Ncc and comps */
4578:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4579:     if (clperm) {
4580:       if (perm) {
4581:         if (comps) {
4582:           for (b = 0; b < fdof; b++) {
4583:             ncSet = fcSet = PETSC_FALSE;
4584:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4585:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4586:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4587:           }
4588:         } else {
4589:           for (b = 0; b < fdof; b++) {
4590:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4591:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4592:               ++cind;
4593:             }
4594:           }
4595:         }
4596:       } else {
4597:         if (comps) {
4598:           for (b = 0; b < fdof; b++) {
4599:             ncSet = fcSet = PETSC_FALSE;
4600:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4601:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4602:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4603:           }
4604:         } else {
4605:           for (b = 0; b < fdof; b++) {
4606:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4607:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4608:               ++cind;
4609:             }
4610:           }
4611:         }
4612:       }
4613:     } else {
4614:       if (perm) {
4615:         if (comps) {
4616:           for (b = 0; b < fdof; b++) {
4617:             ncSet = fcSet = PETSC_FALSE;
4618:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4619:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4620:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4621:           }
4622:         } else {
4623:           for (b = 0; b < fdof; b++) {
4624:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4625:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4626:               ++cind;
4627:             }
4628:           }
4629:         }
4630:       } else {
4631:         if (comps) {
4632:           for (b = 0; b < fdof; b++) {
4633:             ncSet = fcSet = PETSC_FALSE;
4634:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4635:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4636:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4637:           }
4638:         } else {
4639:           for (b = 0; b < fdof; b++) {
4640:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4641:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4642:               ++cind;
4643:             }
4644:           }
4645:         }
4646:       }
4647:     }
4648:   }
4649:   *offset += fdof;
4650:   return(0);
4651: }

4653: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4654: {
4655:   PetscScalar    *array;
4656:   const PetscInt *cone, *coneO;
4657:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4658:   PetscErrorCode  ierr;

4661:   PetscSectionGetChart(section, &pStart, &pEnd);
4662:   DMPlexGetConeSize(dm, point, &numPoints);
4663:   DMPlexGetCone(dm, point, &cone);
4664:   DMPlexGetConeOrientation(dm, point, &coneO);
4665:   VecGetArray(v, &array);
4666:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4667:     const PetscInt cp = !p ? point : cone[p-1];
4668:     const PetscInt o  = !p ? 0     : coneO[p-1];

4670:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4671:     PetscSectionGetDof(section, cp, &dof);
4672:     /* ADD_VALUES */
4673:     {
4674:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4675:       PetscScalar    *a;
4676:       PetscInt        cdof, coff, cind = 0, k;

4678:       PetscSectionGetConstraintDof(section, cp, &cdof);
4679:       PetscSectionGetOffset(section, cp, &coff);
4680:       a    = &array[coff];
4681:       if (!cdof) {
4682:         if (o >= 0) {
4683:           for (k = 0; k < dof; ++k) {
4684:             a[k] += values[off+k];
4685:           }
4686:         } else {
4687:           for (k = 0; k < dof; ++k) {
4688:             a[k] += values[off+dof-k-1];
4689:           }
4690:         }
4691:       } else {
4692:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4693:         if (o >= 0) {
4694:           for (k = 0; k < dof; ++k) {
4695:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4696:             a[k] += values[off+k];
4697:           }
4698:         } else {
4699:           for (k = 0; k < dof; ++k) {
4700:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4701:             a[k] += values[off+dof-k-1];
4702:           }
4703:         }
4704:       }
4705:     }
4706:   }
4707:   VecRestoreArray(v, &array);
4708:   return(0);
4709: }

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

4714:   Not collective

4716:   Input Parameters:
4717: + dm - The DM
4718: . section - The section describing the layout in v, or NULL to use the default section
4719: . v - The local vector
4720: . point - The point in the DM
4721: . values - The array of values
4722: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4723:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4728:   Level: intermediate

4730: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4731: @*/
4732: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4733: {
4734:   PetscSection    clSection;
4735:   IS              clPoints;
4736:   PetscScalar    *array;
4737:   PetscInt       *points = NULL;
4738:   const PetscInt *clp, *clperm;
4739:   PetscInt        depth, numFields, numPoints, p;
4740:   PetscErrorCode  ierr;

4744:   if (!section) {DMGetSection(dm, &section);}
4747:   DMPlexGetDepth(dm, &depth);
4748:   PetscSectionGetNumFields(section, &numFields);
4749:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4750:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4751:     return(0);
4752:   }
4753:   /* Get points */
4754:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4755:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4756:   /* Get array */
4757:   VecGetArray(v, &array);
4758:   /* Get values */
4759:   if (numFields > 0) {
4760:     PetscInt offset = 0, f;
4761:     for (f = 0; f < numFields; ++f) {
4762:       const PetscInt    **perms = NULL;
4763:       const PetscScalar **flips = NULL;

4765:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4766:       switch (mode) {
4767:       case INSERT_VALUES:
4768:         for (p = 0; p < numPoints; p++) {
4769:           const PetscInt    point = points[2*p];
4770:           const PetscInt    *perm = perms ? perms[p] : NULL;
4771:           const PetscScalar *flip = flips ? flips[p] : NULL;
4772:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4773:         } break;
4774:       case INSERT_ALL_VALUES:
4775:         for (p = 0; p < numPoints; p++) {
4776:           const PetscInt    point = points[2*p];
4777:           const PetscInt    *perm = perms ? perms[p] : NULL;
4778:           const PetscScalar *flip = flips ? flips[p] : NULL;
4779:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4780:         } break;
4781:       case INSERT_BC_VALUES:
4782:         for (p = 0; p < numPoints; p++) {
4783:           const PetscInt    point = points[2*p];
4784:           const PetscInt    *perm = perms ? perms[p] : NULL;
4785:           const PetscScalar *flip = flips ? flips[p] : NULL;
4786:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4787:         } break;
4788:       case ADD_VALUES:
4789:         for (p = 0; p < numPoints; p++) {
4790:           const PetscInt    point = points[2*p];
4791:           const PetscInt    *perm = perms ? perms[p] : NULL;
4792:           const PetscScalar *flip = flips ? flips[p] : NULL;
4793:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4794:         } break;
4795:       case ADD_ALL_VALUES:
4796:         for (p = 0; p < numPoints; p++) {
4797:           const PetscInt    point = points[2*p];
4798:           const PetscInt    *perm = perms ? perms[p] : NULL;
4799:           const PetscScalar *flip = flips ? flips[p] : NULL;
4800:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4801:         } break;
4802:       case ADD_BC_VALUES:
4803:         for (p = 0; p < numPoints; p++) {
4804:           const PetscInt    point = points[2*p];
4805:           const PetscInt    *perm = perms ? perms[p] : NULL;
4806:           const PetscScalar *flip = flips ? flips[p] : NULL;
4807:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4808:         } break;
4809:       default:
4810:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4811:       }
4812:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4813:     }
4814:   } else {
4815:     PetscInt dof, off;
4816:     const PetscInt    **perms = NULL;
4817:     const PetscScalar **flips = NULL;

4819:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4820:     switch (mode) {
4821:     case INSERT_VALUES:
4822:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4823:         const PetscInt    point = points[2*p];
4824:         const PetscInt    *perm = perms ? perms[p] : NULL;
4825:         const PetscScalar *flip = flips ? flips[p] : NULL;
4826:         PetscSectionGetDof(section, point, &dof);
4827:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4828:       } break;
4829:     case INSERT_ALL_VALUES:
4830:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4831:         const PetscInt    point = points[2*p];
4832:         const PetscInt    *perm = perms ? perms[p] : NULL;
4833:         const PetscScalar *flip = flips ? flips[p] : NULL;
4834:         PetscSectionGetDof(section, point, &dof);
4835:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4836:       } break;
4837:     case INSERT_BC_VALUES:
4838:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4839:         const PetscInt    point = points[2*p];
4840:         const PetscInt    *perm = perms ? perms[p] : NULL;
4841:         const PetscScalar *flip = flips ? flips[p] : NULL;
4842:         PetscSectionGetDof(section, point, &dof);
4843:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4844:       } break;
4845:     case ADD_VALUES:
4846:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4847:         const PetscInt    point = points[2*p];
4848:         const PetscInt    *perm = perms ? perms[p] : NULL;
4849:         const PetscScalar *flip = flips ? flips[p] : NULL;
4850:         PetscSectionGetDof(section, point, &dof);
4851:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4852:       } break;
4853:     case ADD_ALL_VALUES:
4854:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4855:         const PetscInt    point = points[2*p];
4856:         const PetscInt    *perm = perms ? perms[p] : NULL;
4857:         const PetscScalar *flip = flips ? flips[p] : NULL;
4858:         PetscSectionGetDof(section, point, &dof);
4859:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4860:       } break;
4861:     case ADD_BC_VALUES:
4862:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4863:         const PetscInt    point = points[2*p];
4864:         const PetscInt    *perm = perms ? perms[p] : NULL;
4865:         const PetscScalar *flip = flips ? flips[p] : NULL;
4866:         PetscSectionGetDof(section, point, &dof);
4867:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4868:       } break;
4869:     default:
4870:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4871:     }
4872:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4873:   }
4874:   /* Cleanup points */
4875:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4876:   /* Cleanup array */
4877:   VecRestoreArray(v, &array);
4878:   return(0);
4879: }

4881: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4882: {
4883:   PetscSection      clSection;
4884:   IS                clPoints;
4885:   PetscScalar       *array;
4886:   PetscInt          *points = NULL;
4887:   const PetscInt    *clp, *clperm;
4888:   PetscInt          numFields, numPoints, p;
4889:   PetscInt          offset = 0, f;
4890:   PetscErrorCode    ierr;

4894:   if (!section) {DMGetSection(dm, &section);}
4897:   PetscSectionGetNumFields(section, &numFields);
4898:   /* Get points */
4899:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4900:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4901:   /* Get array */
4902:   VecGetArray(v, &array);
4903:   /* Get values */
4904:   for (f = 0; f < numFields; ++f) {
4905:     const PetscInt    **perms = NULL;
4906:     const PetscScalar **flips = NULL;

4908:     if (!fieldActive[f]) {
4909:       for (p = 0; p < numPoints*2; p += 2) {
4910:         PetscInt fdof;
4911:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4912:         offset += fdof;
4913:       }
4914:       continue;
4915:     }
4916:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4917:     switch (mode) {
4918:     case INSERT_VALUES:
4919:       for (p = 0; p < numPoints; p++) {
4920:         const PetscInt    point = points[2*p];
4921:         const PetscInt    *perm = perms ? perms[p] : NULL;
4922:         const PetscScalar *flip = flips ? flips[p] : NULL;
4923:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4924:       } break;
4925:     case INSERT_ALL_VALUES:
4926:       for (p = 0; p < numPoints; p++) {
4927:         const PetscInt    point = points[2*p];
4928:         const PetscInt    *perm = perms ? perms[p] : NULL;
4929:         const PetscScalar *flip = flips ? flips[p] : NULL;
4930:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4931:         } break;
4932:     case INSERT_BC_VALUES:
4933:       for (p = 0; p < numPoints; p++) {
4934:         const PetscInt    point = points[2*p];
4935:         const PetscInt    *perm = perms ? perms[p] : NULL;
4936:         const PetscScalar *flip = flips ? flips[p] : NULL;
4937:         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4938:       } break;
4939:     case ADD_VALUES:
4940:       for (p = 0; p < numPoints; p++) {
4941:         const PetscInt    point = points[2*p];
4942:         const PetscInt    *perm = perms ? perms[p] : NULL;
4943:         const PetscScalar *flip = flips ? flips[p] : NULL;
4944:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4945:       } break;
4946:     case ADD_ALL_VALUES:
4947:       for (p = 0; p < numPoints; p++) {
4948:         const PetscInt    point = points[2*p];
4949:         const PetscInt    *perm = perms ? perms[p] : NULL;
4950:         const PetscScalar *flip = flips ? flips[p] : NULL;
4951:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4952:       } break;
4953:     default:
4954:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4955:     }
4956:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4957:   }
4958:   /* Cleanup points */
4959:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4960:   /* Cleanup array */
4961:   VecRestoreArray(v, &array);
4962:   return(0);
4963: }

4965: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4966: {
4967:   PetscMPIInt    rank;
4968:   PetscInt       i, j;

4972:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4973:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4974:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4975:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4976:   numCIndices = numCIndices ? numCIndices : numRIndices;
4977:   for (i = 0; i < numRIndices; i++) {
4978:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4979:     for (j = 0; j < numCIndices; j++) {
4980: #if defined(PETSC_USE_COMPLEX)
4981:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4982: #else
4983:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4984: #endif
4985:     }
4986:     PetscViewerASCIIPrintf(viewer, "\n");
4987:   }
4988:   return(0);
4989: }

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

4994:   Input Parameters:
4995: + section - The section for this data layout
4996: . point   - The point contributing dofs with these indices
4997: . off     - The global offset of this point
4998: . loff    - The local offset of each field
4999: . setBC   - The flag determining whether to include indices of bounsary values
5000: . perm    - A permutation of the dofs on this point, or NULL
5001: - indperm - A permutation of the entire indices array, or NULL

5003:   Output Parameter:
5004: . indices - Indices for dofs on this point

5006:   Level: developer

5008:   Note: The indices could be local or global, depending on the value of 'off'.
5009: */
5010: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
5011: {
5012:   PetscInt        dof;   /* The number of unknowns on this point */
5013:   PetscInt        cdof;  /* The number of constraints on this point */
5014:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5015:   PetscInt        cind = 0, k;
5016:   PetscErrorCode  ierr;

5019:   PetscSectionGetDof(section, point, &dof);
5020:   PetscSectionGetConstraintDof(section, point, &cdof);
5021:   if (!cdof || setBC) {
5022:     for (k = 0; k < dof; ++k) {
5023:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5024:       const PetscInt ind    = indperm ? indperm[preind] : preind;

5026:       indices[ind] = off + k;
5027:     }
5028:   } else {
5029:     PetscSectionGetConstraintIndices(section, point, &cdofs);
5030:     for (k = 0; k < dof; ++k) {
5031:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5032:       const PetscInt ind    = indperm ? indperm[preind] : preind;

5034:       if ((cind < cdof) && (k == cdofs[cind])) {
5035:         /* Insert check for returning constrained indices */
5036:         indices[ind] = -(off+k+1);
5037:         ++cind;
5038:       } else {
5039:         indices[ind] = off+k-cind;
5040:       }
5041:     }
5042:   }
5043:   *loff += dof;
5044:   return(0);
5045: }

5047: /*
5048:   This version only believes the point offset from the globalSection

5050:  . off - The global offset of this point
5051: */
5052: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5053: {
5054:   PetscInt       numFields, foff, f;

5058:   PetscSectionGetNumFields(section, &numFields);
5059:   for (f = 0, foff = 0; f < numFields; ++f) {
5060:     PetscInt        fdof, cfdof;
5061:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5062:     PetscInt        cind = 0, b;
5063:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5065:     PetscSectionGetFieldDof(section, point, f, &fdof);
5066:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5067:     if (!cfdof || setBC) {
5068:       for (b = 0; b < fdof; ++b) {
5069:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5070:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5072:         indices[ind] = off+foff+b;
5073:       }
5074:     } else {
5075:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5076:       for (b = 0; b < fdof; ++b) {
5077:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5078:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5080:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5081:           indices[ind] = -(off+foff+b+1);
5082:           ++cind;
5083:         } else {
5084:           indices[ind] = off+foff+b-cind;
5085:         }
5086:       }
5087:     }
5088:     foff     += (setBC ? fdof : (fdof - cfdof));
5089:     foffs[f] += fdof;
5090:   }
5091:   return(0);
5092: }

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

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

5105:   PetscSectionGetNumFields(section, &numFields);
5106:   for (f = 0; f < numFields; ++f) {
5107:     PetscInt        fdof, cfdof;
5108:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5109:     PetscInt        cind = 0, b;
5110:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5112:     PetscSectionGetFieldDof(section, point, f, &fdof);
5113:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5114:     PetscSectionGetFieldOffset(globalSection, point, f, &foff);
5115:     if (!cfdof || setBC) {
5116:       for (b = 0; b < fdof; ++b) {
5117:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5118:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5120:         indices[ind] = foff+b;
5121:       }
5122:     } else {
5123:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5124:       for (b = 0; b < fdof; ++b) {
5125:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5126:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5128:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5129:           indices[ind] = -(foff+b+1);
5130:           ++cind;
5131:         } else {
5132:           indices[ind] = foff+b-cind;
5133:         }
5134:       }
5135:     }
5136:     foffs[f] += fdof;
5137:   }
5138:   return(0);
5139: }

5141: 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)
5142: {
5143:   Mat             cMat;
5144:   PetscSection    aSec, cSec;
5145:   IS              aIS;
5146:   PetscInt        aStart = -1, aEnd = -1;
5147:   const PetscInt  *anchors;
5148:   PetscInt        numFields, f, p, q, newP = 0;
5149:   PetscInt        newNumPoints = 0, newNumIndices = 0;
5150:   PetscInt        *newPoints, *indices, *newIndices;
5151:   PetscInt        maxAnchor, maxDof;
5152:   PetscInt        newOffsets[32];
5153:   PetscInt        *pointMatOffsets[32];
5154:   PetscInt        *newPointOffsets[32];
5155:   PetscScalar     *pointMat[32];
5156:   PetscScalar     *newValues=NULL,*tmpValues;
5157:   PetscBool       anyConstrained = PETSC_FALSE;
5158:   PetscErrorCode  ierr;

5163:   PetscSectionGetNumFields(section, &numFields);

5165:   DMPlexGetAnchors(dm,&aSec,&aIS);
5166:   /* if there are point-to-point constraints */
5167:   if (aSec) {
5168:     PetscArrayzero(newOffsets, 32);
5169:     ISGetIndices(aIS,&anchors);
5170:     PetscSectionGetChart(aSec,&aStart,&aEnd);
5171:     /* figure out how many points are going to be in the new element matrix
5172:      * (we allow double counting, because it's all just going to be summed
5173:      * into the global matrix anyway) */
5174:     for (p = 0; p < 2*numPoints; p+=2) {
5175:       PetscInt b    = points[p];
5176:       PetscInt bDof = 0, bSecDof;

5178:       PetscSectionGetDof(section,b,&bSecDof);
5179:       if (!bSecDof) {
5180:         continue;
5181:       }
5182:       if (b >= aStart && b < aEnd) {
5183:         PetscSectionGetDof(aSec,b,&bDof);
5184:       }
5185:       if (bDof) {
5186:         /* this point is constrained */
5187:         /* it is going to be replaced by its anchors */
5188:         PetscInt bOff, q;

5190:         anyConstrained = PETSC_TRUE;
5191:         newNumPoints  += bDof;
5192:         PetscSectionGetOffset(aSec,b,&bOff);
5193:         for (q = 0; q < bDof; q++) {
5194:           PetscInt a = anchors[bOff + q];
5195:           PetscInt aDof;

5197:           PetscSectionGetDof(section,a,&aDof);
5198:           newNumIndices += aDof;
5199:           for (f = 0; f < numFields; ++f) {
5200:             PetscInt fDof;

5202:             PetscSectionGetFieldDof(section, a, f, &fDof);
5203:             newOffsets[f+1] += fDof;
5204:           }
5205:         }
5206:       }
5207:       else {
5208:         /* this point is not constrained */
5209:         newNumPoints++;
5210:         newNumIndices += bSecDof;
5211:         for (f = 0; f < numFields; ++f) {
5212:           PetscInt fDof;

5214:           PetscSectionGetFieldDof(section, b, f, &fDof);
5215:           newOffsets[f+1] += fDof;
5216:         }
5217:       }
5218:     }
5219:   }
5220:   if (!anyConstrained) {
5221:     if (outNumPoints)  *outNumPoints  = 0;
5222:     if (outNumIndices) *outNumIndices = 0;
5223:     if (outPoints)     *outPoints     = NULL;
5224:     if (outValues)     *outValues     = NULL;
5225:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5226:     return(0);
5227:   }

5229:   if (outNumPoints)  *outNumPoints  = newNumPoints;
5230:   if (outNumIndices) *outNumIndices = newNumIndices;

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

5234:   if (!outPoints && !outValues) {
5235:     if (offsets) {
5236:       for (f = 0; f <= numFields; f++) {
5237:         offsets[f] = newOffsets[f];
5238:       }
5239:     }
5240:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5241:     return(0);
5242:   }

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

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

5248:   /* workspaces */
5249:   if (numFields) {
5250:     for (f = 0; f < numFields; f++) {
5251:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5252:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5253:     }
5254:   }
5255:   else {
5256:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5257:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5258:   }

5260:   /* get workspaces for the point-to-point matrices */
5261:   if (numFields) {
5262:     PetscInt totalOffset, totalMatOffset;

5264:     for (p = 0; p < numPoints; p++) {
5265:       PetscInt b    = points[2*p];
5266:       PetscInt bDof = 0, bSecDof;

5268:       PetscSectionGetDof(section,b,&bSecDof);
5269:       if (!bSecDof) {
5270:         for (f = 0; f < numFields; f++) {
5271:           newPointOffsets[f][p + 1] = 0;
5272:           pointMatOffsets[f][p + 1] = 0;
5273:         }
5274:         continue;
5275:       }
5276:       if (b >= aStart && b < aEnd) {
5277:         PetscSectionGetDof(aSec, b, &bDof);
5278:       }
5279:       if (bDof) {
5280:         for (f = 0; f < numFields; f++) {
5281:           PetscInt fDof, q, bOff, allFDof = 0;

5283:           PetscSectionGetFieldDof(section, b, f, &fDof);
5284:           PetscSectionGetOffset(aSec, b, &bOff);
5285:           for (q = 0; q < bDof; q++) {
5286:             PetscInt a = anchors[bOff + q];
5287:             PetscInt aFDof;

5289:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5290:             allFDof += aFDof;
5291:           }
5292:           newPointOffsets[f][p+1] = allFDof;
5293:           pointMatOffsets[f][p+1] = fDof * allFDof;
5294:         }
5295:       }
5296:       else {
5297:         for (f = 0; f < numFields; f++) {
5298:           PetscInt fDof;

5300:           PetscSectionGetFieldDof(section, b, f, &fDof);
5301:           newPointOffsets[f][p+1] = fDof;
5302:           pointMatOffsets[f][p+1] = 0;
5303:         }
5304:       }
5305:     }
5306:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5307:       newPointOffsets[f][0] = totalOffset;
5308:       pointMatOffsets[f][0] = totalMatOffset;
5309:       for (p = 0; p < numPoints; p++) {
5310:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5311:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5312:       }
5313:       totalOffset    = newPointOffsets[f][numPoints];
5314:       totalMatOffset = pointMatOffsets[f][numPoints];
5315:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5316:     }
5317:   }
5318:   else {
5319:     for (p = 0; p < numPoints; p++) {
5320:       PetscInt b    = points[2*p];
5321:       PetscInt bDof = 0, bSecDof;

5323:       PetscSectionGetDof(section,b,&bSecDof);
5324:       if (!bSecDof) {
5325:         newPointOffsets[0][p + 1] = 0;
5326:         pointMatOffsets[0][p + 1] = 0;
5327:         continue;
5328:       }
5329:       if (b >= aStart && b < aEnd) {
5330:         PetscSectionGetDof(aSec, b, &bDof);
5331:       }
5332:       if (bDof) {
5333:         PetscInt bOff, q, allDof = 0;

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

5339:           PetscSectionGetDof(section, a, &aDof);
5340:           allDof += aDof;
5341:         }
5342:         newPointOffsets[0][p+1] = allDof;
5343:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5344:       }
5345:       else {
5346:         newPointOffsets[0][p+1] = bSecDof;
5347:         pointMatOffsets[0][p+1] = 0;
5348:       }
5349:     }
5350:     newPointOffsets[0][0] = 0;
5351:     pointMatOffsets[0][0] = 0;
5352:     for (p = 0; p < numPoints; p++) {
5353:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5354:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5355:     }
5356:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5357:   }

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

5362:   /* get the point-to-point matrices; construct newPoints */
5363:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5364:   PetscSectionGetMaxDof(section, &maxDof);
5365:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5366:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5367:   if (numFields) {
5368:     for (p = 0, newP = 0; p < numPoints; p++) {
5369:       PetscInt b    = points[2*p];
5370:       PetscInt o    = points[2*p+1];
5371:       PetscInt bDof = 0, bSecDof;

5373:       PetscSectionGetDof(section, b, &bSecDof);
5374:       if (!bSecDof) {
5375:         continue;
5376:       }
5377:       if (b >= aStart && b < aEnd) {
5378:         PetscSectionGetDof(aSec, b, &bDof);
5379:       }
5380:       if (bDof) {
5381:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5383:         fStart[0] = 0;
5384:         fEnd[0]   = 0;
5385:         for (f = 0; f < numFields; f++) {
5386:           PetscInt fDof;

5388:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5389:           fStart[f+1] = fStart[f] + fDof;
5390:           fEnd[f+1]   = fStart[f+1];
5391:         }
5392:         PetscSectionGetOffset(cSec, b, &bOff);
5393:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);

5395:         fAnchorStart[0] = 0;
5396:         fAnchorEnd[0]   = 0;
5397:         for (f = 0; f < numFields; f++) {
5398:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5400:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5401:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5402:         }
5403:         PetscSectionGetOffset(aSec, b, &bOff);
5404:         for (q = 0; q < bDof; q++) {
5405:           PetscInt a = anchors[bOff + q], aOff;

5407:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5408:           newPoints[2*(newP + q)]     = a;
5409:           newPoints[2*(newP + q) + 1] = 0;
5410:           PetscSectionGetOffset(section, a, &aOff);
5411:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);
5412:         }
5413:         newP += bDof;

5415:         if (outValues) {
5416:           /* get the point-to-point submatrix */
5417:           for (f = 0; f < numFields; f++) {
5418:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5419:           }
5420:         }
5421:       }
5422:       else {
5423:         newPoints[2 * newP]     = b;
5424:         newPoints[2 * newP + 1] = o;
5425:         newP++;
5426:       }
5427:     }
5428:   } else {
5429:     for (p = 0; p < numPoints; p++) {
5430:       PetscInt b    = points[2*p];
5431:       PetscInt o    = points[2*p+1];
5432:       PetscInt bDof = 0, bSecDof;

5434:       PetscSectionGetDof(section, b, &bSecDof);
5435:       if (!bSecDof) {
5436:         continue;
5437:       }
5438:       if (b >= aStart && b < aEnd) {
5439:         PetscSectionGetDof(aSec, b, &bDof);
5440:       }
5441:       if (bDof) {
5442:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5453:           newPoints[2*(newP + q)]     = a;
5454:           newPoints[2*(newP + q) + 1] = 0;
5455:           PetscSectionGetOffset(section, a, &aOff);
5456:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);
5457:         }
5458:         newP += bDof;

5460:         /* get the point-to-point submatrix */
5461:         if (outValues) {
5462:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5463:         }
5464:       }
5465:       else {
5466:         newPoints[2 * newP]     = b;
5467:         newPoints[2 * newP + 1] = o;
5468:         newP++;
5469:       }
5470:     }
5471:   }

5473:   if (outValues) {
5474:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5475:     PetscArrayzero(tmpValues,newNumIndices*numIndices);
5476:     /* multiply constraints on the right */
5477:     if (numFields) {
5478:       for (f = 0; f < numFields; f++) {
5479:         PetscInt oldOff = offsets[f];

5481:         for (p = 0; p < numPoints; p++) {
5482:           PetscInt cStart = newPointOffsets[f][p];
5483:           PetscInt b      = points[2 * p];
5484:           PetscInt c, r, k;
5485:           PetscInt dof;

5487:           PetscSectionGetFieldDof(section,b,f,&dof);
5488:           if (!dof) {
5489:             continue;
5490:           }
5491:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5492:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5493:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5495:             for (r = 0; r < numIndices; r++) {
5496:               for (c = 0; c < nCols; c++) {
5497:                 for (k = 0; k < dof; k++) {
5498:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5499:                 }
5500:               }
5501:             }
5502:           }
5503:           else {
5504:             /* copy this column as is */
5505:             for (r = 0; r < numIndices; r++) {
5506:               for (c = 0; c < dof; c++) {
5507:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5508:               }
5509:             }
5510:           }
5511:           oldOff += dof;
5512:         }
5513:       }
5514:     }
5515:     else {
5516:       PetscInt oldOff = 0;
5517:       for (p = 0; p < numPoints; p++) {
5518:         PetscInt cStart = newPointOffsets[0][p];
5519:         PetscInt b      = points[2 * p];
5520:         PetscInt c, r, k;
5521:         PetscInt dof;

5523:         PetscSectionGetDof(section,b,&dof);
5524:         if (!dof) {
5525:           continue;
5526:         }
5527:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5528:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5529:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5531:           for (r = 0; r < numIndices; r++) {
5532:             for (c = 0; c < nCols; c++) {
5533:               for (k = 0; k < dof; k++) {
5534:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5535:               }
5536:             }
5537:           }
5538:         }
5539:         else {
5540:           /* copy this column as is */
5541:           for (r = 0; r < numIndices; r++) {
5542:             for (c = 0; c < dof; c++) {
5543:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5544:             }
5545:           }
5546:         }
5547:         oldOff += dof;
5548:       }
5549:     }

5551:     if (multiplyLeft) {
5552:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5553:       PetscArrayzero(newValues,newNumIndices*newNumIndices);
5554:       /* multiply constraints transpose on the left */
5555:       if (numFields) {
5556:         for (f = 0; f < numFields; f++) {
5557:           PetscInt oldOff = offsets[f];

5559:           for (p = 0; p < numPoints; p++) {
5560:             PetscInt rStart = newPointOffsets[f][p];
5561:             PetscInt b      = points[2 * p];
5562:             PetscInt c, r, k;
5563:             PetscInt dof;

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

5570:               for (r = 0; r < nRows; r++) {
5571:                 for (c = 0; c < newNumIndices; c++) {
5572:                   for (k = 0; k < dof; k++) {
5573:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5574:                   }
5575:                 }
5576:               }
5577:             }
5578:             else {
5579:               /* copy this row as is */
5580:               for (r = 0; r < dof; r++) {
5581:                 for (c = 0; c < newNumIndices; c++) {
5582:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5583:                 }
5584:               }
5585:             }
5586:             oldOff += dof;
5587:           }
5588:         }
5589:       }
5590:       else {
5591:         PetscInt oldOff = 0;

5593:         for (p = 0; p < numPoints; p++) {
5594:           PetscInt rStart = newPointOffsets[0][p];
5595:           PetscInt b      = points[2 * p];
5596:           PetscInt c, r, k;
5597:           PetscInt dof;

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

5604:             for (r = 0; r < nRows; r++) {
5605:               for (c = 0; c < newNumIndices; c++) {
5606:                 for (k = 0; k < dof; k++) {
5607:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5608:                 }
5609:               }
5610:             }
5611:           }
5612:           else {
5613:             /* copy this row as is */
5614:             for (r = 0; r < dof; r++) {
5615:               for (c = 0; c < newNumIndices; c++) {
5616:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5617:               }
5618:             }
5619:           }
5620:           oldOff += dof;
5621:         }
5622:       }

5624:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5625:     }
5626:     else {
5627:       newValues = tmpValues;
5628:     }
5629:   }

5631:   /* clean up */
5632:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5633:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5635:   if (numFields) {
5636:     for (f = 0; f < numFields; f++) {
5637:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5638:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5639:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5640:     }
5641:   }
5642:   else {
5643:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5644:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5645:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5646:   }
5647:   ISRestoreIndices(aIS,&anchors);

5649:   /* output */
5650:   if (outPoints) {
5651:     *outPoints = newPoints;
5652:   }
5653:   else {
5654:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5655:   }
5656:   if (outValues) {
5657:     *outValues = newValues;
5658:   }
5659:   for (f = 0; f <= numFields; f++) {
5660:     offsets[f] = newOffsets[f];
5661:   }
5662:   return(0);
5663: }

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

5668:   Not collective

5670:   Input Parameters:
5671: + dm - The DM
5672: . section - The section describing the layout in v, or NULL to use the default section
5673: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5674: - point - The mesh point

5676:   Output parameters:
5677: + numIndices - The number of indices
5678: . indices - The indices
5679: - outOffsets - Field offset if not NULL

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

5683:   Level: advanced

5685: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5686: @*/
5687: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5688: {
5689:   PetscSection    clSection;
5690:   IS              clPoints;
5691:   const PetscInt *clp, *clperm;
5692:   const PetscInt  **perms[32] = {NULL};
5693:   PetscInt       *points = NULL, *pointsNew;
5694:   PetscInt        numPoints, numPointsNew;
5695:   PetscInt        offsets[32];
5696:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5697:   PetscErrorCode  ierr;

5705:   PetscSectionGetNumFields(section, &Nf);
5706:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5707:   PetscArrayzero(offsets, 32);
5708:   /* Get points in closure */
5709:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5710:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5711:   /* Get number of indices and indices per field */
5712:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5713:     PetscInt dof, fdof;

5715:     PetscSectionGetDof(section, points[p], &dof);
5716:     for (f = 0; f < Nf; ++f) {
5717:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5718:       offsets[f+1] += fdof;
5719:     }
5720:     Nind += dof;
5721:   }
5722:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5723:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5724:   if (!Nf) offsets[1] = Nind;
5725:   /* Get dual space symmetries */
5726:   for (f = 0; f < PetscMax(1,Nf); f++) {
5727:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5728:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5729:   }
5730:   /* Correct for hanging node constraints */
5731:   {
5732:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5733:     if (numPointsNew) {
5734:       for (f = 0; f < PetscMax(1,Nf); f++) {
5735:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5736:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5737:       }
5738:       for (f = 0; f < PetscMax(1,Nf); f++) {
5739:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5740:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5741:       }
5742:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5743:       numPoints = numPointsNew;
5744:       Nind      = NindNew;
5745:       points    = pointsNew;
5746:     }
5747:   }
5748:   /* Calculate indices */
5749:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5750:   if (Nf) {
5751:     if (outOffsets) {
5752:       PetscInt f;

5754:       for (f = 0; f <= Nf; f++) {
5755:         outOffsets[f] = offsets[f];
5756:       }
5757:     }
5758:     for (p = 0; p < numPoints; p++) {
5759:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5760:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);
5761:     }
5762:   } else {
5763:     for (p = 0, off = 0; p < numPoints; p++) {
5764:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5766:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5767:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);
5768:     }
5769:   }
5770:   /* Cleanup points */
5771:   for (f = 0; f < PetscMax(1,Nf); f++) {
5772:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5773:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5774:   }
5775:   if (numPointsNew) {
5776:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5777:   } else {
5778:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5779:   }
5780:   if (numIndices) *numIndices = Nind;
5781:   return(0);
5782: }

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

5787:   Not collective

5789:   Input Parameters:
5790: + dm - The DM
5791: . section - The section describing the layout in v, or NULL to use the default section
5792: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5793: . point - The mesh point
5794: . numIndices - The number of indices
5795: . indices - The indices
5796: - outOffsets - Field offset if not NULL

5798:   Level: advanced

5800: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5801: @*/
5802: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5803: {

5809:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5810:   return(0);
5811: }

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

5816:   Not collective

5818:   Input Parameters:
5819: + dm - The DM
5820: . section - The section describing the layout in v, or NULL to use the default section
5821: . globalSection - The section describing the layout in v, or NULL to use the default global section
5822: . A - The matrix
5823: . point - The point in the DM
5824: . values - The array of values
5825: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5830:   Level: intermediate

5832: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5833: @*/
5834: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5835: {
5836:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5837:   PetscSection        clSection;
5838:   IS                  clPoints;
5839:   PetscInt           *points = NULL, *newPoints;
5840:   const PetscInt     *clp, *clperm;
5841:   PetscInt           *indices;
5842:   PetscInt            offsets[32];
5843:   const PetscInt    **perms[32] = {NULL};
5844:   const PetscScalar **flips[32] = {NULL};
5845:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5846:   PetscScalar        *valCopy = NULL;
5847:   PetscScalar        *newValues;
5848:   PetscErrorCode      ierr;

5852:   if (!section) {DMGetSection(dm, &section);}
5854:   if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5857:   PetscSectionGetNumFields(section, &numFields);
5858:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5859:   PetscArrayzero(offsets, 32);
5860:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5861:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5862:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5863:     PetscInt fdof;

5865:     PetscSectionGetDof(section, points[p], &dof);
5866:     for (f = 0; f < numFields; ++f) {
5867:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5868:       offsets[f+1] += fdof;
5869:     }
5870:     numIndices += dof;
5871:   }
5872:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5886:         if (!numFields) {
5887:           PetscSectionGetDof(section,point,&fdof);
5888:         } else {
5889:           PetscSectionGetFieldDof(section,point,f,&fdof);
5890:         }
5891:         if (flip) {
5892:           PetscInt i, j, k;

5894:           if (!valCopy) {
5895:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5896:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5897:             values = valCopy;
5898:           }
5899:           for (i = 0; i < fdof; i++) {
5900:             PetscScalar fval = flip[i];

5902:             for (k = 0; k < numIndices; k++) {
5903:               valCopy[numIndices * (foffset + i) + k] *= fval;
5904:               valCopy[numIndices * k + (foffset + i)] *= fval;
5905:             }
5906:           }
5907:         }
5908:         foffset += fdof;
5909:       }
5910:     }
5911:   }
5912:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5913:   if (newNumPoints) {
5914:     if (valCopy) {
5915:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5916:     }
5917:     for (f = 0; f < PetscMax(1,numFields); f++) {
5918:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5919:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5920:     }
5921:     for (f = 0; f < PetscMax(1,numFields); f++) {
5922:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5923:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5924:     }
5925:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5926:     numPoints  = newNumPoints;
5927:     numIndices = newNumIndices;
5928:     points     = newPoints;
5929:     values     = newValues;
5930:   }
5931:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5932:   if (numFields) {
5933:     PetscBool useFieldOffsets;

5935:     PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
5936:     if (useFieldOffsets) {
5937:       for (p = 0; p < numPoints; p++) {
5938:         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices);
5939:       }
5940:     } else {
5941:       for (p = 0; p < numPoints; p++) {
5942:         PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5943:         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);
5944:       }
5945:     }
5946:   } else {
5947:     for (p = 0, off = 0; p < numPoints; p++) {
5948:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5949:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5950:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);
5951:     }
5952:   }
5953:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5954:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5955:   if (mesh->printFEM > 1) {
5956:     PetscInt i;
5957:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5958:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5959:     PetscPrintf(PETSC_COMM_SELF, "\n");
5960:   }
5961:   if (ierr) {
5962:     PetscMPIInt    rank;
5963:     PetscErrorCode ierr2;

5965:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5966:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5967:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5968:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5969: 
5970:   }
5971:   for (f = 0; f < PetscMax(1,numFields); f++) {
5972:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5973:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5974:   }
5975:   if (newNumPoints) {
5976:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5977:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5978:   }
5979:   else {
5980:     if (valCopy) {
5981:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5982:     }
5983:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5984:   }
5985:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5986:   return(0);
5987: }

5989: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5990: {
5991:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5992:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5993:   PetscInt       *cpoints = NULL;
5994:   PetscInt       *findices, *cindices;
5995:   const PetscInt *fclperm, *cclperm;
5996:   PetscInt        foffsets[32], coffsets[32];
5997:   CellRefiner     cellRefiner;
5998:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5999:   PetscErrorCode  ierr;

6004:   if (!fsection) {DMGetSection(dmf, &fsection);}
6006:   if (!csection) {DMGetSection(dmc, &csection);}
6008:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6010:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6013:   PetscSectionGetNumFields(fsection, &numFields);
6014:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6015:   PetscArrayzero(foffsets, 32);
6016:   PetscArrayzero(coffsets, 32);
6017:   PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6018:   PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6019:   /* Column indices */
6020:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6021:   maxFPoints = numCPoints;
6022:   /* Compress out points not in the section */
6023:   /*   TODO: Squeeze out points with 0 dof as well */
6024:   PetscSectionGetChart(csection, &pStart, &pEnd);
6025:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6026:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6027:       cpoints[q*2]   = cpoints[p];
6028:       cpoints[q*2+1] = cpoints[p+1];
6029:       ++q;
6030:     }
6031:   }
6032:   numCPoints = q;
6033:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6034:     PetscInt fdof;

6036:     PetscSectionGetDof(csection, cpoints[p], &dof);
6037:     if (!dof) continue;
6038:     for (f = 0; f < numFields; ++f) {
6039:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6040:       coffsets[f+1] += fdof;
6041:     }
6042:     numCIndices += dof;
6043:   }
6044:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6045:   /* Row indices */
6046:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6047:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6048:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6049:   for (r = 0, q = 0; r < numSubcells; ++r) {
6050:     /* TODO Map from coarse to fine cells */
6051:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6052:     /* Compress out points not in the section */
6053:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6054:     for (p = 0; p < numFPoints*2; p += 2) {
6055:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6056:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6057:         if (!dof) continue;
6058:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6059:         if (s < q) continue;
6060:         ftotpoints[q*2]   = fpoints[p];
6061:         ftotpoints[q*2+1] = fpoints[p+1];
6062:         ++q;
6063:       }
6064:     }
6065:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6066:   }
6067:   numFPoints = q;
6068:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6069:     PetscInt fdof;

6071:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6072:     if (!dof) continue;
6073:     for (f = 0; f < numFields; ++f) {
6074:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6075:       foffsets[f+1] += fdof;
6076:     }
6077:     numFIndices += dof;
6078:   }
6079:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

6081:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6082:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6083:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6084:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6085:   if (numFields) {
6086:     const PetscInt **permsF[32] = {NULL};
6087:     const PetscInt **permsC[32] = {NULL};

6089:     for (f = 0; f < numFields; f++) {
6090:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6091:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6092:     }
6093:     for (p = 0; p < numFPoints; p++) {
6094:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6095:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6096:     }
6097:     for (p = 0; p < numCPoints; p++) {
6098:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6099:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6100:     }
6101:     for (f = 0; f < numFields; f++) {
6102:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6103:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6104:     }
6105:   } else {
6106:     const PetscInt **permsF = NULL;
6107:     const PetscInt **permsC = NULL;

6109:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6110:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6111:     for (p = 0, off = 0; p < numFPoints; p++) {
6112:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6114:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6115:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6116:     }
6117:     for (p = 0, off = 0; p < numCPoints; p++) {
6118:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6120:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6121:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6122:     }
6123:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6124:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6125:   }
6126:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
6127:   /* TODO: flips */
6128:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6129:   if (ierr) {
6130:     PetscMPIInt    rank;
6131:     PetscErrorCode ierr2;

6133:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6134:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6135:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6136:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6137:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6138: 
6139:   }
6140:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6141:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6142:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6143:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6144:   return(0);
6145: }

6147: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6148: {
6149:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6150:   PetscInt      *cpoints = NULL;
6151:   PetscInt       foffsets[32], coffsets[32];
6152:   const PetscInt *fclperm, *cclperm;
6153:   CellRefiner    cellRefiner;
6154:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

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

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

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

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

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

6262:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6263:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6264:     for (p = 0, off = 0; p < numFPoints; p++) {
6265:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6267:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6268:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6269:     }
6270:     for (p = 0, off = 0; p < numCPoints; p++) {
6271:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6273:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6274:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6275:     }
6276:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6277:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6278:   }
6279:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6280:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6281:   return(0);
6282: }

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

6287:   Input Parameter:
6288: . dm - The DMPlex object

6290:   Output Parameters:
6291: + cMax - The first hybrid cell
6292: . fMax - The first hybrid face
6293: . eMax - The first hybrid edge
6294: - vMax - The first hybrid vertex

6296:   Level: developer

6298: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6299: @*/
6300: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6301: {
6302:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6303:   PetscInt       dim;

6308:   DMGetDimension(dm, &dim);
6309:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6310:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6311:   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6312:   if (eMax) *eMax = mesh->hybridPointMax[1];
6313:   if (vMax) *vMax = mesh->hybridPointMax[0];
6314:   return(0);
6315: }

6317: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6318: {
6319:   IS             is, his;
6320:   PetscInt       first = 0, stride;
6321:   PetscBool      isStride;

6325:   DMLabelGetStratumIS(depthLabel, d, &is);
6326:   PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6327:   if (isStride) {
6328:     ISStrideGetInfo(is, &first, &stride);
6329:   }
6330:   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6331:   ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6332:   DMLabelSetStratumIS(dimLabel, d, his);
6333:   ISDestroy(&his);
6334:   ISDestroy(&is);
6335:   return(0);
6336: }

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

6341:   Input Parameters:
6342: + dm   - The DMPlex object
6343: . cMax - The first hybrid cell
6344: . fMax - The first hybrid face
6345: . eMax - The first hybrid edge
6346: - vMax - The first hybrid vertex

6348:   Level: developer

6350: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6351: @*/
6352: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6353: {
6354:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6355:   PetscInt       dim;

6360:   DMGetDimension(dm, &dim);
6361:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6362:   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6363:   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6364:   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6365:   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6366:   return(0);
6367: }

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

6372:   Input Parameter:
6373: . dm   - The DMPlex object

6375:   Output Parameter:
6376: . cellHeight - The height of a cell

6378:   Level: developer

6380: .seealso DMPlexSetVTKCellHeight()
6381: @*/
6382: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6383: {
6384:   DM_Plex *mesh = (DM_Plex*) dm->data;

6389:   *cellHeight = mesh->vtkCellHeight;
6390:   return(0);
6391: }

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

6396:   Input Parameters:
6397: + dm   - The DMPlex object
6398: - cellHeight - The height of a cell

6400:   Level: developer

6402: .seealso DMPlexGetVTKCellHeight()
6403: @*/
6404: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6405: {
6406:   DM_Plex *mesh = (DM_Plex*) dm->data;

6410:   mesh->vtkCellHeight = cellHeight;
6411:   return(0);
6412: }

6414: /* We can easily have a form that takes an IS instead */
6415: PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6416: {
6417:   PetscSection   section, globalSection;
6418:   PetscInt      *numbers, p;

6422:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6423:   PetscSectionSetChart(section, pStart, pEnd);
6424:   for (p = pStart; p < pEnd; ++p) {
6425:     PetscSectionSetDof(section, p, 1);
6426:   }
6427:   PetscSectionSetUp(section);
6428:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6429:   PetscMalloc1(pEnd - pStart, &numbers);
6430:   for (p = pStart; p < pEnd; ++p) {
6431:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6432:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6433:     else                       numbers[p-pStart] += shift;
6434:   }
6435:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6436:   if (globalSize) {
6437:     PetscLayout layout;
6438:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6439:     PetscLayoutGetSize(layout, globalSize);
6440:     PetscLayoutDestroy(&layout);
6441:   }
6442:   PetscSectionDestroy(&section);
6443:   PetscSectionDestroy(&globalSection);
6444:   return(0);
6445: }

6447: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6448: {
6449:   PetscInt       cellHeight, cStart, cEnd, cMax;

6453:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6454:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6455:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6456:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6457:   DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6458:   return(0);
6459: }

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

6464:   Input Parameter:
6465: . dm   - The DMPlex object

6467:   Output Parameter:
6468: . globalCellNumbers - Global cell numbers for all cells on this process

6470:   Level: developer

6472: .seealso DMPlexGetVertexNumbering()
6473: @*/
6474: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6475: {
6476:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6481:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6482:   *globalCellNumbers = mesh->globalCellNumbers;
6483:   return(0);
6484: }

6486: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6487: {
6488:   PetscInt       vStart, vEnd, vMax;

6493:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6494:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6495:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6496:   DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6497:   return(0);
6498: }

6500: /*@
6501:   DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process

6503:   Input Parameter:
6504: . dm   - The DMPlex object

6506:   Output Parameter:
6507: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6509:   Level: developer

6511: .seealso DMPlexGetCellNumbering()
6512: @*/
6513: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6514: {
6515:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6520:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6521:   *globalVertexNumbers = mesh->globalVertexNumbers;
6522:   return(0);
6523: }

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

6528:   Input Parameter:
6529: . dm   - The DMPlex object

6531:   Output Parameter:
6532: . globalPointNumbers - Global numbers for all points on this process

6534:   Level: developer

6536: .seealso DMPlexGetCellNumbering()
6537: @*/
6538: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6539: {
6540:   IS             nums[4];
6541:   PetscInt       depths[4], gdepths[4], starts[4];
6542:   PetscInt       depth, d, shift = 0;

6547:   DMPlexGetDepth(dm, &depth);
6548:   /* For unstratified meshes use dim instead of depth */
6549:   if (depth < 0) {DMGetDimension(dm, &depth);}
6550:   for (d = 0; d <= depth; ++d) {
6551:     PetscInt end;

6553:     depths[d] = depth-d;
6554:     DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6555:     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6556:   }
6557:   PetscSortIntWithArray(depth+1, starts, depths);
6558:   MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6559:   for (d = 0; d <= depth; ++d) {
6560:     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6561:   }
6562:   for (d = 0; d <= depth; ++d) {
6563:     PetscInt pStart, pEnd, gsize;

6565:     DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6566:     DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6567:     shift += gsize;
6568:   }
6569:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6570:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6571:   return(0);
6572: }


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

6578:   Input Parameter:
6579: . dm - The DMPlex object

6581:   Output Parameter:
6582: . ranks - The rank field

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

6587:   Level: intermediate

6589: .seealso: DMView()
6590: @*/
6591: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6592: {
6593:   DM             rdm;
6594:   PetscFE        fe;
6595:   PetscScalar   *r;
6596:   PetscMPIInt    rank;
6597:   PetscInt       dim, cStart, cEnd, c;

6603:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6604:   DMClone(dm, &rdm);
6605:   DMGetDimension(rdm, &dim);
6606:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6607:   PetscObjectSetName((PetscObject) fe, "rank");
6608:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6609:   PetscFEDestroy(&fe);
6610:   DMCreateDS(rdm);
6611:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6612:   DMCreateGlobalVector(rdm, ranks);
6613:   PetscObjectSetName((PetscObject) *ranks, "partition");
6614:   VecGetArray(*ranks, &r);
6615:   for (c = cStart; c < cEnd; ++c) {
6616:     PetscScalar *lr;

6618:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6619:     *lr = rank;
6620:   }
6621:   VecRestoreArray(*ranks, &r);
6622:   DMDestroy(&rdm);
6623:   return(0);
6624: }

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

6629:   Input Parameters:
6630: + dm    - The DMPlex
6631: - label - The DMLabel

6633:   Output Parameter:
6634: . val - The label value field

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

6639:   Level: intermediate

6641: .seealso: DMView()
6642: @*/
6643: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6644: {
6645:   DM             rdm;
6646:   PetscFE        fe;
6647:   PetscScalar   *v;
6648:   PetscInt       dim, cStart, cEnd, c;

6655:   DMClone(dm, &rdm);
6656:   DMGetDimension(rdm, &dim);
6657:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6658:   PetscObjectSetName((PetscObject) fe, "label_value");
6659:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6660:   PetscFEDestroy(&fe);
6661:   DMCreateDS(rdm);
6662:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6663:   DMCreateGlobalVector(rdm, val);
6664:   PetscObjectSetName((PetscObject) *val, "label_value");
6665:   VecGetArray(*val, &v);
6666:   for (c = cStart; c < cEnd; ++c) {
6667:     PetscScalar *lv;
6668:     PetscInt     cval;

6670:     DMPlexPointGlobalRef(rdm, c, v, &lv);
6671:     DMLabelGetValue(label, c, &cval);
6672:     *lv = cval;
6673:   }
6674:   VecRestoreArray(*val, &v);
6675:   DMDestroy(&rdm);
6676:   return(0);
6677: }

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

6682:   Input Parameter:
6683: . dm - The DMPlex object

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

6687:   Level: developer

6689: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6690: @*/
6691: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6692: {
6693:   PetscSection    coneSection, supportSection;
6694:   const PetscInt *cone, *support;
6695:   PetscInt        coneSize, c, supportSize, s;
6696:   PetscInt        pStart, pEnd, p, pp, csize, ssize;
6697:   PetscBool       storagecheck = PETSC_TRUE;
6698:   PetscErrorCode  ierr;

6702:   DMPlexGetConeSection(dm, &coneSection);
6703:   DMPlexGetSupportSection(dm, &supportSection);
6704:   /* Check that point p is found in the support of its cone points, and vice versa */
6705:   DMPlexGetChart(dm, &pStart, &pEnd);
6706:   for (p = pStart; p < pEnd; ++p) {
6707:     DMPlexGetConeSize(dm, p, &coneSize);
6708:     DMPlexGetCone(dm, p, &cone);
6709:     for (c = 0; c < coneSize; ++c) {
6710:       PetscBool dup = PETSC_FALSE;
6711:       PetscInt  d;
6712:       for (d = c-1; d >= 0; --d) {
6713:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6714:       }
6715:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6716:       DMPlexGetSupport(dm, cone[c], &support);
6717:       for (s = 0; s < supportSize; ++s) {
6718:         if (support[s] == p) break;
6719:       }
6720:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6721:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6722:         for (s = 0; s < coneSize; ++s) {
6723:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6724:         }
6725:         PetscPrintf(PETSC_COMM_SELF, "\n");
6726:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6727:         for (s = 0; s < supportSize; ++s) {
6728:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6729:         }
6730:         PetscPrintf(PETSC_COMM_SELF, "\n");
6731:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6732:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6733:       }
6734:     }
6735:     DMPlexGetTreeParent(dm, p, &pp, NULL);
6736:     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6737:     DMPlexGetSupportSize(dm, p, &supportSize);
6738:     DMPlexGetSupport(dm, p, &support);
6739:     for (s = 0; s < supportSize; ++s) {
6740:       DMPlexGetConeSize(dm, support[s], &coneSize);
6741:       DMPlexGetCone(dm, support[s], &cone);
6742:       for (c = 0; c < coneSize; ++c) {
6743:         DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
6744:         if (cone[c] != pp) { c = 0; break; }
6745:         if (cone[c] == p) break;
6746:       }
6747:       if (c >= coneSize) {
6748:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6749:         for (c = 0; c < supportSize; ++c) {
6750:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6751:         }
6752:         PetscPrintf(PETSC_COMM_SELF, "\n");
6753:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6754:         for (c = 0; c < coneSize; ++c) {
6755:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6756:         }
6757:         PetscPrintf(PETSC_COMM_SELF, "\n");
6758:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6759:       }
6760:     }
6761:   }
6762:   if (storagecheck) {
6763:     PetscSectionGetStorageSize(coneSection, &csize);
6764:     PetscSectionGetStorageSize(supportSection, &ssize);
6765:     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6766:   }
6767:   return(0);
6768: }

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

6773:   Input Parameters:
6774: + dm - The DMPlex object
6775: - cellHeight - Normally 0

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

6780:   Level: developer

6782: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6783: @*/
6784: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
6785: {
6786:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6787:   PetscBool      isSimplex = PETSC_FALSE;

6792:   DMGetDimension(dm, &dim);
6793:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6794:   if (cStart < cEnd) {
6795:     DMPlexGetConeSize(dm, cStart, &c);
6796:     isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE;
6797:   }
6798:   switch (dim) {
6799:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6800:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6801:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6802:   default:
6803:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6804:   }
6805:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6806:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6807:   cMax = cMax >= 0 ? cMax : cEnd;
6808:   for (c = cStart; c < cMax; ++c) {
6809:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6811:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6812:     for (cl = 0; cl < closureSize*2; cl += 2) {
6813:       const PetscInt p = closure[cl];
6814:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6815:     }
6816:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6817:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6818:   }
6819:   for (c = cMax; c < cEnd; ++c) {
6820:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6822:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6823:     for (cl = 0; cl < closureSize*2; cl += 2) {
6824:       const PetscInt p = closure[cl];
6825:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6826:     }
6827:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6828:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6829:   }
6830:   return(0);
6831: }

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

6836:   Input Parameters:
6837: + dm - The DMPlex object
6838: - cellHeight - Normally 0

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

6842:   Level: developer

6844: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6845: @*/
6846: PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
6847: {
6848:   PetscInt       pMax[4];
6849:   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;

6854:   DMGetDimension(dm, &dim);
6855:   DMPlexGetDepth(dm, &depth);
6856:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6857:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6858:   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
6859:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6860:     for (c = cStart; c < cEnd; ++c) {
6861:       const PetscInt *cone, *ornt, *faces;
6862:       PetscInt        numFaces, faceSize, coneSize,f;
6863:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6865:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6866:       DMPlexGetConeSize(dm, c, &coneSize);
6867:       DMPlexGetCone(dm, c, &cone);
6868:       DMPlexGetConeOrientation(dm, c, &ornt);
6869:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6870:       for (cl = 0; cl < closureSize*2; cl += 2) {
6871:         const PetscInt p = closure[cl];
6872:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6873:       }
6874:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6875:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6876:       for (f = 0; f < numFaces; ++f) {
6877:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6879:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6880:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6881:           const PetscInt p = fclosure[cl];
6882:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6883:         }
6884:         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);
6885:         for (v = 0; v < fnumCorners; ++v) {
6886:           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]);
6887:         }
6888:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6889:       }
6890:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6891:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6892:     }
6893:   }
6894:   return(0);
6895: }

6897: /*@
6898:   DMPlexCheckGeometry - Check the geometry of mesh cells

6900:   Input Parameter:
6901: . dm - The DMPlex object

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

6905:   Level: developer

6907: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
6908: @*/
6909: PetscErrorCode DMPlexCheckGeometry(DM dm)
6910: {
6911:   PetscReal      detJ, J[9], refVol = 1.0;
6912:   PetscReal      vol;
6913:   PetscInt       dim, depth, d, cStart, cEnd, c, cMax;

6917:   DMGetDimension(dm, &dim);
6918:   DMPlexGetDepth(dm, &depth);
6919:   for (d = 0; d < dim; ++d) refVol *= 2.0;
6920:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6921:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6922:   cMax = cMax < 0 ? cEnd : cMax;
6923:   for (c = cStart; c < cMax; ++c) {
6924:     DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
6925:     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
6926:     PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
6927:     if (depth > 1) {
6928:       DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
6929:       if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
6930:       PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
6931:     }
6932:   }
6933:   return(0);
6934: }

6936: static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
6937: {
6938:   PetscInt i,l,n;
6939:   const PetscInt *cone;

6943:   *missingPoint = -1;
6944:   DMPlexGetConeSize(dm, p, &n);
6945:   DMPlexGetCone(dm, p, &cone);
6946:   for (i=0; i<n; i++) {
6947:     PetscFindInt(cone[i], npoints, points, &l);
6948:     if (l < 0) {
6949:       *missingPoint = cone[i];
6950:       break;
6951:     }
6952:   }
6953:   return(0);
6954: }

6956: /*@
6957:   DMPlexCheckPointSF - Check that several sufficient conditions are met for the point SF of this plex.

6959:   Input Parameters:
6960: . dm - The DMPlex object

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

6964:   Level: developer

6966: .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6967: @*/
6968: PetscErrorCode DMPlexCheckPointSF(DM dm)
6969: {
6970:   PetscSF sf;
6971:   PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
6972:   const PetscInt *locals;

6977:   DMPlexGetDepth(dm, &depth);
6978:   DMGetPointSF(dm, &sf);
6979:   PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);

6981:   /* 1) check there are no faces in 2D, cells in 3D, in interface */
6982:   DMPlexGetVTKCellHeight(dm, &d);
6983:   DMPlexGetHeightStratum(dm, d, &plo, &phi);
6984:   for (i=0; i<nleaves; i++) {
6985:     p = locals[i];
6986:     if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
6987:   }

6989:   /* 2) if some point is in interface, then all its cone points must be also in interface  */
6990:   for (i=0; i<nleaves; i++) {
6991:     p = locals[i];
6992:     DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);
6993:     if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
6994:   }
6995:   return(0);
6996: }

6998: typedef struct cell_stats
6999: {
7000:   PetscReal min, max, sum, squaresum;
7001:   PetscInt  count;
7002: } cell_stats_t;

7004: static void cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
7005: {
7006:   PetscInt i, N = *len;

7008:   for (i = 0; i < N; i++) {
7009:     cell_stats_t *A = (cell_stats_t *) a;
7010:     cell_stats_t *B = (cell_stats_t *) b;

7012:     B->min = PetscMin(A->min,B->min);
7013:     B->max = PetscMax(A->max,B->max);
7014:     B->sum += A->sum;
7015:     B->squaresum += A->squaresum;
7016:     B->count += A->count;
7017:   }
7018: }

7020: /*@
7021:   DMPlexCheckCellShape - Checks the Jacobian of the mapping and computes some minimal statistics.

7023:   Input Parameters:
7024: + dm - The DMPlex object
7025: - output - If true, statistics will be displayed on stdout

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

7029:   Level: developer

7031: .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
7032: @*/
7033: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output)
7034: {
7035:   PetscMPIInt    rank,size;
7036:   PetscInt       dim, c, cStart, cEnd, cMax, count = 0;
7037:   cell_stats_t   stats, globalStats;
7038:   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
7039:   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
7040:   DM             dmCoarse;

7045:   stats.min   = PETSC_MAX_REAL;
7046:   stats.max   = PETSC_MIN_REAL;
7047:   stats.sum   = stats.squaresum = 0.;
7048:   stats.count = 0;

7050:   DMGetCoordinateDim(dm,&dim);
7051:   PetscMalloc2(dim * dim, &J, dim * dim, &invJ);
7052:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
7053:   DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
7054:   cMax = cMax < 0 ? cEnd : cMax;
7055:   for (c = cStart; c < cMax; c++) {
7056:     PetscInt  i;
7057:     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;

7059:     DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
7060:     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
7061:     for (i = 0; i < dim * dim; i++) {
7062:       frobJ    += J[i] * J[i];
7063:       frobInvJ += invJ[i] * invJ[i];
7064:     }
7065:     cond2 = frobJ * frobInvJ;
7066:     cond  = PetscSqrtReal(cond2);

7068:     stats.min        = PetscMin(stats.min,cond);
7069:     stats.max        = PetscMax(stats.max,cond);
7070:     stats.sum       += cond;
7071:     stats.squaresum += cond2;
7072:     stats.count++;
7073:   }

7075:   MPI_Comm_size(comm,&size);
7076:   if (size > 1) {
7077:     PetscMPIInt   blockLengths[2] = {4,1};
7078:     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
7079:     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
7080:     MPI_Op        statReduce;

7082:     MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
7083:     MPI_Type_commit(&statType);
7084:     MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
7085:     MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
7086:     MPI_Op_free(&statReduce);
7087:     MPI_Type_free(&statType);
7088:   } else {
7089:     PetscArraycpy(&globalStats,&stats,1);
7090:   }

7092:   MPI_Comm_rank(comm,&rank);
7093:   if (!rank) {
7094:     count = globalStats.count;
7095:     min   = globalStats.min;
7096:     max   = globalStats.max;
7097:     mean  = globalStats.sum / globalStats.count;
7098:     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
7099:   }

7101:   if (output) {
7102:     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);
7103:   }
7104:   PetscFree2(J,invJ);

7106:   DMGetCoarseDM(dm,&dmCoarse);
7107:   if (dmCoarse) {
7108:     PetscBool isplex;

7110:     PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
7111:     if (isplex) {
7112:       DMPlexCheckCellShape(dmCoarse,output);
7113:     }
7114:   }
7115:   return(0);
7116: }

7118: /* Pointwise interpolation
7119:      Just code FEM for now
7120:      u^f = I u^c
7121:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
7122:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
7123:      I_{ij} = psi^f_i phi^c_j
7124: */
7125: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
7126: {
7127:   PetscSection   gsc, gsf;
7128:   PetscInt       m, n;
7129:   void          *ctx;
7130:   DM             cdm;
7131:   PetscBool      regular, ismatis;

7135:   DMGetGlobalSection(dmFine, &gsf);
7136:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7137:   DMGetGlobalSection(dmCoarse, &gsc);
7138:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7140:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
7141:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
7142:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7143:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
7144:   DMGetApplicationContext(dmFine, &ctx);

7146:   DMGetCoarseDM(dmFine, &cdm);
7147:   DMPlexGetRegularRefinement(dmFine, &regular);
7148:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
7149:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
7150:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
7151:   if (scaling) {
7152:     /* Use naive scaling */
7153:     DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
7154:   }
7155:   return(0);
7156: }

7158: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
7159: {
7161:   VecScatter     ctx;

7164:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
7165:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
7166:   VecScatterDestroy(&ctx);
7167:   return(0);
7168: }

7170: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
7171: {
7172:   PetscSection   gsc, gsf;
7173:   PetscInt       m, n;
7174:   void          *ctx;
7175:   DM             cdm;
7176:   PetscBool      regular;

7180:   DMGetGlobalSection(dmFine, &gsf);
7181:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7182:   DMGetGlobalSection(dmCoarse, &gsc);
7183:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7185:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
7186:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7187:   MatSetType(*mass, dmCoarse->mattype);
7188:   DMGetApplicationContext(dmFine, &ctx);

7190:   DMGetCoarseDM(dmFine, &cdm);
7191:   DMPlexGetRegularRefinement(dmFine, &regular);
7192:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
7193:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
7194:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
7195:   return(0);
7196: }

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

7201:   Input Parameter:
7202: . dm - The DMPlex object

7204:   Output Parameter:
7205: . regular - The flag

7207:   Level: intermediate

7209: .seealso: DMPlexSetRegularRefinement()
7210: @*/
7211: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7212: {
7216:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7217:   return(0);
7218: }

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

7223:   Input Parameters:
7224: + dm - The DMPlex object
7225: - regular - The flag

7227:   Level: intermediate

7229: .seealso: DMPlexGetRegularRefinement()
7230: @*/
7231: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7232: {
7235:   ((DM_Plex *) dm->data)->regularRefinement = regular;
7236:   return(0);
7237: }

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

7244:   not collective

7246:   Input Parameters:
7247: . dm - The DMPlex object

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


7254:   Level: intermediate

7256: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7257: @*/
7258: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7259: {
7260:   DM_Plex *plex = (DM_Plex *)dm->data;

7265:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7266:   if (anchorSection) *anchorSection = plex->anchorSection;
7267:   if (anchorIS) *anchorIS = plex->anchorIS;
7268:   return(0);
7269: }

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

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

7279:   collective on dm

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

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

7288:   Level: intermediate

7290: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7291: @*/
7292: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7293: {
7294:   DM_Plex        *plex = (DM_Plex *)dm->data;
7295:   PetscMPIInt    result;

7300:   if (anchorSection) {
7302:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7303:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7304:   }
7305:   if (anchorIS) {
7307:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7308:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7309:   }

7311:   PetscObjectReference((PetscObject)anchorSection);
7312:   PetscSectionDestroy(&plex->anchorSection);
7313:   plex->anchorSection = anchorSection;

7315:   PetscObjectReference((PetscObject)anchorIS);
7316:   ISDestroy(&plex->anchorIS);
7317:   plex->anchorIS = anchorIS;

7319: #if defined(PETSC_USE_DEBUG)
7320:   if (anchorIS && anchorSection) {
7321:     PetscInt size, a, pStart, pEnd;
7322:     const PetscInt *anchors;

7324:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7325:     ISGetLocalSize(anchorIS,&size);
7326:     ISGetIndices(anchorIS,&anchors);
7327:     for (a = 0; a < size; a++) {
7328:       PetscInt p;

7330:       p = anchors[a];
7331:       if (p >= pStart && p < pEnd) {
7332:         PetscInt dof;

7334:         PetscSectionGetDof(anchorSection,p,&dof);
7335:         if (dof) {
7336:           PetscErrorCode ierr2;

7338:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7339:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7340:         }
7341:       }
7342:     }
7343:     ISRestoreIndices(anchorIS,&anchors);
7344:   }
7345: #endif
7346:   /* reset the generic constraints */
7347:   DMSetDefaultConstraints(dm,NULL,NULL);
7348:   return(0);
7349: }

7351: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7352: {
7353:   PetscSection anchorSection;
7354:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

7359:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7360:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
7361:   PetscSectionGetNumFields(section,&numFields);
7362:   if (numFields) {
7363:     PetscInt f;
7364:     PetscSectionSetNumFields(*cSec,numFields);

7366:     for (f = 0; f < numFields; f++) {
7367:       PetscInt numComp;

7369:       PetscSectionGetFieldComponents(section,f,&numComp);
7370:       PetscSectionSetFieldComponents(*cSec,f,numComp);
7371:     }
7372:   }
7373:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7374:   PetscSectionGetChart(section,&sStart,&sEnd);
7375:   pStart = PetscMax(pStart,sStart);
7376:   pEnd   = PetscMin(pEnd,sEnd);
7377:   pEnd   = PetscMax(pStart,pEnd);
7378:   PetscSectionSetChart(*cSec,pStart,pEnd);
7379:   for (p = pStart; p < pEnd; p++) {
7380:     PetscSectionGetDof(anchorSection,p,&dof);
7381:     if (dof) {
7382:       PetscSectionGetDof(section,p,&dof);
7383:       PetscSectionSetDof(*cSec,p,dof);
7384:       for (f = 0; f < numFields; f++) {
7385:         PetscSectionGetFieldDof(section,p,f,&dof);
7386:         PetscSectionSetFieldDof(*cSec,p,f,dof);
7387:       }
7388:     }
7389:   }
7390:   PetscSectionSetUp(*cSec);
7391:   return(0);
7392: }

7394: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7395: {
7396:   PetscSection aSec;
7397:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7398:   const PetscInt *anchors;
7399:   PetscInt numFields, f;
7400:   IS aIS;

7405:   PetscSectionGetStorageSize(cSec, &m);
7406:   PetscSectionGetStorageSize(section, &n);
7407:   MatCreate(PETSC_COMM_SELF,cMat);
7408:   MatSetSizes(*cMat,m,n,m,n);
7409:   MatSetType(*cMat,MATSEQAIJ);
7410:   DMPlexGetAnchors(dm,&aSec,&aIS);
7411:   ISGetIndices(aIS,&anchors);
7412:   /* cSec will be a subset of aSec and section */
7413:   PetscSectionGetChart(cSec,&pStart,&pEnd);
7414:   PetscMalloc1(m+1,&i);
7415:   i[0] = 0;
7416:   PetscSectionGetNumFields(section,&numFields);
7417:   for (p = pStart; p < pEnd; p++) {
7418:     PetscInt rDof, rOff, r;

7420:     PetscSectionGetDof(aSec,p,&rDof);
7421:     if (!rDof) continue;
7422:     PetscSectionGetOffset(aSec,p,&rOff);
7423:     if (numFields) {
7424:       for (f = 0; f < numFields; f++) {
7425:         annz = 0;
7426:         for (r = 0; r < rDof; r++) {
7427:           a = anchors[rOff + r];
7428:           PetscSectionGetFieldDof(section,a,f,&aDof);
7429:           annz += aDof;
7430:         }
7431:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7432:         PetscSectionGetFieldOffset(cSec,p,f,&off);
7433:         for (q = 0; q < dof; q++) {
7434:           i[off + q + 1] = i[off + q] + annz;
7435:         }
7436:       }
7437:     }
7438:     else {
7439:       annz = 0;
7440:       for (q = 0; q < dof; q++) {
7441:         a = anchors[off + q];
7442:         PetscSectionGetDof(section,a,&aDof);
7443:         annz += aDof;
7444:       }
7445:       PetscSectionGetDof(cSec,p,&dof);
7446:       PetscSectionGetOffset(cSec,p,&off);
7447:       for (q = 0; q < dof; q++) {
7448:         i[off + q + 1] = i[off + q] + annz;
7449:       }
7450:     }
7451:   }
7452:   nnz = i[m];
7453:   PetscMalloc1(nnz,&j);
7454:   offset = 0;
7455:   for (p = pStart; p < pEnd; p++) {
7456:     if (numFields) {
7457:       for (f = 0; f < numFields; f++) {
7458:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7459:         for (q = 0; q < dof; q++) {
7460:           PetscInt rDof, rOff, r;
7461:           PetscSectionGetDof(aSec,p,&rDof);
7462:           PetscSectionGetOffset(aSec,p,&rOff);
7463:           for (r = 0; r < rDof; r++) {
7464:             PetscInt s;

7466:             a = anchors[rOff + r];
7467:             PetscSectionGetFieldDof(section,a,f,&aDof);
7468:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7469:             for (s = 0; s < aDof; s++) {
7470:               j[offset++] = aOff + s;
7471:             }
7472:           }
7473:         }
7474:       }
7475:     }
7476:     else {
7477:       PetscSectionGetDof(cSec,p,&dof);
7478:       for (q = 0; q < dof; q++) {
7479:         PetscInt rDof, rOff, r;
7480:         PetscSectionGetDof(aSec,p,&rDof);
7481:         PetscSectionGetOffset(aSec,p,&rOff);
7482:         for (r = 0; r < rDof; r++) {
7483:           PetscInt s;

7485:           a = anchors[rOff + r];
7486:           PetscSectionGetDof(section,a,&aDof);
7487:           PetscSectionGetOffset(section,a,&aOff);
7488:           for (s = 0; s < aDof; s++) {
7489:             j[offset++] = aOff + s;
7490:           }
7491:         }
7492:       }
7493:     }
7494:   }
7495:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7496:   PetscFree(i);
7497:   PetscFree(j);
7498:   ISRestoreIndices(aIS,&anchors);
7499:   return(0);
7500: }

7502: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7503: {
7504:   DM_Plex        *plex = (DM_Plex *)dm->data;
7505:   PetscSection   anchorSection, section, cSec;
7506:   Mat            cMat;

7511:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7512:   if (anchorSection) {
7513:     PetscInt Nf;

7515:     DMGetSection(dm,&section);
7516:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7517:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7518:     DMGetNumFields(dm,&Nf);
7519:     if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7520:     DMSetDefaultConstraints(dm,cSec,cMat);
7521:     PetscSectionDestroy(&cSec);
7522:     MatDestroy(&cMat);
7523:   }
7524:   return(0);
7525: }

7527: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7528: {
7529:   IS             subis;
7530:   PetscSection   section, subsection;

7534:   DMGetDefaultSection(dm, &section);
7535:   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7536:   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7537:   /* Create subdomain */
7538:   DMPlexFilter(dm, label, value, subdm);
7539:   /* Create submodel */
7540:   DMPlexCreateSubpointIS(*subdm, &subis);
7541:   PetscSectionCreateSubmeshSection(section, subis, &subsection);
7542:   ISDestroy(&subis);
7543:   DMSetDefaultSection(*subdm, subsection);
7544:   PetscSectionDestroy(&subsection);
7545:   DMCopyDisc(dm, *subdm);
7546:   /* Create map from submodel to global model */
7547:   if (is) {
7548:     PetscSection    sectionGlobal, subsectionGlobal;
7549:     IS              spIS;
7550:     const PetscInt *spmap;
7551:     PetscInt       *subIndices;
7552:     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
7553:     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];

7555:     DMPlexCreateSubpointIS(*subdm, &spIS);
7556:     ISGetIndices(spIS, &spmap);
7557:     PetscSectionGetNumFields(section, &Nf);
7558:     DMGetDefaultGlobalSection(dm, &sectionGlobal);
7559:     DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);
7560:     PetscSectionGetChart(subsection, &pStart, &pEnd);
7561:     for (p = pStart; p < pEnd; ++p) {
7562:       PetscInt gdof, pSubSize  = 0;

7564:       PetscSectionGetDof(sectionGlobal, p, &gdof);
7565:       if (gdof > 0) {
7566:         for (f = 0; f < Nf; ++f) {
7567:           PetscInt fdof, fcdof;

7569:           PetscSectionGetFieldDof(subsection, p, f, &fdof);
7570:           PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7571:           pSubSize += fdof-fcdof;
7572:         }
7573:         subSize += pSubSize;
7574:         if (pSubSize) {
7575:           if (bs < 0) {
7576:             bs = pSubSize;
7577:           } else if (bs != pSubSize) {
7578:             /* Layout does not admit a pointwise block size */
7579:             bs = 1;
7580:           }
7581:         }
7582:       }
7583:     }
7584:     /* Must have same blocksize on all procs (some might have no points) */
7585:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7586:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7587:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7588:     else                            {bs = bsMinMax[0];}
7589:     PetscMalloc1(subSize, &subIndices);
7590:     for (p = pStart; p < pEnd; ++p) {
7591:       PetscInt gdof, goff;

7593:       PetscSectionGetDof(subsectionGlobal, p, &gdof);
7594:       if (gdof > 0) {
7595:         const PetscInt point = spmap[p];

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

7601:           /* Can get rid of this loop by storing field information in the global section */
7602:           for (f2 = 0; f2 < f; ++f2) {
7603:             PetscSectionGetFieldDof(section, p, f2, &fdof);
7604:             PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7605:             poff += fdof-fcdof;
7606:           }
7607:           PetscSectionGetFieldDof(section, p, f, &fdof);
7608:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7609:           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7610:             subIndices[subOff] = goff+poff+fc;
7611:           }
7612:         }
7613:       }
7614:     }
7615:     ISRestoreIndices(spIS, &spmap);
7616:     ISDestroy(&spIS);
7617:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7618:     if (bs > 1) {
7619:       /* We need to check that the block size does not come from non-contiguous fields */
7620:       PetscInt i, j, set = 1;
7621:       for (i = 0; i < subSize; i += bs) {
7622:         for (j = 0; j < bs; ++j) {
7623:           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7624:         }
7625:       }
7626:       if (set) {ISSetBlockSize(*is, bs);}
7627:     }
7628:     /* Attach nullspace */
7629:     for (f = 0; f < Nf; ++f) {
7630:       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7631:       if ((*subdm)->nullspaceConstructors[f]) break;
7632:     }
7633:     if (f < Nf) {
7634:       MatNullSpace nullSpace;

7636:       (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7637:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7638:       MatNullSpaceDestroy(&nullSpace);
7639:     }
7640:   }
7641:   return(0);
7642: }