Actual source code: plex.c

petsc-3.11.4 2019-09-28
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_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;

 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:     PetscReal    scale         = 2.0;
675:     PetscReal    tikzscale     = 1.0;
676:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
677:     double       tcoords[3];
678:     PetscScalar *coords;
679:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
680:     PetscMPIInt  rank, size;
681:     char         **names, **colors, **lcolors;
682:     PetscBool    plotEdges, flg;

684:     DMGetDimension(dm, &dim);
685:     DMPlexGetDepth(dm, &depth);
686:     DMGetNumLabels(dm, &numLabels);
687:     numLabels  = PetscMax(numLabels, 10);
688:     numColors  = 10;
689:     numLColors = 10;
690:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
691:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
692:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);
693:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
694:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
695:     if (!useLabels) numLabels = 0;
696:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
697:     if (!useColors) {
698:       numColors = 3;
699:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
700:     }
701:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
702:     if (!useColors) {
703:       numLColors = 4;
704:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
705:     }
706:     plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
707:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);
708:     if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
709:     if (depth < dim) plotEdges = PETSC_FALSE;
710:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
711:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
712:     PetscObjectGetName((PetscObject) dm, &name);
713:     PetscViewerASCIIPrintf(viewer, "\
714: \\documentclass[tikz]{standalone}\n\n\
715: \\usepackage{pgflibraryshapes}\n\
716: \\usetikzlibrary{backgrounds}\n\
717: \\usetikzlibrary{arrows}\n\
718: \\begin{document}\n");
719:     if (size > 1) {
720:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
721:       for (p = 0; p < size; ++p) {
722:         if (p > 0 && p == size-1) {
723:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
724:         } else if (p > 0) {
725:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
726:         }
727:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
728:       }
729:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
730:     }
731:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", tikzscale);
732:     /* Plot vertices */
733:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
734:     VecGetArray(coordinates, &coords);
735:     PetscViewerASCIIPushSynchronized(viewer);
736:     for (v = vStart; v < vEnd; ++v) {
737:       PetscInt  off, dof, d;
738:       PetscBool isLabeled = PETSC_FALSE;

740:       PetscSectionGetDof(coordSection, v, &dof);
741:       PetscSectionGetOffset(coordSection, v, &off);
742:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
743:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
744:       for (d = 0; d < dof; ++d) {
745:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
746:         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
747:       }
748:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
749:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
750:       for (d = 0; d < dof; ++d) {
751:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
752:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
753:       }
754:       color = colors[rank%numColors];
755:       for (l = 0; l < numLabels; ++l) {
756:         PetscInt val;
757:         DMGetLabelValue(dm, names[l], v, &val);
758:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
759:       }
760:       if (useNumbers) {
761:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
762:       } else {
763:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
764:       }
765:     }
766:     VecRestoreArray(coordinates, &coords);
767:     PetscViewerFlush(viewer);
768:     /* Plot cells */
769:     DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
770:     DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
771:     if (dim == 3 || !useNumbers) {
772:       for (e = eStart; e < eEnd; ++e) {
773:         const PetscInt *cone;

775:         color = colors[rank%numColors];
776:         for (l = 0; l < numLabels; ++l) {
777:           PetscInt val;
778:           DMGetLabelValue(dm, names[l], e, &val);
779:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
780:         }
781:         DMPlexGetCone(dm, e, &cone);
782:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
783:       }
784:     } else {
785:       for (c = cStart; c < cEnd; ++c) {
786:         PetscInt *closure = NULL;
787:         PetscInt  closureSize, firstPoint = -1;

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

794:           if ((point < vStart) || (point >= vEnd)) continue;
795:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
796:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
797:           if (firstPoint < 0) firstPoint = point;
798:         }
799:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
800:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
801:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
802:       }
803:     }
804:     VecGetArray(coordinates, &coords);
805:     for (c = cStart; c < cEnd; ++c) {
806:       double    ccoords[3] = {0.0, 0.0, 0.0};
807:       PetscBool isLabeled  = PETSC_FALSE;
808:       PetscInt *closure    = NULL;
809:       PetscInt  closureSize, dof, d, n = 0;

811:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
812:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
813:       for (p = 0; p < closureSize*2; p += 2) {
814:         const PetscInt point = closure[p];
815:         PetscInt       off;

817:         if ((point < vStart) || (point >= vEnd)) continue;
818:         PetscSectionGetDof(coordSection, point, &dof);
819:         PetscSectionGetOffset(coordSection, point, &off);
820:         for (d = 0; d < dof; ++d) {
821:           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
822:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
823:         }
824:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
825:         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
826:         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
827:         ++n;
828:       }
829:       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
830:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
831:       for (d = 0; d < dof; ++d) {
832:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
833:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d]);
834:       }
835:       color = colors[rank%numColors];
836:       for (l = 0; l < numLabels; ++l) {
837:         PetscInt val;
838:         DMGetLabelValue(dm, names[l], c, &val);
839:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
840:       }
841:       if (useNumbers) {
842:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);
843:       } else {
844:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);
845:       }
846:     }
847:     VecRestoreArray(coordinates, &coords);
848:     /* Plot edges */
849:     if (plotEdges) {
850:       VecGetArray(coordinates, &coords);
851:       PetscViewerASCIIPrintf(viewer, "\\path\n");
852:       for (e = eStart; e < eEnd; ++e) {
853:         const PetscInt *cone;
854:         PetscInt        coneSize, offA, offB, dof, d;

856:         DMPlexGetConeSize(dm, e, &coneSize);
857:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
858:         DMPlexGetCone(dm, e, &cone);
859:         PetscSectionGetDof(coordSection, cone[0], &dof);
860:         PetscSectionGetOffset(coordSection, cone[0], &offA);
861:         PetscSectionGetOffset(coordSection, cone[1], &offB);
862:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
863:         for (d = 0; d < dof; ++d) {
864:           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
865:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
866:         }
867:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
868:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
869:         for (d = 0; d < dof; ++d) {
870:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
871:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
872:         }
873:         color = colors[rank%numColors];
874:         for (l = 0; l < numLabels; ++l) {
875:           PetscInt val;
876:           DMGetLabelValue(dm, names[l], v, &val);
877:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
878:         }
879:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
880:       }
881:       VecRestoreArray(coordinates, &coords);
882:       PetscViewerFlush(viewer);
883:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
884:     }
885:     PetscViewerFlush(viewer);
886:     PetscViewerASCIIPopSynchronized(viewer);
887:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
888:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
889:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
890:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
891:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
892:     PetscFree3(names, colors, lcolors);
893:   } else {
894:     MPI_Comm    comm;
895:     PetscInt   *sizes, *hybsizes;
896:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
897:     PetscInt    pStart, pEnd, p;
898:     PetscInt    numLabels, l;
899:     const char *name;
900:     PetscMPIInt size;

902:     PetscObjectGetComm((PetscObject)dm,&comm);
903:     MPI_Comm_size(comm, &size);
904:     DMGetDimension(dm, &dim);
905:     DMPlexGetVTKCellHeight(dm, &cellHeight);
906:     PetscObjectGetName((PetscObject) dm, &name);
907:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
908:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
909:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
910:     DMPlexGetDepth(dm, &locDepth);
911:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
912:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);
913:     PetscCalloc2(size,&sizes,size,&hybsizes);
914:     if (depth == 1) {
915:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
916:       pEnd = pEnd - pStart;
917:       pMax[0] -= pStart;
918:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
919:       MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
920:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
921:       for (p = 0; p < size; ++p) {
922:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
923:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
924:       }
925:       PetscViewerASCIIPrintf(viewer, "\n");
926:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
927:       pEnd = pEnd - pStart;
928:       pMax[depth] -= pStart;
929:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
930:       MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
931:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
932:       for (p = 0; p < size; ++p) {
933:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
934:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
935:       }
936:       PetscViewerASCIIPrintf(viewer, "\n");
937:     } else {
938:       PetscMPIInt rank;
939:       MPI_Comm_rank(comm, &rank);
940:       for (d = 0; d <= dim; d++) {
941:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
942:         pEnd    -= pStart;
943:         pMax[d] -= pStart;
944:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
945:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
946:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
947:         for (p = 0; p < size; ++p) {
948:           if (!rank) {
949:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
950:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
951:           }
952:         }
953:         PetscViewerASCIIPrintf(viewer, "\n");
954:       }
955:     }
956:     PetscFree2(sizes,hybsizes);
957:     DMGetNumLabels(dm, &numLabels);
958:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
959:     for (l = 0; l < numLabels; ++l) {
960:       DMLabel         label;
961:       const char     *name;
962:       IS              valueIS;
963:       const PetscInt *values;
964:       PetscInt        numValues, v;

966:       DMGetLabelName(dm, l, &name);
967:       DMGetLabel(dm, name, &label);
968:       DMLabelGetNumValues(label, &numValues);
969:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
970:       DMLabelGetValueIS(label, &valueIS);
971:       ISGetIndices(valueIS, &values);
972:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
973:       for (v = 0; v < numValues; ++v) {
974:         PetscInt size;

976:         DMLabelGetStratumSize(label, values[v], &size);
977:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
978:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
979:       }
980:       PetscViewerASCIIPrintf(viewer, ")\n");
981:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
982:       ISRestoreIndices(valueIS, &values);
983:       ISDestroy(&valueIS);
984:     }
985:     /* If no fields are specified, people do not want to see adjacency */
986:     if (dm->Nf) {
987:       PetscInt f;

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

992:         PetscObjectGetName(dm->fields[f].disc, &name);
993:         if (numLabels) {PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);}
994:         PetscViewerASCIIPushTab(viewer);
995:         if (dm->fields[f].label) {DMLabelView(dm->fields[f].label, viewer);}
996:         if (dm->fields[f].adjacency[0]) {
997:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");}
998:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");}
999:         } else {
1000:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");}
1001:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");}
1002:         }
1003:         PetscViewerASCIIPopTab(viewer);
1004:       }
1005:     }
1006:     DMGetCoarseDM(dm, &cdm);
1007:     if (cdm) {
1008:       PetscViewerASCIIPushTab(viewer);
1009:       DMPlexView_Ascii(cdm, viewer);
1010:       PetscViewerASCIIPopTab(viewer);
1011:     }
1012:   }
1013:   return(0);
1014: }

1016: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1017: {
1018:   PetscDraw          draw;
1019:   DM                 cdm;
1020:   PetscSection       coordSection;
1021:   Vec                coordinates;
1022:   const PetscScalar *coords;
1023:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1024:   PetscBool          isnull;
1025:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
1026:   PetscMPIInt        rank;
1027:   PetscErrorCode     ierr;

1030:   DMGetCoordinateDim(dm, &dim);
1031:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1032:   DMGetCoordinateDM(dm, &cdm);
1033:   DMGetSection(cdm, &coordSection);
1034:   DMGetCoordinatesLocal(dm, &coordinates);
1035:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1036:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

1038:   PetscViewerDrawGetDraw(viewer, 0, &draw);
1039:   PetscDrawIsNull(draw, &isnull);
1040:   if (isnull) return(0);
1041:   PetscDrawSetTitle(draw, "Mesh");

1043:   VecGetLocalSize(coordinates, &N);
1044:   VecGetArrayRead(coordinates, &coords);
1045:   for (c = 0; c < N; c += dim) {
1046:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1047:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1048:   }
1049:   VecRestoreArrayRead(coordinates, &coords);
1050:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1051:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1052:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1053:   PetscDrawClear(draw);

1055:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1056:   for (c = cStart; c < cEnd; ++c) {
1057:     PetscScalar *coords = NULL;
1058:     PetscInt     numCoords,coneSize;

1060:     DMPlexGetConeSize(dm, c, &coneSize);
1061:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1062:     switch (coneSize) {
1063:     case 3:
1064:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1065:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1066:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1067:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1068:       break;
1069:     case 4:
1070:       PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1071:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1072:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1073:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1074:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1075:       break;
1076:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1077:     }
1078:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1079:   }
1080:   for (c = cStart; c < cEnd; ++c) {
1081:     PetscScalar *coords = NULL;
1082:     PetscInt     numCoords,coneSize;

1084:     DMPlexGetConeSize(dm, c, &coneSize);
1085:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1086:     switch (coneSize) {
1087:     case 3:
1088:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1089:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1090:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1091:       break;
1092:     case 4:
1093:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1094:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1095:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
1096:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1097:       break;
1098:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1099:     }
1100:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1101:   }
1102:   PetscDrawFlush(draw);
1103:   PetscDrawPause(draw);
1104:   PetscDrawSave(draw);
1105:   return(0);
1106: }

1108: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1109: {
1110:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1111:   char           name[PETSC_MAX_PATH_LEN];

1117:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
1118:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
1119:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
1120:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
1121:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
1122:   if (iascii) {
1123:     PetscViewerFormat format;
1124:     PetscViewerGetFormat(viewer, &format);
1125:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1126:       DMPlexView_GLVis(dm, viewer);
1127:     } else {
1128:       DMPlexView_Ascii(dm, viewer);
1129:     }
1130:   } else if (ishdf5) {
1131: #if defined(PETSC_HAVE_HDF5)
1132:     DMPlexView_HDF5_Internal(dm, viewer);
1133: #else
1134:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1135: #endif
1136:   } else if (isvtk) {
1137:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
1138:   } else if (isdraw) {
1139:     DMPlexView_Draw(dm, viewer);
1140:   } else if (isglvis) {
1141:     DMPlexView_GLVis(dm, viewer);
1142:   } else {
1143:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1144:   }
1145:   /* Optionally view the partition */
1146:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1147:   if (flg) {
1148:     Vec ranks;
1149:     DMPlexCreateRankField(dm, &ranks);
1150:     VecView(ranks, viewer);
1151:     VecDestroy(&ranks);
1152:   }
1153:   /* Optionally view a label */
1154:   PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, PETSC_MAX_PATH_LEN, &flg);
1155:   if (flg) {
1156:     DMLabel label;
1157:     Vec     val;

1159:     DMGetLabel(dm, name, &label);
1160:     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1161:     DMPlexCreateLabelField(dm, label, &val);
1162:     VecView(val, viewer);
1163:     VecDestroy(&val);
1164:   }
1165:   return(0);
1166: }

1168: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1169: {
1170:   PetscBool      ishdf5;

1176:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1177:   if (ishdf5) {
1178: #if defined(PETSC_HAVE_HDF5)
1179:     PetscViewerFormat format;
1180:     PetscViewerGetFormat(viewer, &format);
1181:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1182:       DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1183:     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1184:       DMPlexLoad_HDF5_Internal(dm, viewer);
1185:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1186: #else
1187:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1188: #endif
1189:   } else {
1190:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1191:   }
1192:   return(0);
1193: }

1195: PetscErrorCode DMDestroy_Plex(DM dm)
1196: {
1197:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1201:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1202:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1203:   if (--mesh->refct > 0) return(0);
1204:   PetscSectionDestroy(&mesh->coneSection);
1205:   PetscFree(mesh->cones);
1206:   PetscFree(mesh->coneOrientations);
1207:   PetscSectionDestroy(&mesh->supportSection);
1208:   PetscSectionDestroy(&mesh->subdomainSection);
1209:   PetscFree(mesh->supports);
1210:   PetscFree(mesh->facesTmp);
1211:   PetscFree(mesh->tetgenOpts);
1212:   PetscFree(mesh->triangleOpts);
1213:   PetscPartitionerDestroy(&mesh->partitioner);
1214:   DMLabelDestroy(&mesh->subpointMap);
1215:   ISDestroy(&mesh->globalVertexNumbers);
1216:   ISDestroy(&mesh->globalCellNumbers);
1217:   PetscSectionDestroy(&mesh->anchorSection);
1218:   ISDestroy(&mesh->anchorIS);
1219:   PetscSectionDestroy(&mesh->parentSection);
1220:   PetscFree(mesh->parents);
1221:   PetscFree(mesh->childIDs);
1222:   PetscSectionDestroy(&mesh->childSection);
1223:   PetscFree(mesh->children);
1224:   DMDestroy(&mesh->referenceTree);
1225:   PetscGridHashDestroy(&mesh->lbox);
1226:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1227:   PetscFree(mesh);
1228:   return(0);
1229: }

1231: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1232: {
1233:   PetscSection           sectionGlobal;
1234:   PetscInt               bs = -1, mbs;
1235:   PetscInt               localSize;
1236:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1237:   PetscErrorCode         ierr;
1238:   MatType                mtype;
1239:   ISLocalToGlobalMapping ltog;

1242:   MatInitializePackage();
1243:   mtype = dm->mattype;
1244:   DMGetGlobalSection(dm, &sectionGlobal);
1245:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1246:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1247:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1248:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1249:   MatSetType(*J, mtype);
1250:   MatSetFromOptions(*J);
1251:   MatGetBlockSize(*J, &mbs);
1252:   if (mbs > 1) bs = mbs;
1253:   PetscStrcmp(mtype, MATSHELL, &isShell);
1254:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1255:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1256:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1257:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1258:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1259:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1260:   PetscStrcmp(mtype, MATIS, &isMatIS);
1261:   if (!isShell) {
1262:     PetscSection subSection;
1263:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1264:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1265:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1272:       DMGetSection(dm, &section);
1273:       PetscSectionGetStorageSize(section, &size);
1274:       PetscMalloc1(size,&ltogidx);
1275:       DMPlexGetSubdomainSection(dm, &subSection);
1276:     } else {
1277:       DMGetLocalToGlobalMapping(dm,&ltog);
1278:     }
1279:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1280:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1281:       PetscInt bdof;

1283:       PetscSectionGetDof(sectionGlobal, p, &dof);
1284:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1285:       dof  = dof < 0 ? -(dof+1) : dof;
1286:       bdof = cdof && (dof-cdof) ? 1 : dof;
1287:       if (dof) {
1288:         if (bs < 0)          {bs = bdof;}
1289:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1290:       }
1291:       if (isMatIS) {
1292:         PetscInt loff,c,off;
1293:         PetscSectionGetOffset(subSection, p, &loff);
1294:         PetscSectionGetOffset(sectionGlobal, p, &off);
1295:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1296:       }
1297:     }
1298:     /* Must have same blocksize on all procs (some might have no points) */
1299:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1300:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1301:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1302:     else                            {bs = bsMinMax[0];}
1303:     bs = bs < 0 ? 1 : bs;
1304:     if (isMatIS) {
1305:       PetscInt l;
1306:       /* Must reduce indices by blocksize */
1307:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1308:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1309:     }
1310:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1311:     if (isMatIS) {
1312:       ISLocalToGlobalMappingDestroy(&ltog);
1313:     }
1314:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1315:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1316:     PetscFree4(dnz, onz, dnzu, onzu);
1317:   }
1318:   MatSetDM(*J, dm);
1319:   return(0);
1320: }

1322: /*@
1323:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1325:   Not collective

1327:   Input Parameter:
1328: . mesh - The DMPlex

1330:   Output Parameters:
1331: . subsection - The subdomain section

1333:   Level: developer

1335: .seealso:
1336: @*/
1337: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1338: {
1339:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1344:   if (!mesh->subdomainSection) {
1345:     PetscSection section;
1346:     PetscSF      sf;

1348:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1349:     DMGetSection(dm,&section);
1350:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1351:     PetscSFDestroy(&sf);
1352:   }
1353:   *subsection = mesh->subdomainSection;
1354:   return(0);
1355: }

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

1360:   Not collective

1362:   Input Parameter:
1363: . mesh - The DMPlex

1365:   Output Parameters:
1366: + pStart - The first mesh point
1367: - pEnd   - The upper bound for mesh points

1369:   Level: beginner

1371: .seealso: DMPlexCreate(), DMPlexSetChart()
1372: @*/
1373: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1374: {
1375:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1380:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1381:   return(0);
1382: }

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

1387:   Not collective

1389:   Input Parameters:
1390: + mesh - The DMPlex
1391: . pStart - The first mesh point
1392: - pEnd   - The upper bound for mesh points

1394:   Output Parameters:

1396:   Level: beginner

1398: .seealso: DMPlexCreate(), DMPlexGetChart()
1399: @*/
1400: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1401: {
1402:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1407:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1408:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1409:   return(0);
1410: }

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

1415:   Not collective

1417:   Input Parameters:
1418: + mesh - The DMPlex
1419: - p - The point, which must lie in the chart set with DMPlexSetChart()

1421:   Output Parameter:
1422: . size - The cone size for point p

1424:   Level: beginner

1426: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1427: @*/
1428: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1429: {
1430:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1436:   PetscSectionGetDof(mesh->coneSection, p, size);
1437:   return(0);
1438: }

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

1443:   Not collective

1445:   Input Parameters:
1446: + mesh - The DMPlex
1447: . p - The point, which must lie in the chart set with DMPlexSetChart()
1448: - size - The cone size for point p

1450:   Output Parameter:

1452:   Note:
1453:   This should be called after DMPlexSetChart().

1455:   Level: beginner

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

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

1468:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1469:   return(0);
1470: }

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

1475:   Not collective

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

1482:   Output Parameter:

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

1487:   Level: beginner

1489: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1490: @*/
1491: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1492: {
1493:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1494:   PetscInt       csize;

1499:   PetscSectionAddDof(mesh->coneSection, p, size);
1500:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1502:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1503:   return(0);
1504: }

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

1509:   Not collective

1511:   Input Parameters:
1512: + dm - The DMPlex
1513: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1518:   Level: beginner

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

1526: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1527: @*/
1528: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1529: {
1530:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1531:   PetscInt       off;

1537:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1538:   *cone = &mesh->cones[off];
1539:   return(0);
1540: }

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

1545:   Not collective

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

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

1555:   Level: intermediate

1557: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1558: @*/
1559: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1560: {
1561:   PetscSection        cs, newcs;
1562:   PetscInt            *cones;
1563:   PetscInt            *newarr=NULL;
1564:   PetscInt            n;
1565:   PetscErrorCode      ierr;

1568:   DMPlexGetCones(dm, &cones);
1569:   DMPlexGetConeSection(dm, &cs);
1570:   PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1571:   if (pConesSection) *pConesSection = newcs;
1572:   if (pCones) {
1573:     PetscSectionGetStorageSize(newcs, &n);
1574:     ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1575:   }
1576:   return(0);
1577: }

1579: static PetscErrorCode DMPlexGetConeRecursive_Private(DM dm, PetscInt *n_inout, const PetscInt points[], PetscInt *offset_inout, PetscInt buf[])
1580: {
1581:   PetscInt p, n, cn, i;
1582:   const PetscInt *cone;

1586:   n = *n_inout;
1587:   *n_inout = 0;
1588:   for (i=0; i<n; i++) {
1589:     p = points[i];
1590:     DMPlexGetConeSize(dm, p, &cn);
1591:     if (!cn) {
1592:       cn = 1;
1593:       if (buf) {
1594:         buf[*offset_inout] = p;
1595:         ++(*offset_inout);
1596:       }
1597:     } else {
1598:       DMPlexGetCone(dm, p, &cone);
1599:       DMPlexGetConeRecursive_Private(dm, &cn, cone, offset_inout, buf);
1600:     }
1601:     *n_inout += cn;
1602:   }
1603:   return(0);
1604: }

1606: /*@C
1607:   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.

1609:   Not collective

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

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

1618:   Level: advanced

1620: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple()
1621: @*/
1622: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS p, IS *pCones)
1623: {
1624:   const PetscInt      *arr=NULL;
1625:   PetscInt            *cpoints=NULL;
1626:   PetscInt            n, cn;
1627:   PetscInt            zero;
1628:   PetscErrorCode      ierr;

1631:   ISGetLocalSize(p, &n);
1632:   ISGetIndices(p, &arr);
1633:   zero = 0;
1634:   /* first figure out the total number of returned points */
1635:   cn = n;
1636:   DMPlexGetConeRecursive_Private(dm, &cn, arr, &zero, NULL);
1637:   PetscMalloc1(cn, &cpoints);
1638:   /* now get recursive cones themselves */
1639:   DMPlexGetConeRecursive_Private(dm, &n, arr, &zero, cpoints);
1640:   ISCreateGeneral(PetscObjectComm((PetscObject)p), n, cpoints, PETSC_OWN_POINTER, pCones);
1641:   ISRestoreIndices(p, &arr);
1642:   return(0);
1643: }

1645: /*@
1646:   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

1648:   Not collective

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

1655:   Output Parameter:

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

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

1662:   Level: beginner

1664: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1665: @*/
1666: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1667: {
1668:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1669:   PetscInt       pStart, pEnd;
1670:   PetscInt       dof, off, c;

1675:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1676:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1678:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1679:   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);
1680:   for (c = 0; c < dof; ++c) {
1681:     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);
1682:     mesh->cones[off+c] = cone[c];
1683:   }
1684:   return(0);
1685: }

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

1690:   Not collective

1692:   Input Parameters:
1693: + mesh - The DMPlex
1694: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1702:   Level: beginner

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

1710: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1711: @*/
1712: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1713: {
1714:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1715:   PetscInt       off;

1720: #if defined(PETSC_USE_DEBUG)
1721:   {
1722:     PetscInt dof;
1723:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1725:   }
1726: #endif
1727:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1729:   *coneOrientation = &mesh->coneOrientations[off];
1730:   return(0);
1731: }

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

1736:   Not collective

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

1746:   Output Parameter:

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

1751:   Level: beginner

1753: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1754: @*/
1755: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1756: {
1757:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1758:   PetscInt       pStart, pEnd;
1759:   PetscInt       dof, off, c;

1764:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1765:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1767:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1768:   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);
1769:   for (c = 0; c < dof; ++c) {
1770:     PetscInt cdof, o = coneOrientation[c];

1772:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1773:     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);
1774:     mesh->coneOrientations[off+c] = o;
1775:   }
1776:   return(0);
1777: }

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

1782:   Not collective

1784:   Input Parameters:
1785: + mesh - The DMPlex
1786: . p - The point, which must lie in the chart set with DMPlexSetChart()
1787: . conePos - The local index in the cone where the point should be put
1788: - conePoint - The mesh point to insert

1790:   Level: beginner

1792: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1793: @*/
1794: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1795: {
1796:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1797:   PetscInt       pStart, pEnd;
1798:   PetscInt       dof, off;

1803:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1804:   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);
1805:   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);
1806:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1807:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1808:   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);
1809:   mesh->cones[off+conePos] = conePoint;
1810:   return(0);
1811: }

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

1816:   Not collective

1818:   Input Parameters:
1819: + mesh - The DMPlex
1820: . p - The point, which must lie in the chart set with DMPlexSetChart()
1821: . conePos - The local index in the cone where the point should be put
1822: - coneOrientation - The point orientation to insert

1824:   Level: beginner

1826: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1827: @*/
1828: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1829: {
1830:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1831:   PetscInt       pStart, pEnd;
1832:   PetscInt       dof, off;

1837:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1838:   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);
1839:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1840:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1841:   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);
1842:   mesh->coneOrientations[off+conePos] = coneOrientation;
1843:   return(0);
1844: }

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

1849:   Not collective

1851:   Input Parameters:
1852: + mesh - The DMPlex
1853: - p - The point, which must lie in the chart set with DMPlexSetChart()

1855:   Output Parameter:
1856: . size - The support size for point p

1858:   Level: beginner

1860: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1861: @*/
1862: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1863: {
1864:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1870:   PetscSectionGetDof(mesh->supportSection, p, size);
1871:   return(0);
1872: }

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

1877:   Not collective

1879:   Input Parameters:
1880: + mesh - The DMPlex
1881: . p - The point, which must lie in the chart set with DMPlexSetChart()
1882: - size - The support size for point p

1884:   Output Parameter:

1886:   Note:
1887:   This should be called after DMPlexSetChart().

1889:   Level: beginner

1891: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1892: @*/
1893: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1894: {
1895:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1902:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1903:   return(0);
1904: }

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

1909:   Not collective

1911:   Input Parameters:
1912: + mesh - The DMPlex
1913: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1918:   Level: beginner

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

1926: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1927: @*/
1928: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1929: {
1930:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1931:   PetscInt       off;

1937:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1938:   *support = &mesh->supports[off];
1939:   return(0);
1940: }

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

1945:   Not collective

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

1952:   Output Parameter:

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

1957:   Level: beginner

1959: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1960: @*/
1961: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1962: {
1963:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1964:   PetscInt       pStart, pEnd;
1965:   PetscInt       dof, off, c;

1970:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1971:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1973:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1974:   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);
1975:   for (c = 0; c < dof; ++c) {
1976:     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);
1977:     mesh->supports[off+c] = support[c];
1978:   }
1979:   return(0);
1980: }

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

1985:   Not collective

1987:   Input Parameters:
1988: + mesh - The DMPlex
1989: . p - The point, which must lie in the chart set with DMPlexSetChart()
1990: . supportPos - The local index in the cone where the point should be put
1991: - supportPoint - The mesh point to insert

1993:   Level: beginner

1995: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1996: @*/
1997: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1998: {
1999:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2000:   PetscInt       pStart, pEnd;
2001:   PetscInt       dof, off;

2006:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2007:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2008:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2009:   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);
2010:   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);
2011:   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);
2012:   mesh->supports[off+supportPos] = supportPoint;
2013:   return(0);
2014: }

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

2019:   Not collective

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

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

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

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

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

2040:   Level: beginner

2042: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2043: @*/
2044: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2045: {
2046:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2047:   PetscInt       *closure, *fifo;
2048:   const PetscInt *tmp = NULL, *tmpO = NULL;
2049:   PetscInt        tmpSize, t;
2050:   PetscInt        depth       = 0, maxSize;
2051:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2052:   PetscErrorCode  ierr;

2056:   DMPlexGetDepth(dm, &depth);
2057:   /* This is only 1-level */
2058:   if (useCone) {
2059:     DMPlexGetConeSize(dm, p, &tmpSize);
2060:     DMPlexGetCone(dm, p, &tmp);
2061:     DMPlexGetConeOrientation(dm, p, &tmpO);
2062:   } else {
2063:     DMPlexGetSupportSize(dm, p, &tmpSize);
2064:     DMPlexGetSupport(dm, p, &tmp);
2065:   }
2066:   if (depth == 1) {
2067:     if (*points) {
2068:       closure = *points;
2069:     } else {
2070:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2071:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2072:     }
2073:     closure[0] = p; closure[1] = 0;
2074:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2075:       closure[closureSize]   = tmp[t];
2076:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2077:     }
2078:     if (numPoints) *numPoints = closureSize/2;
2079:     if (points)    *points    = closure;
2080:     return(0);
2081:   }
2082:   {
2083:     PetscInt c, coneSeries, s,supportSeries;

2085:     c = mesh->maxConeSize;
2086:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2087:     s = mesh->maxSupportSize;
2088:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2089:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2090:   }
2091:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2092:   if (*points) {
2093:     closure = *points;
2094:   } else {
2095:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2096:   }
2097:   closure[0] = p; closure[1] = 0;
2098:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2099:     const PetscInt cp = tmp[t];
2100:     const PetscInt co = tmpO ? tmpO[t] : 0;

2102:     closure[closureSize]   = cp;
2103:     closure[closureSize+1] = co;
2104:     fifo[fifoSize]         = cp;
2105:     fifo[fifoSize+1]       = co;
2106:   }
2107:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2108:   while (fifoSize - fifoStart) {
2109:     const PetscInt q   = fifo[fifoStart];
2110:     const PetscInt o   = fifo[fifoStart+1];
2111:     const PetscInt rev = o >= 0 ? 0 : 1;
2112:     const PetscInt off = rev ? -(o+1) : o;

2114:     if (useCone) {
2115:       DMPlexGetConeSize(dm, q, &tmpSize);
2116:       DMPlexGetCone(dm, q, &tmp);
2117:       DMPlexGetConeOrientation(dm, q, &tmpO);
2118:     } else {
2119:       DMPlexGetSupportSize(dm, q, &tmpSize);
2120:       DMPlexGetSupport(dm, q, &tmp);
2121:       tmpO = NULL;
2122:     }
2123:     for (t = 0; t < tmpSize; ++t) {
2124:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2125:       const PetscInt cp = tmp[i];
2126:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2127:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2128:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2129:       PetscInt       co = tmpO ? tmpO[i] : 0;
2130:       PetscInt       c;

2132:       if (rev) {
2133:         PetscInt childSize, coff;
2134:         DMPlexGetConeSize(dm, cp, &childSize);
2135:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2136:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2137:       }
2138:       /* Check for duplicate */
2139:       for (c = 0; c < closureSize; c += 2) {
2140:         if (closure[c] == cp) break;
2141:       }
2142:       if (c == closureSize) {
2143:         closure[closureSize]   = cp;
2144:         closure[closureSize+1] = co;
2145:         fifo[fifoSize]         = cp;
2146:         fifo[fifoSize+1]       = co;
2147:         closureSize           += 2;
2148:         fifoSize              += 2;
2149:       }
2150:     }
2151:     fifoStart += 2;
2152:   }
2153:   if (numPoints) *numPoints = closureSize/2;
2154:   if (points)    *points    = closure;
2155:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2156:   return(0);
2157: }

2159: /*@C
2160:   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

2162:   Not collective

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

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

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

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

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

2184:   Level: beginner

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

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

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

2248:     if (ornt < 0) {
2249:       PetscInt childSize, coff;
2250:       DMPlexGetConeSize(dm, cp, &childSize);
2251:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2252:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2253:     }
2254:     closure[closureSize]   = cp;
2255:     closure[closureSize+1] = co;
2256:     fifo[fifoSize]         = cp;
2257:     fifo[fifoSize+1]       = co;
2258:   }
2259:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2260:   while (fifoSize - fifoStart) {
2261:     const PetscInt q   = fifo[fifoStart];
2262:     const PetscInt o   = fifo[fifoStart+1];
2263:     const PetscInt rev = o >= 0 ? 0 : 1;
2264:     const PetscInt off = rev ? -(o+1) : o;

2266:     if (useCone) {
2267:       DMPlexGetConeSize(dm, q, &tmpSize);
2268:       DMPlexGetCone(dm, q, &tmp);
2269:       DMPlexGetConeOrientation(dm, q, &tmpO);
2270:     } else {
2271:       DMPlexGetSupportSize(dm, q, &tmpSize);
2272:       DMPlexGetSupport(dm, q, &tmp);
2273:       tmpO = NULL;
2274:     }
2275:     for (t = 0; t < tmpSize; ++t) {
2276:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2277:       const PetscInt cp = tmp[i];
2278:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2279:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2280:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2281:       PetscInt       co = tmpO ? tmpO[i] : 0;
2282:       PetscInt       c;

2284:       if (rev) {
2285:         PetscInt childSize, coff;
2286:         DMPlexGetConeSize(dm, cp, &childSize);
2287:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2288:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2289:       }
2290:       /* Check for duplicate */
2291:       for (c = 0; c < closureSize; c += 2) {
2292:         if (closure[c] == cp) break;
2293:       }
2294:       if (c == closureSize) {
2295:         closure[closureSize]   = cp;
2296:         closure[closureSize+1] = co;
2297:         fifo[fifoSize]         = cp;
2298:         fifo[fifoSize+1]       = co;
2299:         closureSize           += 2;
2300:         fifoSize              += 2;
2301:       }
2302:     }
2303:     fifoStart += 2;
2304:   }
2305:   if (numPoints) *numPoints = closureSize/2;
2306:   if (points)    *points    = closure;
2307:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2308:   return(0);
2309: }

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

2314:   Not collective

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

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

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

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

2332:   Level: beginner

2334: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2335: @*/
2336: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2337: {

2344:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2345:   if (numPoints) *numPoints = 0;
2346:   return(0);
2347: }

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

2352:   Not collective

2354:   Input Parameter:
2355: . mesh - The DMPlex

2357:   Output Parameters:
2358: + maxConeSize - The maximum number of in-edges
2359: - maxSupportSize - The maximum number of out-edges

2361:   Level: beginner

2363: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2364: @*/
2365: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2366: {
2367:   DM_Plex *mesh = (DM_Plex*) dm->data;

2371:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2372:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2373:   return(0);
2374: }

2376: PetscErrorCode DMSetUp_Plex(DM dm)
2377: {
2378:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2379:   PetscInt       size;

2384:   PetscSectionSetUp(mesh->coneSection);
2385:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2386:   PetscMalloc1(size, &mesh->cones);
2387:   PetscCalloc1(size, &mesh->coneOrientations);
2388:   if (mesh->maxSupportSize) {
2389:     PetscSectionSetUp(mesh->supportSection);
2390:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2391:     PetscMalloc1(size, &mesh->supports);
2392:   }
2393:   return(0);
2394: }

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

2401:   if (subdm) {DMClone(dm, subdm);}
2402:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2403:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2404:   if (dm->useNatural && dm->sfMigration) {
2405:     PetscSF        sfMigrationInv,sfNatural;
2406:     PetscSection   section, sectionSeq;

2408:     (*subdm)->sfMigration = dm->sfMigration;
2409:     PetscObjectReference((PetscObject) dm->sfMigration);
2410:     DMGetSection((*subdm), &section);
2411:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2412:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2413:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2415:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2416:     (*subdm)->sfNatural = sfNatural;
2417:     PetscSectionDestroy(&sectionSeq);
2418:     PetscSFDestroy(&sfMigrationInv);
2419:   }
2420:   return(0);
2421: }

2423: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2424: {
2426:   PetscInt       i = 0;

2429:   DMClone(dms[0], superdm);
2430:   DMCreateSectionSuperDM(dms, len, is, superdm);
2431:   (*superdm)->useNatural = PETSC_FALSE;
2432:   for (i = 0; i < len; i++){
2433:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2434:       PetscSF        sfMigrationInv,sfNatural;
2435:       PetscSection   section, sectionSeq;

2437:       (*superdm)->sfMigration = dms[i]->sfMigration;
2438:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2439:       (*superdm)->useNatural = PETSC_TRUE;
2440:       DMGetSection((*superdm), &section);
2441:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2442:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2443:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2445:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2446:       (*superdm)->sfNatural = sfNatural;
2447:       PetscSectionDestroy(&sectionSeq);
2448:       PetscSFDestroy(&sfMigrationInv);
2449:       break;
2450:     }
2451:   }
2452:   return(0);
2453: }

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

2458:   Not collective

2460:   Input Parameter:
2461: . mesh - The DMPlex

2463:   Output Parameter:

2465:   Note:
2466:   This should be called after all calls to DMPlexSetCone()

2468:   Level: beginner

2470: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2471: @*/
2472: PetscErrorCode DMPlexSymmetrize(DM dm)
2473: {
2474:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2475:   PetscInt      *offsets;
2476:   PetscInt       supportSize;
2477:   PetscInt       pStart, pEnd, p;

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

2488:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2489:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2490:     for (c = off; c < off+dof; ++c) {
2491:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2492:     }
2493:   }
2494:   for (p = pStart; p < pEnd; ++p) {
2495:     PetscInt dof;

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

2499:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2500:   }
2501:   PetscSectionSetUp(mesh->supportSection);
2502:   /* Calculate supports */
2503:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2504:   PetscMalloc1(supportSize, &mesh->supports);
2505:   PetscCalloc1(pEnd - pStart, &offsets);
2506:   for (p = pStart; p < pEnd; ++p) {
2507:     PetscInt dof, off, c;

2509:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2510:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2511:     for (c = off; c < off+dof; ++c) {
2512:       const PetscInt q = mesh->cones[c];
2513:       PetscInt       offS;

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

2517:       mesh->supports[offS+offsets[q]] = p;
2518:       ++offsets[q];
2519:     }
2520:   }
2521:   PetscFree(offsets);
2522:   return(0);
2523: }

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

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

2533:   Collective on dm

2535:   Input Parameter:
2536: . mesh - The DMPlex

2538:   Output Parameter:

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

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

2548:   Level: beginner

2550: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2551: @*/
2552: PetscErrorCode DMPlexStratify(DM dm)
2553: {
2554:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2555:   DMLabel        label;
2556:   PetscInt       pStart, pEnd, p;
2557:   PetscInt       numRoots = 0, numLeaves = 0;
2558:   PetscInt       cMax, fMax, eMax, vMax;

2563:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2564:   /* Calculate depth */
2565:   DMPlexGetChart(dm, &pStart, &pEnd);
2566:   DMCreateLabel(dm, "depth");
2567:   DMPlexGetDepthLabel(dm, &label);
2568:   /* Initialize roots and count leaves */
2569:   for (p = pStart; p < pEnd; ++p) {
2570:     PetscInt coneSize, supportSize;

2572:     DMPlexGetConeSize(dm, p, &coneSize);
2573:     DMPlexGetSupportSize(dm, p, &supportSize);
2574:     if (!coneSize && supportSize) {
2575:       ++numRoots;
2576:       DMLabelSetValue(label, p, 0);
2577:     } else if (!supportSize && coneSize) {
2578:       ++numLeaves;
2579:     } else if (!supportSize && !coneSize) {
2580:       /* Isolated points */
2581:       DMLabelSetValue(label, p, 0);
2582:     }
2583:   }
2584:   if (numRoots + numLeaves == (pEnd - pStart)) {
2585:     for (p = pStart; p < pEnd; ++p) {
2586:       PetscInt coneSize, supportSize;

2588:       DMPlexGetConeSize(dm, p, &coneSize);
2589:       DMPlexGetSupportSize(dm, p, &supportSize);
2590:       if (!supportSize && coneSize) {
2591:         DMLabelSetValue(label, p, 1);
2592:       }
2593:     }
2594:   } else {
2595:     IS       pointIS;
2596:     PetscInt numPoints = 0, level = 0;

2598:     DMLabelGetStratumIS(label, level, &pointIS);
2599:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2600:     while (numPoints) {
2601:       const PetscInt *points;
2602:       const PetscInt  newLevel = level+1;

2604:       ISGetIndices(pointIS, &points);
2605:       for (p = 0; p < numPoints; ++p) {
2606:         const PetscInt  point = points[p];
2607:         const PetscInt *support;
2608:         PetscInt        supportSize, s;

2610:         DMPlexGetSupportSize(dm, point, &supportSize);
2611:         DMPlexGetSupport(dm, point, &support);
2612:         for (s = 0; s < supportSize; ++s) {
2613:           DMLabelSetValue(label, support[s], newLevel);
2614:         }
2615:       }
2616:       ISRestoreIndices(pointIS, &points);
2617:       ++level;
2618:       ISDestroy(&pointIS);
2619:       DMLabelGetStratumIS(label, level, &pointIS);
2620:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2621:       else         {numPoints = 0;}
2622:     }
2623:     ISDestroy(&pointIS);
2624:   }
2625:   { /* just in case there is an empty process */
2626:     PetscInt numValues, maxValues = 0, v;

2628:     DMLabelGetNumValues(label,&numValues);
2629:     for (v = 0; v < numValues; v++) {
2630:       IS pointIS;

2632:       DMLabelGetStratumIS(label, v, &pointIS);
2633:       if (pointIS) {
2634:         PetscInt  min, max, numPoints;
2635:         PetscInt  start;
2636:         PetscBool contig;

2638:         ISGetLocalSize(pointIS, &numPoints);
2639:         ISGetMinMax(pointIS, &min, &max);
2640:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2641:         if (start == 0 && contig) {
2642:           ISDestroy(&pointIS);
2643:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2644:           DMLabelSetStratumIS(label, v, pointIS);
2645:         }
2646:       }
2647:       ISDestroy(&pointIS);
2648:     }
2649:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2650:     for (v = numValues; v < maxValues; v++) {
2651:       DMLabelAddStratum(label,v);
2652:     }
2653:   }
2654:   PetscObjectStateGet((PetscObject) label, &mesh->depthState);

2656:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2657:   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2658:     DMLabel  dimLabel;
2659:     PetscInt dim;

2661:     DMGetDimension(dm, &dim);
2662:     DMGetLabel(dm, "dim", &dimLabel);
2663:     if (!dimLabel) {
2664:       DMCreateLabel(dm, "dim");
2665:       DMGetLabel(dm, "dim", &dimLabel);
2666:     }
2667:     if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2668:     if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2669:     if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2670:     if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2671:   }
2672:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2673:   return(0);
2674: }

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

2679:   Not Collective

2681:   Input Parameters:
2682: + dm - The DMPlex object
2683: . numPoints - The number of input points for the join
2684: - points - The input points

2686:   Output Parameters:
2687: + numCoveredPoints - The number of points in the join
2688: - coveredPoints - The points in the join

2690:   Level: intermediate

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

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

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

2700: .keywords: mesh
2701: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2702: @*/
2703: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2704: {
2705:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2706:   PetscInt      *join[2];
2707:   PetscInt       joinSize, i = 0;
2708:   PetscInt       dof, off, p, c, m;

2716:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2717:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2718:   /* Copy in support of first point */
2719:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2720:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2721:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2722:     join[i][joinSize] = mesh->supports[off+joinSize];
2723:   }
2724:   /* Check each successive support */
2725:   for (p = 1; p < numPoints; ++p) {
2726:     PetscInt newJoinSize = 0;

2728:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2729:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2730:     for (c = 0; c < dof; ++c) {
2731:       const PetscInt point = mesh->supports[off+c];

2733:       for (m = 0; m < joinSize; ++m) {
2734:         if (point == join[i][m]) {
2735:           join[1-i][newJoinSize++] = point;
2736:           break;
2737:         }
2738:       }
2739:     }
2740:     joinSize = newJoinSize;
2741:     i        = 1-i;
2742:   }
2743:   *numCoveredPoints = joinSize;
2744:   *coveredPoints    = join[i];
2745:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2746:   return(0);
2747: }

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

2752:   Not Collective

2754:   Input Parameters:
2755: + dm - The DMPlex object
2756: . numPoints - The number of input points for the join
2757: - points - The input points

2759:   Output Parameters:
2760: + numCoveredPoints - The number of points in the join
2761: - coveredPoints - The points in the join

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

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

2769:   Level: intermediate

2771: .keywords: mesh
2772: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2773: @*/
2774: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2775: {

2783:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2784:   if (numCoveredPoints) *numCoveredPoints = 0;
2785:   return(0);
2786: }

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

2791:   Not Collective

2793:   Input Parameters:
2794: + dm - The DMPlex object
2795: . numPoints - The number of input points for the join
2796: - points - The input points

2798:   Output Parameters:
2799: + numCoveredPoints - The number of points in the join
2800: - coveredPoints - The points in the join

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

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

2808:   Level: intermediate

2810: .keywords: mesh
2811: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2812: @*/
2813: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2814: {
2815:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2816:   PetscInt      *offsets, **closures;
2817:   PetscInt      *join[2];
2818:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2819:   PetscInt       p, d, c, m, ms;


2828:   DMPlexGetDepth(dm, &depth);
2829:   PetscCalloc1(numPoints, &closures);
2830:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2831:   ms      = mesh->maxSupportSize;
2832:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2833:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2834:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

2836:   for (p = 0; p < numPoints; ++p) {
2837:     PetscInt closureSize;

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

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

2845:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2846:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2847:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2848:           offsets[p*(depth+2)+d+1] = i;
2849:           break;
2850:         }
2851:       }
2852:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2853:     }
2854:     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);
2855:   }
2856:   for (d = 0; d < depth+1; ++d) {
2857:     PetscInt dof;

2859:     /* Copy in support of first point */
2860:     dof = offsets[d+1] - offsets[d];
2861:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2862:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2863:     }
2864:     /* Check each successive cone */
2865:     for (p = 1; p < numPoints && joinSize; ++p) {
2866:       PetscInt newJoinSize = 0;

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

2872:         for (m = 0; m < joinSize; ++m) {
2873:           if (point == join[i][m]) {
2874:             join[1-i][newJoinSize++] = point;
2875:             break;
2876:           }
2877:         }
2878:       }
2879:       joinSize = newJoinSize;
2880:       i        = 1-i;
2881:     }
2882:     if (joinSize) break;
2883:   }
2884:   *numCoveredPoints = joinSize;
2885:   *coveredPoints    = join[i];
2886:   for (p = 0; p < numPoints; ++p) {
2887:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2888:   }
2889:   PetscFree(closures);
2890:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2891:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2892:   return(0);
2893: }

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

2898:   Not Collective

2900:   Input Parameters:
2901: + dm - The DMPlex object
2902: . numPoints - The number of input points for the meet
2903: - points - The input points

2905:   Output Parameters:
2906: + numCoveredPoints - The number of points in the meet
2907: - coveredPoints - The points in the meet

2909:   Level: intermediate

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

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

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

2919: .keywords: mesh
2920: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2921: @*/
2922: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2923: {
2924:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2925:   PetscInt      *meet[2];
2926:   PetscInt       meetSize, i = 0;
2927:   PetscInt       dof, off, p, c, m;

2935:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2936:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2937:   /* Copy in cone of first point */
2938:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2939:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2940:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2941:     meet[i][meetSize] = mesh->cones[off+meetSize];
2942:   }
2943:   /* Check each successive cone */
2944:   for (p = 1; p < numPoints; ++p) {
2945:     PetscInt newMeetSize = 0;

2947:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2948:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2949:     for (c = 0; c < dof; ++c) {
2950:       const PetscInt point = mesh->cones[off+c];

2952:       for (m = 0; m < meetSize; ++m) {
2953:         if (point == meet[i][m]) {
2954:           meet[1-i][newMeetSize++] = point;
2955:           break;
2956:         }
2957:       }
2958:     }
2959:     meetSize = newMeetSize;
2960:     i        = 1-i;
2961:   }
2962:   *numCoveringPoints = meetSize;
2963:   *coveringPoints    = meet[i];
2964:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2965:   return(0);
2966: }

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

2971:   Not Collective

2973:   Input Parameters:
2974: + dm - The DMPlex object
2975: . numPoints - The number of input points for the meet
2976: - points - The input points

2978:   Output Parameters:
2979: + numCoveredPoints - The number of points in the meet
2980: - coveredPoints - The points in the meet

2982:   Level: intermediate

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

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

2990: .keywords: mesh
2991: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2992: @*/
2993: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2994: {

3002:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3003:   if (numCoveredPoints) *numCoveredPoints = 0;
3004:   return(0);
3005: }

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

3010:   Not Collective

3012:   Input Parameters:
3013: + dm - The DMPlex object
3014: . numPoints - The number of input points for the meet
3015: - points - The input points

3017:   Output Parameters:
3018: + numCoveredPoints - The number of points in the meet
3019: - coveredPoints - The points in the meet

3021:   Level: intermediate

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

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

3029: .keywords: mesh
3030: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3031: @*/
3032: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3033: {
3034:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3035:   PetscInt      *offsets, **closures;
3036:   PetscInt      *meet[2];
3037:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
3038:   PetscInt       p, h, c, m, mc;


3047:   DMPlexGetDepth(dm, &height);
3048:   PetscMalloc1(numPoints, &closures);
3049:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3050:   mc      = mesh->maxConeSize;
3051:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3052:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3053:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

3055:   for (p = 0; p < numPoints; ++p) {
3056:     PetscInt closureSize;

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

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

3064:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3065:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3066:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3067:           offsets[p*(height+2)+h+1] = i;
3068:           break;
3069:         }
3070:       }
3071:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3072:     }
3073:     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);
3074:   }
3075:   for (h = 0; h < height+1; ++h) {
3076:     PetscInt dof;

3078:     /* Copy in cone of first point */
3079:     dof = offsets[h+1] - offsets[h];
3080:     for (meetSize = 0; meetSize < dof; ++meetSize) {
3081:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3082:     }
3083:     /* Check each successive cone */
3084:     for (p = 1; p < numPoints && meetSize; ++p) {
3085:       PetscInt newMeetSize = 0;

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

3091:         for (m = 0; m < meetSize; ++m) {
3092:           if (point == meet[i][m]) {
3093:             meet[1-i][newMeetSize++] = point;
3094:             break;
3095:           }
3096:         }
3097:       }
3098:       meetSize = newMeetSize;
3099:       i        = 1-i;
3100:     }
3101:     if (meetSize) break;
3102:   }
3103:   *numCoveredPoints = meetSize;
3104:   *coveredPoints    = meet[i];
3105:   for (p = 0; p < numPoints; ++p) {
3106:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3107:   }
3108:   PetscFree(closures);
3109:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3110:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3111:   return(0);
3112: }

3114: /*@C
3115:   DMPlexEqual - Determine if two DMs have the same topology

3117:   Not Collective

3119:   Input Parameters:
3120: + dmA - A DMPlex object
3121: - dmB - A DMPlex object

3123:   Output Parameters:
3124: . equal - PETSC_TRUE if the topologies are identical

3126:   Level: intermediate

3128:   Notes:
3129:   We are not solving graph isomorphism, so we do not permutation.

3131: .keywords: mesh
3132: .seealso: DMPlexGetCone()
3133: @*/
3134: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3135: {
3136:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


3144:   *equal = PETSC_FALSE;
3145:   DMPlexGetDepth(dmA, &depth);
3146:   DMPlexGetDepth(dmB, &depthB);
3147:   if (depth != depthB) return(0);
3148:   DMPlexGetChart(dmA, &pStart,  &pEnd);
3149:   DMPlexGetChart(dmB, &pStartB, &pEndB);
3150:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3151:   for (p = pStart; p < pEnd; ++p) {
3152:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3153:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

3155:     DMPlexGetConeSize(dmA, p, &coneSize);
3156:     DMPlexGetCone(dmA, p, &cone);
3157:     DMPlexGetConeOrientation(dmA, p, &ornt);
3158:     DMPlexGetConeSize(dmB, p, &coneSizeB);
3159:     DMPlexGetCone(dmB, p, &coneB);
3160:     DMPlexGetConeOrientation(dmB, p, &orntB);
3161:     if (coneSize != coneSizeB) return(0);
3162:     for (c = 0; c < coneSize; ++c) {
3163:       if (cone[c] != coneB[c]) return(0);
3164:       if (ornt[c] != orntB[c]) return(0);
3165:     }
3166:     DMPlexGetSupportSize(dmA, p, &supportSize);
3167:     DMPlexGetSupport(dmA, p, &support);
3168:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
3169:     DMPlexGetSupport(dmB, p, &supportB);
3170:     if (supportSize != supportSizeB) return(0);
3171:     for (s = 0; s < supportSize; ++s) {
3172:       if (support[s] != supportB[s]) return(0);
3173:     }
3174:   }
3175:   *equal = PETSC_TRUE;
3176:   return(0);
3177: }

3179: /*@C
3180:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

3182:   Not Collective

3184:   Input Parameters:
3185: + dm         - The DMPlex
3186: . cellDim    - The cell dimension
3187: - numCorners - The number of vertices on a cell

3189:   Output Parameters:
3190: . numFaceVertices - The number of vertices on a face

3192:   Level: developer

3194:   Notes:
3195:   Of course this can only work for a restricted set of symmetric shapes

3197: .seealso: DMPlexGetCone()
3198: @*/
3199: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3200: {
3201:   MPI_Comm       comm;

3205:   PetscObjectGetComm((PetscObject)dm,&comm);
3207:   switch (cellDim) {
3208:   case 0:
3209:     *numFaceVertices = 0;
3210:     break;
3211:   case 1:
3212:     *numFaceVertices = 1;
3213:     break;
3214:   case 2:
3215:     switch (numCorners) {
3216:     case 3: /* triangle */
3217:       *numFaceVertices = 2; /* Edge has 2 vertices */
3218:       break;
3219:     case 4: /* quadrilateral */
3220:       *numFaceVertices = 2; /* Edge has 2 vertices */
3221:       break;
3222:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3223:       *numFaceVertices = 3; /* Edge has 3 vertices */
3224:       break;
3225:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3226:       *numFaceVertices = 3; /* Edge has 3 vertices */
3227:       break;
3228:     default:
3229:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3230:     }
3231:     break;
3232:   case 3:
3233:     switch (numCorners) {
3234:     case 4: /* tetradehdron */
3235:       *numFaceVertices = 3; /* Face has 3 vertices */
3236:       break;
3237:     case 6: /* tet cohesive cells */
3238:       *numFaceVertices = 4; /* Face has 4 vertices */
3239:       break;
3240:     case 8: /* hexahedron */
3241:       *numFaceVertices = 4; /* Face has 4 vertices */
3242:       break;
3243:     case 9: /* tet cohesive Lagrange cells */
3244:       *numFaceVertices = 6; /* Face has 6 vertices */
3245:       break;
3246:     case 10: /* quadratic tetrahedron */
3247:       *numFaceVertices = 6; /* Face has 6 vertices */
3248:       break;
3249:     case 12: /* hex cohesive Lagrange cells */
3250:       *numFaceVertices = 6; /* Face has 6 vertices */
3251:       break;
3252:     case 18: /* quadratic tet cohesive Lagrange cells */
3253:       *numFaceVertices = 6; /* Face has 6 vertices */
3254:       break;
3255:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3256:       *numFaceVertices = 9; /* Face has 9 vertices */
3257:       break;
3258:     default:
3259:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3260:     }
3261:     break;
3262:   default:
3263:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3264:   }
3265:   return(0);
3266: }

3268: /*@
3269:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3271:   Not Collective

3273:   Input Parameter:
3274: . dm    - The DMPlex object

3276:   Output Parameter:
3277: . depthLabel - The DMLabel recording point depth

3279:   Level: developer

3281: .keywords: mesh, points
3282: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3283: @*/
3284: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3285: {

3291:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3292:   *depthLabel = dm->depthLabel;
3293:   return(0);
3294: }

3296: /*@
3297:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3299:   Not Collective

3301:   Input Parameter:
3302: . dm    - The DMPlex object

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

3307:   Level: developer

3309: .keywords: mesh, points
3310: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3311: @*/
3312: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3313: {
3314:   DMLabel        label;
3315:   PetscInt       d = 0;

3321:   DMPlexGetDepthLabel(dm, &label);
3322:   if (label) {DMLabelGetNumValues(label, &d);}
3323:   *depth = d-1;
3324:   return(0);
3325: }

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

3330:   Not Collective

3332:   Input Parameters:
3333: + dm           - The DMPlex object
3334: - stratumValue - The requested depth

3336:   Output Parameters:
3337: + start - The first point at this depth
3338: - end   - One beyond the last point at this depth

3340:   Level: developer

3342: .keywords: mesh, points
3343: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3344: @*/
3345: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3346: {
3347:   DMLabel        label;
3348:   PetscInt       pStart, pEnd;

3355:   DMPlexGetChart(dm, &pStart, &pEnd);
3356:   if (pStart == pEnd) return(0);
3357:   if (stratumValue < 0) {
3358:     if (start) *start = pStart;
3359:     if (end)   *end   = pEnd;
3360:     return(0);
3361:   }
3362:   DMPlexGetDepthLabel(dm, &label);
3363:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3364:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3365:   return(0);
3366: }

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

3371:   Not Collective

3373:   Input Parameters:
3374: + dm           - The DMPlex object
3375: - stratumValue - The requested height

3377:   Output Parameters:
3378: + start - The first point at this height
3379: - end   - One beyond the last point at this height

3381:   Level: developer

3383: .keywords: mesh, points
3384: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3385: @*/
3386: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3387: {
3388:   DMLabel        label;
3389:   PetscInt       depth, pStart, pEnd;

3396:   DMPlexGetChart(dm, &pStart, &pEnd);
3397:   if (pStart == pEnd) return(0);
3398:   if (stratumValue < 0) {
3399:     if (start) *start = pStart;
3400:     if (end)   *end   = pEnd;
3401:     return(0);
3402:   }
3403:   DMPlexGetDepthLabel(dm, &label);
3404:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3405:   DMLabelGetNumValues(label, &depth);
3406:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3407:   return(0);
3408: }

3410: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3411: {
3412:   PetscSection   section, s;
3413:   Mat            m;
3414:   PetscInt       maxHeight;

3418:   DMClone(dm, cdm);
3419:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3420:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3421:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3422:   DMSetSection(*cdm, section);
3423:   PetscSectionDestroy(&section);
3424:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3425:   MatCreate(PETSC_COMM_SELF, &m);
3426:   DMSetDefaultConstraints(*cdm, s, m);
3427:   PetscSectionDestroy(&s);
3428:   MatDestroy(&m);

3430:   DMSetNumFields(*cdm, 1);
3431:   DMCreateDS(*cdm);
3432:   return(0);
3433: }

3435: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3436: {
3437:   Vec            coordsLocal;
3438:   DM             coordsDM;

3442:   *field = NULL;
3443:   DMGetCoordinatesLocal(dm,&coordsLocal);
3444:   DMGetCoordinateDM(dm,&coordsDM);
3445:   if (coordsLocal && coordsDM) {
3446:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3447:   }
3448:   return(0);
3449: }

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

3454:   Not Collective

3456:   Input Parameters:
3457: . dm        - The DMPlex object

3459:   Output Parameter:
3460: . section - The PetscSection object

3462:   Level: developer

3464: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3465: @*/
3466: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3467: {
3468:   DM_Plex *mesh = (DM_Plex*) dm->data;

3472:   if (section) *section = mesh->coneSection;
3473:   return(0);
3474: }

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

3479:   Not Collective

3481:   Input Parameters:
3482: . dm        - The DMPlex object

3484:   Output Parameter:
3485: . section - The PetscSection object

3487:   Level: developer

3489: .seealso: DMPlexGetConeSection()
3490: @*/
3491: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3492: {
3493:   DM_Plex *mesh = (DM_Plex*) dm->data;

3497:   if (section) *section = mesh->supportSection;
3498:   return(0);
3499: }

3501: /*@C
3502:   DMPlexGetCones - Return cone data

3504:   Not Collective

3506:   Input Parameters:
3507: . dm        - The DMPlex object

3509:   Output Parameter:
3510: . cones - The cone for each point

3512:   Level: developer

3514: .seealso: DMPlexGetConeSection()
3515: @*/
3516: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3517: {
3518:   DM_Plex *mesh = (DM_Plex*) dm->data;

3522:   if (cones) *cones = mesh->cones;
3523:   return(0);
3524: }

3526: /*@C
3527:   DMPlexGetConeOrientations - Return cone orientation data

3529:   Not Collective

3531:   Input Parameters:
3532: . dm        - The DMPlex object

3534:   Output Parameter:
3535: . coneOrientations - The cone orientation for each point

3537:   Level: developer

3539: .seealso: DMPlexGetConeSection()
3540: @*/
3541: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3542: {
3543:   DM_Plex *mesh = (DM_Plex*) dm->data;

3547:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3548:   return(0);
3549: }

3551: /******************************** FEM Support **********************************/

3553: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3554: {
3555:   DMLabel        label;
3556:   PetscInt      *perm;
3557:   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3561:   if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3562:   DMGetDimension(dm, &dim);
3563:   DMPlexGetDepthLabel(dm, &label);
3564:   DMLabelGetValue(label, point, &depth);
3565:   if (depth == 1) {eStart = point;}
3566:   else if  (depth == dim) {
3567:     const PetscInt *cone;

3569:     DMPlexGetCone(dm, point, &cone);
3570:     if (dim == 2) eStart = cone[0];
3571:     else if (dim == 3) {
3572:       const PetscInt *cone2;
3573:       DMPlexGetCone(dm, cone[0], &cone2);
3574:       eStart = cone2[0];
3575:     } 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);
3576:   } 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);
3577:   if (!section) {DMGetSection(dm, &section);}
3578:   PetscSectionGetNumFields(section, &Nf);
3579:   if (dim <= 1) return(0);
3580:   for (f = 0; f < Nf; ++f) {
3581:     /* An order k SEM disc has k-1 dofs on an edge */
3582:     PetscSectionGetFieldDof(section, eStart, f, &k);
3583:     PetscSectionGetFieldComponents(section, f, &Nc);
3584:     k = k/Nc + 1;
3585:     size += PetscPowInt(k+1, dim)*Nc;
3586:   }
3587:   PetscMalloc1(size, &perm);
3588:   for (f = 0; f < Nf; ++f) {
3589:     switch (dim) {
3590:     case 2:
3591:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3592:       PetscSectionGetFieldDof(section, eStart, f, &k);
3593:       PetscSectionGetFieldComponents(section, f, &Nc);
3594:       k = k/Nc + 1;
3595:       /* The SEM order is

3597:          v_lb, {e_b}, v_rb,
3598:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3599:          v_lt, reverse {e_t}, v_rt
3600:       */
3601:       {
3602:         const PetscInt of   = 0;
3603:         const PetscInt oeb  = of   + PetscSqr(k-1);
3604:         const PetscInt oer  = oeb  + (k-1);
3605:         const PetscInt oet  = oer  + (k-1);
3606:         const PetscInt oel  = oet  + (k-1);
3607:         const PetscInt ovlb = oel  + (k-1);
3608:         const PetscInt ovrb = ovlb + 1;
3609:         const PetscInt ovrt = ovrb + 1;
3610:         const PetscInt ovlt = ovrt + 1;
3611:         PetscInt       o;

3613:         /* bottom */
3614:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3615:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3616:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3617:         /* middle */
3618:         for (i = 0; i < k-1; ++i) {
3619:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3620:           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;
3621:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3622:         }
3623:         /* top */
3624:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3625:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3626:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3627:         foffset = offset;
3628:       }
3629:       break;
3630:     case 3:
3631:       /* The original hex closure is

3633:          {c,
3634:           f_b, f_t, f_f, f_b, f_r, f_l,
3635:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3636:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3637:       */
3638:       PetscSectionGetFieldDof(section, eStart, f, &k);
3639:       PetscSectionGetFieldComponents(section, f, &Nc);
3640:       k = k/Nc + 1;
3641:       /* The SEM order is
3642:          Bottom Slice
3643:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3644:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3645:          v_blb, {e_bb}, v_brb,

3647:          Middle Slice (j)
3648:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3649:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3650:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3652:          Top Slice
3653:          v_tlf, {e_tf}, v_trf,
3654:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3655:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3656:       */
3657:       {
3658:         const PetscInt oc    = 0;
3659:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3660:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3661:         const PetscInt off   = oft   + PetscSqr(k-1);
3662:         const PetscInt ofk   = off   + PetscSqr(k-1);
3663:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3664:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3665:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3666:         const PetscInt oebb  = oebl  + (k-1);
3667:         const PetscInt oebr  = oebb  + (k-1);
3668:         const PetscInt oebf  = oebr  + (k-1);
3669:         const PetscInt oetf  = oebf  + (k-1);
3670:         const PetscInt oetr  = oetf  + (k-1);
3671:         const PetscInt oetb  = oetr  + (k-1);
3672:         const PetscInt oetl  = oetb  + (k-1);
3673:         const PetscInt oerf  = oetl  + (k-1);
3674:         const PetscInt oelf  = oerf  + (k-1);
3675:         const PetscInt oelb  = oelf  + (k-1);
3676:         const PetscInt oerb  = oelb  + (k-1);
3677:         const PetscInt ovblf = oerb  + (k-1);
3678:         const PetscInt ovblb = ovblf + 1;
3679:         const PetscInt ovbrb = ovblb + 1;
3680:         const PetscInt ovbrf = ovbrb + 1;
3681:         const PetscInt ovtlf = ovbrf + 1;
3682:         const PetscInt ovtrf = ovtlf + 1;
3683:         const PetscInt ovtrb = ovtrf + 1;
3684:         const PetscInt ovtlb = ovtrb + 1;
3685:         PetscInt       o, n;

3687:         /* Bottom Slice */
3688:         /*   bottom */
3689:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3690:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3691:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3692:         /*   middle */
3693:         for (i = 0; i < k-1; ++i) {
3694:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3695:           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;}
3696:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3697:         }
3698:         /*   top */
3699:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3700:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3701:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3703:         /* Middle Slice */
3704:         for (j = 0; j < k-1; ++j) {
3705:           /*   bottom */
3706:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3707:           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;
3708:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3709:           /*   middle */
3710:           for (i = 0; i < k-1; ++i) {
3711:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3712:             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;
3713:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3714:           }
3715:           /*   top */
3716:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3717:           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;
3718:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3719:         }

3721:         /* Top Slice */
3722:         /*   bottom */
3723:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3724:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3725:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3726:         /*   middle */
3727:         for (i = 0; i < k-1; ++i) {
3728:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3729:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3730:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3731:         }
3732:         /*   top */
3733:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3734:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3735:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3737:         foffset = offset;
3738:       }
3739:       break;
3740:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3741:     }
3742:   }
3743:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3744:   /* Check permutation */
3745:   {
3746:     PetscInt *check;

3748:     PetscMalloc1(size, &check);
3749:     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]);}
3750:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3751:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3752:     PetscFree(check);
3753:   }
3754:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3755:   return(0);
3756: }

3758: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3759: {
3760:   PetscDS        prob;
3761:   PetscInt       depth, Nf, h;
3762:   DMLabel        label;

3766:   DMGetDS(dm, &prob);
3767:   Nf      = prob->Nf;
3768:   label   = dm->depthLabel;
3769:   *dspace = NULL;
3770:   if (field < Nf) {
3771:     PetscObject disc = prob->disc[field];

3773:     if (disc->classid == PETSCFE_CLASSID) {
3774:       PetscDualSpace dsp;

3776:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3777:       DMLabelGetNumValues(label,&depth);
3778:       DMLabelGetValue(label,point,&h);
3779:       h    = depth - 1 - h;
3780:       if (h) {
3781:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3782:       } else {
3783:         *dspace = dsp;
3784:       }
3785:     }
3786:   }
3787:   return(0);
3788: }


3791: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3792: {
3793:   PetscScalar    *array, *vArray;
3794:   const PetscInt *cone, *coneO;
3795:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3796:   PetscErrorCode  ierr;

3799:   PetscSectionGetChart(section, &pStart, &pEnd);
3800:   DMPlexGetConeSize(dm, point, &numPoints);
3801:   DMPlexGetCone(dm, point, &cone);
3802:   DMPlexGetConeOrientation(dm, point, &coneO);
3803:   if (!values || !*values) {
3804:     if ((point >= pStart) && (point < pEnd)) {
3805:       PetscInt dof;

3807:       PetscSectionGetDof(section, point, &dof);
3808:       size += dof;
3809:     }
3810:     for (p = 0; p < numPoints; ++p) {
3811:       const PetscInt cp = cone[p];
3812:       PetscInt       dof;

3814:       if ((cp < pStart) || (cp >= pEnd)) continue;
3815:       PetscSectionGetDof(section, cp, &dof);
3816:       size += dof;
3817:     }
3818:     if (!values) {
3819:       if (csize) *csize = size;
3820:       return(0);
3821:     }
3822:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
3823:   } else {
3824:     array = *values;
3825:   }
3826:   size = 0;
3827:   VecGetArray(v, &vArray);
3828:   if ((point >= pStart) && (point < pEnd)) {
3829:     PetscInt     dof, off, d;
3830:     PetscScalar *varr;

3832:     PetscSectionGetDof(section, point, &dof);
3833:     PetscSectionGetOffset(section, point, &off);
3834:     varr = &vArray[off];
3835:     for (d = 0; d < dof; ++d, ++offset) {
3836:       array[offset] = varr[d];
3837:     }
3838:     size += dof;
3839:   }
3840:   for (p = 0; p < numPoints; ++p) {
3841:     const PetscInt cp = cone[p];
3842:     PetscInt       o  = coneO[p];
3843:     PetscInt       dof, off, d;
3844:     PetscScalar   *varr;

3846:     if ((cp < pStart) || (cp >= pEnd)) continue;
3847:     PetscSectionGetDof(section, cp, &dof);
3848:     PetscSectionGetOffset(section, cp, &off);
3849:     varr = &vArray[off];
3850:     if (o >= 0) {
3851:       for (d = 0; d < dof; ++d, ++offset) {
3852:         array[offset] = varr[d];
3853:       }
3854:     } else {
3855:       for (d = dof-1; d >= 0; --d, ++offset) {
3856:         array[offset] = varr[d];
3857:       }
3858:     }
3859:     size += dof;
3860:   }
3861:   VecRestoreArray(v, &vArray);
3862:   if (!*values) {
3863:     if (csize) *csize = size;
3864:     *values = array;
3865:   } else {
3866:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3867:     *csize = size;
3868:   }
3869:   return(0);
3870: }

3872: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3873: {
3874:   const PetscInt *cla;
3875:   PetscInt       np, *pts = NULL;

3879:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3880:   if (!*clPoints) {
3881:     PetscInt pStart, pEnd, p, q;

3883:     PetscSectionGetChart(section, &pStart, &pEnd);
3884:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3885:     /* Compress out points not in the section */
3886:     for (p = 0, q = 0; p < np; p++) {
3887:       PetscInt r = pts[2*p];
3888:       if ((r >= pStart) && (r < pEnd)) {
3889:         pts[q*2]   = r;
3890:         pts[q*2+1] = pts[2*p+1];
3891:         ++q;
3892:       }
3893:     }
3894:     np = q;
3895:     cla = NULL;
3896:   } else {
3897:     PetscInt dof, off;

3899:     PetscSectionGetDof(*clSec, point, &dof);
3900:     PetscSectionGetOffset(*clSec, point, &off);
3901:     ISGetIndices(*clPoints, &cla);
3902:     np   = dof/2;
3903:     pts  = (PetscInt *) &cla[off];
3904:   }
3905:   *numPoints = np;
3906:   *points    = pts;
3907:   *clp       = cla;

3909:   return(0);
3910: }

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

3917:   if (!*clPoints) {
3918:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3919:   } else {
3920:     ISRestoreIndices(*clPoints, clp);
3921:   }
3922:   *numPoints = 0;
3923:   *points    = NULL;
3924:   *clSec     = NULL;
3925:   *clPoints  = NULL;
3926:   *clp       = NULL;
3927:   return(0);
3928: }

3930: 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[])
3931: {
3932:   PetscInt          offset = 0, p;
3933:   const PetscInt    **perms = NULL;
3934:   const PetscScalar **flips = NULL;
3935:   PetscErrorCode    ierr;

3938:   *size = 0;
3939:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3940:   for (p = 0; p < numPoints; p++) {
3941:     const PetscInt    point = points[2*p];
3942:     const PetscInt    *perm = perms ? perms[p] : NULL;
3943:     const PetscScalar *flip = flips ? flips[p] : NULL;
3944:     PetscInt          dof, off, d;
3945:     const PetscScalar *varr;

3947:     PetscSectionGetDof(section, point, &dof);
3948:     PetscSectionGetOffset(section, point, &off);
3949:     varr = &vArray[off];
3950:     if (clperm) {
3951:       if (perm) {
3952:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3953:       } else {
3954:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3955:       }
3956:       if (flip) {
3957:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3958:       }
3959:     } else {
3960:       if (perm) {
3961:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3962:       } else {
3963:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3964:       }
3965:       if (flip) {
3966:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3967:       }
3968:     }
3969:     offset += dof;
3970:   }
3971:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3972:   *size = offset;
3973:   return(0);
3974: }

3976: 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[])
3977: {
3978:   PetscInt          offset = 0, f;
3979:   PetscErrorCode    ierr;

3982:   *size = 0;
3983:   for (f = 0; f < numFields; ++f) {
3984:     PetscInt          p;
3985:     const PetscInt    **perms = NULL;
3986:     const PetscScalar **flips = NULL;

3988:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3989:     for (p = 0; p < numPoints; p++) {
3990:       const PetscInt    point = points[2*p];
3991:       PetscInt          fdof, foff, b;
3992:       const PetscScalar *varr;
3993:       const PetscInt    *perm = perms ? perms[p] : NULL;
3994:       const PetscScalar *flip = flips ? flips[p] : NULL;

3996:       PetscSectionGetFieldDof(section, point, f, &fdof);
3997:       PetscSectionGetFieldOffset(section, point, f, &foff);
3998:       varr = &vArray[foff];
3999:       if (clperm) {
4000:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4001:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4002:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4003:       } else {
4004:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4005:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4006:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4007:       }
4008:       offset += fdof;
4009:     }
4010:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4011:   }
4012:   *size = offset;
4013:   return(0);
4014: }

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

4019:   Not collective

4021:   Input Parameters:
4022: + dm - The DM
4023: . section - The section describing the layout in v, or NULL to use the default section
4024: . v - The local vector
4025: . point - The point in the DM
4026: . csize - The size of the input values array, or NULL
4027: - values - An array to use for the values, or NULL to have it allocated automatically

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

4033: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4034: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4035: $ assembly function, and a user may already have allocated storage for this operation.
4036: $
4037: $ A typical use could be
4038: $
4039: $  values = NULL;
4040: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4041: $  for (cl = 0; cl < clSize; ++cl) {
4042: $    <Compute on closure>
4043: $  }
4044: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4045: $
4046: $ or
4047: $
4048: $  PetscMalloc1(clMaxSize, &values);
4049: $  for (p = pStart; p < pEnd; ++p) {
4050: $    clSize = clMaxSize;
4051: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4052: $    for (cl = 0; cl < clSize; ++cl) {
4053: $      <Compute on closure>
4054: $    }
4055: $  }
4056: $  PetscFree(values);

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

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

4064:   Level: intermediate

4066: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4067: @*/
4068: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4069: {
4070:   PetscSection       clSection;
4071:   IS                 clPoints;
4072:   PetscScalar       *array;
4073:   const PetscScalar *vArray;
4074:   PetscInt          *points = NULL;
4075:   const PetscInt    *clp, *perm;
4076:   PetscInt           depth, numFields, numPoints, size;
4077:   PetscErrorCode     ierr;

4081:   if (!section) {DMGetSection(dm, &section);}
4084:   DMPlexGetDepth(dm, &depth);
4085:   PetscSectionGetNumFields(section, &numFields);
4086:   if (depth == 1 && numFields < 2) {
4087:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4088:     return(0);
4089:   }
4090:   /* Get points */
4091:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4092:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4093:   /* Get array */
4094:   if (!values || !*values) {
4095:     PetscInt asize = 0, dof, p;

4097:     for (p = 0; p < numPoints*2; p += 2) {
4098:       PetscSectionGetDof(section, points[p], &dof);
4099:       asize += dof;
4100:     }
4101:     if (!values) {
4102:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4103:       if (csize) *csize = asize;
4104:       return(0);
4105:     }
4106:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4107:   } else {
4108:     array = *values;
4109:   }
4110:   VecGetArrayRead(v, &vArray);
4111:   /* Get values */
4112:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4113:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4114:   /* Cleanup points */
4115:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4116:   /* Cleanup array */
4117:   VecRestoreArrayRead(v, &vArray);
4118:   if (!*values) {
4119:     if (csize) *csize = size;
4120:     *values = array;
4121:   } else {
4122:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4123:     *csize = size;
4124:   }
4125:   return(0);
4126: }

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

4131:   Not collective

4133:   Input Parameters:
4134: + dm - The DM
4135: . section - The section describing the layout in v, or NULL to use the default section
4136: . v - The local vector
4137: . point - The point in the DM
4138: . csize - The number of values in the closure, or NULL
4139: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

4149:   Level: intermediate

4151: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4152: @*/
4153: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4154: {
4155:   PetscInt       size = 0;

4159:   /* Should work without recalculating size */
4160:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4161:   *values = NULL;
4162:   return(0);
4163: }

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

4168: 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[])
4169: {
4170:   PetscInt        cdof;   /* The number of constraints on this point */
4171:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4172:   PetscScalar    *a;
4173:   PetscInt        off, cind = 0, k;
4174:   PetscErrorCode  ierr;

4177:   PetscSectionGetConstraintDof(section, point, &cdof);
4178:   PetscSectionGetOffset(section, point, &off);
4179:   a    = &array[off];
4180:   if (!cdof || setBC) {
4181:     if (clperm) {
4182:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4183:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4184:     } else {
4185:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4186:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4187:     }
4188:   } else {
4189:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4190:     if (clperm) {
4191:       if (perm) {for (k = 0; k < dof; ++k) {
4192:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4193:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4194:         }
4195:       } else {
4196:         for (k = 0; k < dof; ++k) {
4197:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4198:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4199:         }
4200:       }
4201:     } else {
4202:       if (perm) {
4203:         for (k = 0; k < dof; ++k) {
4204:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4205:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4206:         }
4207:       } else {
4208:         for (k = 0; k < dof; ++k) {
4209:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4210:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4211:         }
4212:       }
4213:     }
4214:   }
4215:   return(0);
4216: }

4218: 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[])
4219: {
4220:   PetscInt        cdof;   /* The number of constraints on this point */
4221:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4222:   PetscScalar    *a;
4223:   PetscInt        off, cind = 0, k;
4224:   PetscErrorCode  ierr;

4227:   PetscSectionGetConstraintDof(section, point, &cdof);
4228:   PetscSectionGetOffset(section, point, &off);
4229:   a    = &array[off];
4230:   if (cdof) {
4231:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4232:     if (clperm) {
4233:       if (perm) {
4234:         for (k = 0; k < dof; ++k) {
4235:           if ((cind < cdof) && (k == cdofs[cind])) {
4236:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4237:             cind++;
4238:           }
4239:         }
4240:       } else {
4241:         for (k = 0; k < dof; ++k) {
4242:           if ((cind < cdof) && (k == cdofs[cind])) {
4243:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4244:             cind++;
4245:           }
4246:         }
4247:       }
4248:     } else {
4249:       if (perm) {
4250:         for (k = 0; k < dof; ++k) {
4251:           if ((cind < cdof) && (k == cdofs[cind])) {
4252:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4253:             cind++;
4254:           }
4255:         }
4256:       } else {
4257:         for (k = 0; k < dof; ++k) {
4258:           if ((cind < cdof) && (k == cdofs[cind])) {
4259:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4260:             cind++;
4261:           }
4262:         }
4263:       }
4264:     }
4265:   }
4266:   return(0);
4267: }

4269: 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[])
4270: {
4271:   PetscScalar    *a;
4272:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4273:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4274:   PetscInt        cind = 0, b;
4275:   PetscErrorCode  ierr;

4278:   PetscSectionGetFieldDof(section, point, f, &fdof);
4279:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4280:   PetscSectionGetFieldOffset(section, point, f, &foff);
4281:   a    = &array[foff];
4282:   if (!fcdof || setBC) {
4283:     if (clperm) {
4284:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4285:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4286:     } else {
4287:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4288:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4289:     }
4290:   } else {
4291:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4292:     if (clperm) {
4293:       if (perm) {
4294:         for (b = 0; b < fdof; b++) {
4295:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4296:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4297:         }
4298:       } else {
4299:         for (b = 0; b < fdof; b++) {
4300:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4301:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4302:         }
4303:       }
4304:     } else {
4305:       if (perm) {
4306:         for (b = 0; b < fdof; b++) {
4307:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4308:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4309:         }
4310:       } else {
4311:         for (b = 0; b < fdof; b++) {
4312:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4313:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4314:         }
4315:       }
4316:     }
4317:   }
4318:   *offset += fdof;
4319:   return(0);
4320: }

4322: 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[])
4323: {
4324:   PetscScalar    *a;
4325:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4326:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4327:   PetscInt        cind = 0, ncind = 0, b;
4328:   PetscBool       ncSet, fcSet;
4329:   PetscErrorCode  ierr;

4332:   PetscSectionGetFieldDof(section, point, f, &fdof);
4333:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4334:   PetscSectionGetFieldOffset(section, point, f, &foff);
4335:   a    = &array[foff];
4336:   if (fcdof) {
4337:     /* We just override fcdof and fcdofs with Ncc and comps */
4338:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4339:     if (clperm) {
4340:       if (perm) {
4341:         if (comps) {
4342:           for (b = 0; b < fdof; b++) {
4343:             ncSet = fcSet = PETSC_FALSE;
4344:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4345:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4346:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4347:           }
4348:         } else {
4349:           for (b = 0; b < fdof; b++) {
4350:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4351:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4352:               ++cind;
4353:             }
4354:           }
4355:         }
4356:       } else {
4357:         if (comps) {
4358:           for (b = 0; b < fdof; b++) {
4359:             ncSet = fcSet = PETSC_FALSE;
4360:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4361:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4362:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4363:           }
4364:         } else {
4365:           for (b = 0; b < fdof; b++) {
4366:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4367:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4368:               ++cind;
4369:             }
4370:           }
4371:         }
4372:       }
4373:     } else {
4374:       if (perm) {
4375:         if (comps) {
4376:           for (b = 0; b < fdof; b++) {
4377:             ncSet = fcSet = PETSC_FALSE;
4378:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4379:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4380:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4381:           }
4382:         } else {
4383:           for (b = 0; b < fdof; b++) {
4384:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4385:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4386:               ++cind;
4387:             }
4388:           }
4389:         }
4390:       } else {
4391:         if (comps) {
4392:           for (b = 0; b < fdof; b++) {
4393:             ncSet = fcSet = PETSC_FALSE;
4394:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4395:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4396:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4397:           }
4398:         } else {
4399:           for (b = 0; b < fdof; b++) {
4400:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4401:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4402:               ++cind;
4403:             }
4404:           }
4405:         }
4406:       }
4407:     }
4408:   }
4409:   *offset += fdof;
4410:   return(0);
4411: }

4413: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4414: {
4415:   PetscScalar    *array;
4416:   const PetscInt *cone, *coneO;
4417:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4418:   PetscErrorCode  ierr;

4421:   PetscSectionGetChart(section, &pStart, &pEnd);
4422:   DMPlexGetConeSize(dm, point, &numPoints);
4423:   DMPlexGetCone(dm, point, &cone);
4424:   DMPlexGetConeOrientation(dm, point, &coneO);
4425:   VecGetArray(v, &array);
4426:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4427:     const PetscInt cp = !p ? point : cone[p-1];
4428:     const PetscInt o  = !p ? 0     : coneO[p-1];

4430:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4431:     PetscSectionGetDof(section, cp, &dof);
4432:     /* ADD_VALUES */
4433:     {
4434:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4435:       PetscScalar    *a;
4436:       PetscInt        cdof, coff, cind = 0, k;

4438:       PetscSectionGetConstraintDof(section, cp, &cdof);
4439:       PetscSectionGetOffset(section, cp, &coff);
4440:       a    = &array[coff];
4441:       if (!cdof) {
4442:         if (o >= 0) {
4443:           for (k = 0; k < dof; ++k) {
4444:             a[k] += values[off+k];
4445:           }
4446:         } else {
4447:           for (k = 0; k < dof; ++k) {
4448:             a[k] += values[off+dof-k-1];
4449:           }
4450:         }
4451:       } else {
4452:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4453:         if (o >= 0) {
4454:           for (k = 0; k < dof; ++k) {
4455:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4456:             a[k] += values[off+k];
4457:           }
4458:         } else {
4459:           for (k = 0; k < dof; ++k) {
4460:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4461:             a[k] += values[off+dof-k-1];
4462:           }
4463:         }
4464:       }
4465:     }
4466:   }
4467:   VecRestoreArray(v, &array);
4468:   return(0);
4469: }

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

4474:   Not collective

4476:   Input Parameters:
4477: + dm - The DM
4478: . section - The section describing the layout in v, or NULL to use the default section
4479: . v - The local vector
4480: . point - The point in the DM
4481: . values - The array of values
4482: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4483:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4488:   Level: intermediate

4490: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4491: @*/
4492: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4493: {
4494:   PetscSection    clSection;
4495:   IS              clPoints;
4496:   PetscScalar    *array;
4497:   PetscInt       *points = NULL;
4498:   const PetscInt *clp, *clperm;
4499:   PetscInt        depth, numFields, numPoints, p;
4500:   PetscErrorCode  ierr;

4504:   if (!section) {DMGetSection(dm, &section);}
4507:   DMPlexGetDepth(dm, &depth);
4508:   PetscSectionGetNumFields(section, &numFields);
4509:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4510:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4511:     return(0);
4512:   }
4513:   /* Get points */
4514:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4515:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4516:   /* Get array */
4517:   VecGetArray(v, &array);
4518:   /* Get values */
4519:   if (numFields > 0) {
4520:     PetscInt offset = 0, f;
4521:     for (f = 0; f < numFields; ++f) {
4522:       const PetscInt    **perms = NULL;
4523:       const PetscScalar **flips = NULL;

4525:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4526:       switch (mode) {
4527:       case INSERT_VALUES:
4528:         for (p = 0; p < numPoints; p++) {
4529:           const PetscInt    point = points[2*p];
4530:           const PetscInt    *perm = perms ? perms[p] : NULL;
4531:           const PetscScalar *flip = flips ? flips[p] : NULL;
4532:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4533:         } break;
4534:       case INSERT_ALL_VALUES:
4535:         for (p = 0; p < numPoints; p++) {
4536:           const PetscInt    point = points[2*p];
4537:           const PetscInt    *perm = perms ? perms[p] : NULL;
4538:           const PetscScalar *flip = flips ? flips[p] : NULL;
4539:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4540:         } break;
4541:       case INSERT_BC_VALUES:
4542:         for (p = 0; p < numPoints; p++) {
4543:           const PetscInt    point = points[2*p];
4544:           const PetscInt    *perm = perms ? perms[p] : NULL;
4545:           const PetscScalar *flip = flips ? flips[p] : NULL;
4546:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4547:         } break;
4548:       case ADD_VALUES:
4549:         for (p = 0; p < numPoints; p++) {
4550:           const PetscInt    point = points[2*p];
4551:           const PetscInt    *perm = perms ? perms[p] : NULL;
4552:           const PetscScalar *flip = flips ? flips[p] : NULL;
4553:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4554:         } break;
4555:       case ADD_ALL_VALUES:
4556:         for (p = 0; p < numPoints; p++) {
4557:           const PetscInt    point = points[2*p];
4558:           const PetscInt    *perm = perms ? perms[p] : NULL;
4559:           const PetscScalar *flip = flips ? flips[p] : NULL;
4560:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4561:         } break;
4562:       case ADD_BC_VALUES:
4563:         for (p = 0; p < numPoints; p++) {
4564:           const PetscInt    point = points[2*p];
4565:           const PetscInt    *perm = perms ? perms[p] : NULL;
4566:           const PetscScalar *flip = flips ? flips[p] : NULL;
4567:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4568:         } break;
4569:       default:
4570:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4571:       }
4572:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4573:     }
4574:   } else {
4575:     PetscInt dof, off;
4576:     const PetscInt    **perms = NULL;
4577:     const PetscScalar **flips = NULL;

4579:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4580:     switch (mode) {
4581:     case INSERT_VALUES:
4582:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4583:         const PetscInt    point = points[2*p];
4584:         const PetscInt    *perm = perms ? perms[p] : NULL;
4585:         const PetscScalar *flip = flips ? flips[p] : NULL;
4586:         PetscSectionGetDof(section, point, &dof);
4587:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4588:       } break;
4589:     case INSERT_ALL_VALUES:
4590:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4591:         const PetscInt    point = points[2*p];
4592:         const PetscInt    *perm = perms ? perms[p] : NULL;
4593:         const PetscScalar *flip = flips ? flips[p] : NULL;
4594:         PetscSectionGetDof(section, point, &dof);
4595:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4596:       } break;
4597:     case INSERT_BC_VALUES:
4598:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4599:         const PetscInt    point = points[2*p];
4600:         const PetscInt    *perm = perms ? perms[p] : NULL;
4601:         const PetscScalar *flip = flips ? flips[p] : NULL;
4602:         PetscSectionGetDof(section, point, &dof);
4603:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4604:       } break;
4605:     case ADD_VALUES:
4606:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4607:         const PetscInt    point = points[2*p];
4608:         const PetscInt    *perm = perms ? perms[p] : NULL;
4609:         const PetscScalar *flip = flips ? flips[p] : NULL;
4610:         PetscSectionGetDof(section, point, &dof);
4611:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4612:       } break;
4613:     case ADD_ALL_VALUES:
4614:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4615:         const PetscInt    point = points[2*p];
4616:         const PetscInt    *perm = perms ? perms[p] : NULL;
4617:         const PetscScalar *flip = flips ? flips[p] : NULL;
4618:         PetscSectionGetDof(section, point, &dof);
4619:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4620:       } break;
4621:     case ADD_BC_VALUES:
4622:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4623:         const PetscInt    point = points[2*p];
4624:         const PetscInt    *perm = perms ? perms[p] : NULL;
4625:         const PetscScalar *flip = flips ? flips[p] : NULL;
4626:         PetscSectionGetDof(section, point, &dof);
4627:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4628:       } break;
4629:     default:
4630:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4631:     }
4632:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4633:   }
4634:   /* Cleanup points */
4635:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4636:   /* Cleanup array */
4637:   VecRestoreArray(v, &array);
4638:   return(0);
4639: }

4641: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4642: {
4643:   PetscSection      clSection;
4644:   IS                clPoints;
4645:   PetscScalar       *array;
4646:   PetscInt          *points = NULL;
4647:   const PetscInt    *clp, *clperm;
4648:   PetscInt          numFields, numPoints, p;
4649:   PetscInt          offset = 0, f;
4650:   PetscErrorCode    ierr;

4654:   if (!section) {DMGetSection(dm, &section);}
4657:   PetscSectionGetNumFields(section, &numFields);
4658:   /* Get points */
4659:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4660:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4661:   /* Get array */
4662:   VecGetArray(v, &array);
4663:   /* Get values */
4664:   for (f = 0; f < numFields; ++f) {
4665:     const PetscInt    **perms = NULL;
4666:     const PetscScalar **flips = NULL;

4668:     if (!fieldActive[f]) {
4669:       for (p = 0; p < numPoints*2; p += 2) {
4670:         PetscInt fdof;
4671:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4672:         offset += fdof;
4673:       }
4674:       continue;
4675:     }
4676:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4677:     switch (mode) {
4678:     case INSERT_VALUES:
4679:       for (p = 0; p < numPoints; p++) {
4680:         const PetscInt    point = points[2*p];
4681:         const PetscInt    *perm = perms ? perms[p] : NULL;
4682:         const PetscScalar *flip = flips ? flips[p] : NULL;
4683:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4684:       } break;
4685:     case INSERT_ALL_VALUES:
4686:       for (p = 0; p < numPoints; p++) {
4687:         const PetscInt    point = points[2*p];
4688:         const PetscInt    *perm = perms ? perms[p] : NULL;
4689:         const PetscScalar *flip = flips ? flips[p] : NULL;
4690:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4691:         } break;
4692:     case INSERT_BC_VALUES:
4693:       for (p = 0; p < numPoints; p++) {
4694:         const PetscInt    point = points[2*p];
4695:         const PetscInt    *perm = perms ? perms[p] : NULL;
4696:         const PetscScalar *flip = flips ? flips[p] : NULL;
4697:         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4698:       } break;
4699:     case ADD_VALUES:
4700:       for (p = 0; p < numPoints; p++) {
4701:         const PetscInt    point = points[2*p];
4702:         const PetscInt    *perm = perms ? perms[p] : NULL;
4703:         const PetscScalar *flip = flips ? flips[p] : NULL;
4704:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4705:       } break;
4706:     case ADD_ALL_VALUES:
4707:       for (p = 0; p < numPoints; p++) {
4708:         const PetscInt    point = points[2*p];
4709:         const PetscInt    *perm = perms ? perms[p] : NULL;
4710:         const PetscScalar *flip = flips ? flips[p] : NULL;
4711:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4712:       } break;
4713:     default:
4714:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4715:     }
4716:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4717:   }
4718:   /* Cleanup points */
4719:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4720:   /* Cleanup array */
4721:   VecRestoreArray(v, &array);
4722:   return(0);
4723: }

4725: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4726: {
4727:   PetscMPIInt    rank;
4728:   PetscInt       i, j;

4732:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4733:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4734:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4735:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4736:   numCIndices = numCIndices ? numCIndices : numRIndices;
4737:   for (i = 0; i < numRIndices; i++) {
4738:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4739:     for (j = 0; j < numCIndices; j++) {
4740: #if defined(PETSC_USE_COMPLEX)
4741:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4742: #else
4743:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4744: #endif
4745:     }
4746:     PetscViewerASCIIPrintf(viewer, "\n");
4747:   }
4748:   return(0);
4749: }

4751: /* . off - The global offset of this point */
4752: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4753: {
4754:   PetscInt        dof;    /* The number of unknowns on this point */
4755:   PetscInt        cdof;   /* The number of constraints on this point */
4756:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4757:   PetscInt        cind = 0, k;
4758:   PetscErrorCode  ierr;

4761:   PetscSectionGetDof(section, point, &dof);
4762:   PetscSectionGetConstraintDof(section, point, &cdof);
4763:   if (!cdof || setBC) {
4764:     if (perm) {
4765:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4766:     } else {
4767:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4768:     }
4769:   } else {
4770:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4771:     if (perm) {
4772:       for (k = 0; k < dof; ++k) {
4773:         if ((cind < cdof) && (k == cdofs[cind])) {
4774:           /* Insert check for returning constrained indices */
4775:           indices[*loff+perm[k]] = -(off+k+1);
4776:           ++cind;
4777:         } else {
4778:           indices[*loff+perm[k]] = off+k-cind;
4779:         }
4780:       }
4781:     } else {
4782:       for (k = 0; k < dof; ++k) {
4783:         if ((cind < cdof) && (k == cdofs[cind])) {
4784:           /* Insert check for returning constrained indices */
4785:           indices[*loff+k] = -(off+k+1);
4786:           ++cind;
4787:         } else {
4788:           indices[*loff+k] = off+k-cind;
4789:         }
4790:       }
4791:     }
4792:   }
4793:   *loff += dof;
4794:   return(0);
4795: }

4797: /*
4798:   This version only believes the point offset from the globalSection

4800:  . off - The global offset of this point
4801: */
4802: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4803: {
4804:   PetscInt       numFields, foff, f;

4808:   PetscSectionGetNumFields(section, &numFields);
4809:   for (f = 0, foff = 0; f < numFields; ++f) {
4810:     PetscInt        fdof, cfdof;
4811:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4812:     PetscInt        cind = 0, b;
4813:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4815:     PetscSectionGetFieldDof(section, point, f, &fdof);
4816:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4817:     if (!cfdof || setBC) {
4818:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4819:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4820:     } else {
4821:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4822:       if (perm) {
4823:         for (b = 0; b < fdof; b++) {
4824:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4825:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4826:             ++cind;
4827:           } else {
4828:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4829:           }
4830:         }
4831:       } else {
4832:         for (b = 0; b < fdof; b++) {
4833:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4834:             indices[foffs[f]+b] = -(off+foff+b+1);
4835:             ++cind;
4836:           } else {
4837:             indices[foffs[f]+b] = off+foff+b-cind;
4838:           }
4839:         }
4840:       }
4841:     }
4842:     foff     += (setBC ? fdof : (fdof - cfdof));
4843:     foffs[f] += fdof;
4844:   }
4845:   return(0);
4846: }

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

4851:  . foffs - The offset into 'indices' for each field, since it is segregated by field
4852: */
4853: PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4854: {
4855:   PetscInt       numFields, foff, f;

4859:   PetscSectionGetNumFields(section, &numFields);
4860:   for (f = 0; f < numFields; ++f) {
4861:     PetscInt        fdof, cfdof;
4862:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4863:     PetscInt        cind = 0, b;
4864:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4866:     PetscSectionGetFieldDof(section, point, f, &fdof);
4867:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4868:     PetscSectionGetFieldOffset(globalSection, point, f, &foff);
4869:     if (!cfdof || setBC) {
4870:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = foff+b;}}
4871:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = foff+b;}}
4872:     } else {
4873:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4874:       if (perm) {
4875:         for (b = 0; b < fdof; b++) {
4876:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4877:             indices[foffs[f]+perm[b]] = -(foff+b+1);
4878:             ++cind;
4879:           } else {
4880:             indices[foffs[f]+perm[b]] = foff+b-cind;
4881:           }
4882:         }
4883:       } else {
4884:         for (b = 0; b < fdof; b++) {
4885:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4886:             indices[foffs[f]+b] = -(foff+b+1);
4887:             ++cind;
4888:           } else {
4889:             indices[foffs[f]+b] = foff+b-cind;
4890:           }
4891:         }
4892:       }
4893:     }
4894:     foffs[f] += fdof;
4895:   }
4896:   return(0);
4897: }

4899: 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)
4900: {
4901:   Mat             cMat;
4902:   PetscSection    aSec, cSec;
4903:   IS              aIS;
4904:   PetscInt        aStart = -1, aEnd = -1;
4905:   const PetscInt  *anchors;
4906:   PetscInt        numFields, f, p, q, newP = 0;
4907:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4908:   PetscInt        *newPoints, *indices, *newIndices;
4909:   PetscInt        maxAnchor, maxDof;
4910:   PetscInt        newOffsets[32];
4911:   PetscInt        *pointMatOffsets[32];
4912:   PetscInt        *newPointOffsets[32];
4913:   PetscScalar     *pointMat[32];
4914:   PetscScalar     *newValues=NULL,*tmpValues;
4915:   PetscBool       anyConstrained = PETSC_FALSE;
4916:   PetscErrorCode  ierr;

4921:   PetscSectionGetNumFields(section, &numFields);

4923:   DMPlexGetAnchors(dm,&aSec,&aIS);
4924:   /* if there are point-to-point constraints */
4925:   if (aSec) {
4926:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4927:     ISGetIndices(aIS,&anchors);
4928:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4929:     /* figure out how many points are going to be in the new element matrix
4930:      * (we allow double counting, because it's all just going to be summed
4931:      * into the global matrix anyway) */
4932:     for (p = 0; p < 2*numPoints; p+=2) {
4933:       PetscInt b    = points[p];
4934:       PetscInt bDof = 0, bSecDof;

4936:       PetscSectionGetDof(section,b,&bSecDof);
4937:       if (!bSecDof) {
4938:         continue;
4939:       }
4940:       if (b >= aStart && b < aEnd) {
4941:         PetscSectionGetDof(aSec,b,&bDof);
4942:       }
4943:       if (bDof) {
4944:         /* this point is constrained */
4945:         /* it is going to be replaced by its anchors */
4946:         PetscInt bOff, q;

4948:         anyConstrained = PETSC_TRUE;
4949:         newNumPoints  += bDof;
4950:         PetscSectionGetOffset(aSec,b,&bOff);
4951:         for (q = 0; q < bDof; q++) {
4952:           PetscInt a = anchors[bOff + q];
4953:           PetscInt aDof;

4955:           PetscSectionGetDof(section,a,&aDof);
4956:           newNumIndices += aDof;
4957:           for (f = 0; f < numFields; ++f) {
4958:             PetscInt fDof;

4960:             PetscSectionGetFieldDof(section, a, f, &fDof);
4961:             newOffsets[f+1] += fDof;
4962:           }
4963:         }
4964:       }
4965:       else {
4966:         /* this point is not constrained */
4967:         newNumPoints++;
4968:         newNumIndices += bSecDof;
4969:         for (f = 0; f < numFields; ++f) {
4970:           PetscInt fDof;

4972:           PetscSectionGetFieldDof(section, b, f, &fDof);
4973:           newOffsets[f+1] += fDof;
4974:         }
4975:       }
4976:     }
4977:   }
4978:   if (!anyConstrained) {
4979:     if (outNumPoints)  *outNumPoints  = 0;
4980:     if (outNumIndices) *outNumIndices = 0;
4981:     if (outPoints)     *outPoints     = NULL;
4982:     if (outValues)     *outValues     = NULL;
4983:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4984:     return(0);
4985:   }

4987:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4988:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4992:   if (!outPoints && !outValues) {
4993:     if (offsets) {
4994:       for (f = 0; f <= numFields; f++) {
4995:         offsets[f] = newOffsets[f];
4996:       }
4997:     }
4998:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4999:     return(0);
5000:   }

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

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

5006:   /* workspaces */
5007:   if (numFields) {
5008:     for (f = 0; f < numFields; f++) {
5009:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5010:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5011:     }
5012:   }
5013:   else {
5014:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5015:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5016:   }

5018:   /* get workspaces for the point-to-point matrices */
5019:   if (numFields) {
5020:     PetscInt totalOffset, totalMatOffset;

5022:     for (p = 0; p < numPoints; p++) {
5023:       PetscInt b    = points[2*p];
5024:       PetscInt bDof = 0, bSecDof;

5026:       PetscSectionGetDof(section,b,&bSecDof);
5027:       if (!bSecDof) {
5028:         for (f = 0; f < numFields; f++) {
5029:           newPointOffsets[f][p + 1] = 0;
5030:           pointMatOffsets[f][p + 1] = 0;
5031:         }
5032:         continue;
5033:       }
5034:       if (b >= aStart && b < aEnd) {
5035:         PetscSectionGetDof(aSec, b, &bDof);
5036:       }
5037:       if (bDof) {
5038:         for (f = 0; f < numFields; f++) {
5039:           PetscInt fDof, q, bOff, allFDof = 0;

5041:           PetscSectionGetFieldDof(section, b, f, &fDof);
5042:           PetscSectionGetOffset(aSec, b, &bOff);
5043:           for (q = 0; q < bDof; q++) {
5044:             PetscInt a = anchors[bOff + q];
5045:             PetscInt aFDof;

5047:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5048:             allFDof += aFDof;
5049:           }
5050:           newPointOffsets[f][p+1] = allFDof;
5051:           pointMatOffsets[f][p+1] = fDof * allFDof;
5052:         }
5053:       }
5054:       else {
5055:         for (f = 0; f < numFields; f++) {
5056:           PetscInt fDof;

5058:           PetscSectionGetFieldDof(section, b, f, &fDof);
5059:           newPointOffsets[f][p+1] = fDof;
5060:           pointMatOffsets[f][p+1] = 0;
5061:         }
5062:       }
5063:     }
5064:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5065:       newPointOffsets[f][0] = totalOffset;
5066:       pointMatOffsets[f][0] = totalMatOffset;
5067:       for (p = 0; p < numPoints; p++) {
5068:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5069:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5070:       }
5071:       totalOffset    = newPointOffsets[f][numPoints];
5072:       totalMatOffset = pointMatOffsets[f][numPoints];
5073:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5074:     }
5075:   }
5076:   else {
5077:     for (p = 0; p < numPoints; p++) {
5078:       PetscInt b    = points[2*p];
5079:       PetscInt bDof = 0, bSecDof;

5081:       PetscSectionGetDof(section,b,&bSecDof);
5082:       if (!bSecDof) {
5083:         newPointOffsets[0][p + 1] = 0;
5084:         pointMatOffsets[0][p + 1] = 0;
5085:         continue;
5086:       }
5087:       if (b >= aStart && b < aEnd) {
5088:         PetscSectionGetDof(aSec, b, &bDof);
5089:       }
5090:       if (bDof) {
5091:         PetscInt bOff, q, allDof = 0;

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

5097:           PetscSectionGetDof(section, a, &aDof);
5098:           allDof += aDof;
5099:         }
5100:         newPointOffsets[0][p+1] = allDof;
5101:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5102:       }
5103:       else {
5104:         newPointOffsets[0][p+1] = bSecDof;
5105:         pointMatOffsets[0][p+1] = 0;
5106:       }
5107:     }
5108:     newPointOffsets[0][0] = 0;
5109:     pointMatOffsets[0][0] = 0;
5110:     for (p = 0; p < numPoints; p++) {
5111:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5112:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5113:     }
5114:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5115:   }

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

5120:   /* get the point-to-point matrices; construct newPoints */
5121:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5122:   PetscSectionGetMaxDof(section, &maxDof);
5123:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5124:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5125:   if (numFields) {
5126:     for (p = 0, newP = 0; p < numPoints; p++) {
5127:       PetscInt b    = points[2*p];
5128:       PetscInt o    = points[2*p+1];
5129:       PetscInt bDof = 0, bSecDof;

5131:       PetscSectionGetDof(section, b, &bSecDof);
5132:       if (!bSecDof) {
5133:         continue;
5134:       }
5135:       if (b >= aStart && b < aEnd) {
5136:         PetscSectionGetDof(aSec, b, &bDof);
5137:       }
5138:       if (bDof) {
5139:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5141:         fStart[0] = 0;
5142:         fEnd[0]   = 0;
5143:         for (f = 0; f < numFields; f++) {
5144:           PetscInt fDof;

5146:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5147:           fStart[f+1] = fStart[f] + fDof;
5148:           fEnd[f+1]   = fStart[f+1];
5149:         }
5150:         PetscSectionGetOffset(cSec, b, &bOff);
5151:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

5153:         fAnchorStart[0] = 0;
5154:         fAnchorEnd[0]   = 0;
5155:         for (f = 0; f < numFields; f++) {
5156:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5158:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5159:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5160:         }
5161:         PetscSectionGetOffset(aSec, b, &bOff);
5162:         for (q = 0; q < bDof; q++) {
5163:           PetscInt a = anchors[bOff + q], aOff;

5165:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5166:           newPoints[2*(newP + q)]     = a;
5167:           newPoints[2*(newP + q) + 1] = 0;
5168:           PetscSectionGetOffset(section, a, &aOff);
5169:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5170:         }
5171:         newP += bDof;

5173:         if (outValues) {
5174:           /* get the point-to-point submatrix */
5175:           for (f = 0; f < numFields; f++) {
5176:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5177:           }
5178:         }
5179:       }
5180:       else {
5181:         newPoints[2 * newP]     = b;
5182:         newPoints[2 * newP + 1] = o;
5183:         newP++;
5184:       }
5185:     }
5186:   } else {
5187:     for (p = 0; p < numPoints; p++) {
5188:       PetscInt b    = points[2*p];
5189:       PetscInt o    = points[2*p+1];
5190:       PetscInt bDof = 0, bSecDof;

5192:       PetscSectionGetDof(section, b, &bSecDof);
5193:       if (!bSecDof) {
5194:         continue;
5195:       }
5196:       if (b >= aStart && b < aEnd) {
5197:         PetscSectionGetDof(aSec, b, &bDof);
5198:       }
5199:       if (bDof) {
5200:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5211:           newPoints[2*(newP + q)]     = a;
5212:           newPoints[2*(newP + q) + 1] = 0;
5213:           PetscSectionGetOffset(section, a, &aOff);
5214:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5215:         }
5216:         newP += bDof;

5218:         /* get the point-to-point submatrix */
5219:         if (outValues) {
5220:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5221:         }
5222:       }
5223:       else {
5224:         newPoints[2 * newP]     = b;
5225:         newPoints[2 * newP + 1] = o;
5226:         newP++;
5227:       }
5228:     }
5229:   }

5231:   if (outValues) {
5232:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5233:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5234:     /* multiply constraints on the right */
5235:     if (numFields) {
5236:       for (f = 0; f < numFields; f++) {
5237:         PetscInt oldOff = offsets[f];

5239:         for (p = 0; p < numPoints; p++) {
5240:           PetscInt cStart = newPointOffsets[f][p];
5241:           PetscInt b      = points[2 * p];
5242:           PetscInt c, r, k;
5243:           PetscInt dof;

5245:           PetscSectionGetFieldDof(section,b,f,&dof);
5246:           if (!dof) {
5247:             continue;
5248:           }
5249:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5250:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5251:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5253:             for (r = 0; r < numIndices; r++) {
5254:               for (c = 0; c < nCols; c++) {
5255:                 for (k = 0; k < dof; k++) {
5256:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5257:                 }
5258:               }
5259:             }
5260:           }
5261:           else {
5262:             /* copy this column as is */
5263:             for (r = 0; r < numIndices; r++) {
5264:               for (c = 0; c < dof; c++) {
5265:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5266:               }
5267:             }
5268:           }
5269:           oldOff += dof;
5270:         }
5271:       }
5272:     }
5273:     else {
5274:       PetscInt oldOff = 0;
5275:       for (p = 0; p < numPoints; p++) {
5276:         PetscInt cStart = newPointOffsets[0][p];
5277:         PetscInt b      = points[2 * p];
5278:         PetscInt c, r, k;
5279:         PetscInt dof;

5281:         PetscSectionGetDof(section,b,&dof);
5282:         if (!dof) {
5283:           continue;
5284:         }
5285:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5286:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5287:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5289:           for (r = 0; r < numIndices; r++) {
5290:             for (c = 0; c < nCols; c++) {
5291:               for (k = 0; k < dof; k++) {
5292:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5293:               }
5294:             }
5295:           }
5296:         }
5297:         else {
5298:           /* copy this column as is */
5299:           for (r = 0; r < numIndices; r++) {
5300:             for (c = 0; c < dof; c++) {
5301:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5302:             }
5303:           }
5304:         }
5305:         oldOff += dof;
5306:       }
5307:     }

5309:     if (multiplyLeft) {
5310:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5311:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5312:       /* multiply constraints transpose on the left */
5313:       if (numFields) {
5314:         for (f = 0; f < numFields; f++) {
5315:           PetscInt oldOff = offsets[f];

5317:           for (p = 0; p < numPoints; p++) {
5318:             PetscInt rStart = newPointOffsets[f][p];
5319:             PetscInt b      = points[2 * p];
5320:             PetscInt c, r, k;
5321:             PetscInt dof;

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

5328:               for (r = 0; r < nRows; r++) {
5329:                 for (c = 0; c < newNumIndices; c++) {
5330:                   for (k = 0; k < dof; k++) {
5331:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5332:                   }
5333:                 }
5334:               }
5335:             }
5336:             else {
5337:               /* copy this row as is */
5338:               for (r = 0; r < dof; r++) {
5339:                 for (c = 0; c < newNumIndices; c++) {
5340:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5341:                 }
5342:               }
5343:             }
5344:             oldOff += dof;
5345:           }
5346:         }
5347:       }
5348:       else {
5349:         PetscInt oldOff = 0;

5351:         for (p = 0; p < numPoints; p++) {
5352:           PetscInt rStart = newPointOffsets[0][p];
5353:           PetscInt b      = points[2 * p];
5354:           PetscInt c, r, k;
5355:           PetscInt dof;

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

5362:             for (r = 0; r < nRows; r++) {
5363:               for (c = 0; c < newNumIndices; c++) {
5364:                 for (k = 0; k < dof; k++) {
5365:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5366:                 }
5367:               }
5368:             }
5369:           }
5370:           else {
5371:             /* copy this row as is */
5372:             for (r = 0; r < dof; r++) {
5373:               for (c = 0; c < newNumIndices; c++) {
5374:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5375:               }
5376:             }
5377:           }
5378:           oldOff += dof;
5379:         }
5380:       }

5382:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5383:     }
5384:     else {
5385:       newValues = tmpValues;
5386:     }
5387:   }

5389:   /* clean up */
5390:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5391:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5393:   if (numFields) {
5394:     for (f = 0; f < numFields; f++) {
5395:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5396:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5397:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5398:     }
5399:   }
5400:   else {
5401:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5402:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5403:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5404:   }
5405:   ISRestoreIndices(aIS,&anchors);

5407:   /* output */
5408:   if (outPoints) {
5409:     *outPoints = newPoints;
5410:   }
5411:   else {
5412:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5413:   }
5414:   if (outValues) {
5415:     *outValues = newValues;
5416:   }
5417:   for (f = 0; f <= numFields; f++) {
5418:     offsets[f] = newOffsets[f];
5419:   }
5420:   return(0);
5421: }

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

5426:   Not collective

5428:   Input Parameters:
5429: + dm - The DM
5430: . section - The section describing the layout in v, or NULL to use the default section
5431: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5432: - point - The mesh point

5434:   Output parameters:
5435: + numIndices - The number of indices
5436: . indices - The indices
5437: - outOffsets - Field offset if not NULL

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

5441:   Level: advanced

5443: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5444: @*/
5445: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5446: {
5447:   PetscSection    clSection;
5448:   IS              clPoints;
5449:   const PetscInt *clp;
5450:   const PetscInt  **perms[32] = {NULL};
5451:   PetscInt       *points = NULL, *pointsNew;
5452:   PetscInt        numPoints, numPointsNew;
5453:   PetscInt        offsets[32];
5454:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5455:   PetscErrorCode  ierr;

5463:   PetscSectionGetNumFields(section, &Nf);
5464:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5465:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5466:   /* Get points in closure */
5467:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5468:   /* Get number of indices and indices per field */
5469:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5470:     PetscInt dof, fdof;

5472:     PetscSectionGetDof(section, points[p], &dof);
5473:     for (f = 0; f < Nf; ++f) {
5474:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5475:       offsets[f+1] += fdof;
5476:     }
5477:     Nind += dof;
5478:   }
5479:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5480:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5481:   if (!Nf) offsets[1] = Nind;
5482:   /* Get dual space symmetries */
5483:   for (f = 0; f < PetscMax(1,Nf); f++) {
5484:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5485:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5486:   }
5487:   /* Correct for hanging node constraints */
5488:   {
5489:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5490:     if (numPointsNew) {
5491:       for (f = 0; f < PetscMax(1,Nf); f++) {
5492:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5493:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5494:       }
5495:       for (f = 0; f < PetscMax(1,Nf); f++) {
5496:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5497:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5498:       }
5499:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5500:       numPoints = numPointsNew;
5501:       Nind      = NindNew;
5502:       points    = pointsNew;
5503:     }
5504:   }
5505:   /* Calculate indices */
5506:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5507:   if (Nf) {
5508:     if (outOffsets) {
5509:       PetscInt f;

5511:       for (f = 0; f <= Nf; f++) {
5512:         outOffsets[f] = offsets[f];
5513:       }
5514:     }
5515:     for (p = 0; p < numPoints; p++) {
5516:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5517:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5518:     }
5519:   } else {
5520:     for (p = 0, off = 0; p < numPoints; p++) {
5521:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5523:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5524:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5525:     }
5526:   }
5527:   /* Cleanup points */
5528:   for (f = 0; f < PetscMax(1,Nf); f++) {
5529:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5530:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5531:   }
5532:   if (numPointsNew) {
5533:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5534:   } else {
5535:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5536:   }
5537:   if (numIndices) *numIndices = Nind;
5538:   return(0);
5539: }

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

5544:   Not collective

5546:   Input Parameters:
5547: + dm - The DM
5548: . section - The section describing the layout in v, or NULL to use the default section
5549: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5550: . point - The mesh point
5551: . numIndices - The number of indices
5552: . indices - The indices
5553: - outOffsets - Field offset if not NULL

5555:   Level: advanced

5557: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5558: @*/
5559: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5560: {

5566:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5567:   return(0);
5568: }

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

5573:   Not collective

5575:   Input Parameters:
5576: + dm - The DM
5577: . section - The section describing the layout in v, or NULL to use the default section
5578: . globalSection - The section describing the layout in v, or NULL to use the default global section
5579: . A - The matrix
5580: . point - The point in the DM
5581: . values - The array of values
5582: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5587:   Level: intermediate

5589: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5590: @*/
5591: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5592: {
5593:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5594:   PetscSection        clSection;
5595:   IS                  clPoints;
5596:   PetscInt           *points = NULL, *newPoints;
5597:   const PetscInt     *clp;
5598:   PetscInt           *indices;
5599:   PetscInt            offsets[32];
5600:   const PetscInt    **perms[32] = {NULL};
5601:   const PetscScalar **flips[32] = {NULL};
5602:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5603:   PetscScalar        *valCopy = NULL;
5604:   PetscScalar        *newValues;
5605:   PetscErrorCode      ierr;

5609:   if (!section) {DMGetSection(dm, &section);}
5611:   if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5614:   PetscSectionGetNumFields(section, &numFields);
5615:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5616:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5617:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5618:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5619:     PetscInt fdof;

5621:     PetscSectionGetDof(section, points[p], &dof);
5622:     for (f = 0; f < numFields; ++f) {
5623:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5624:       offsets[f+1] += fdof;
5625:     }
5626:     numIndices += dof;
5627:   }
5628:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5642:         if (!numFields) {
5643:           PetscSectionGetDof(section,point,&fdof);
5644:         } else {
5645:           PetscSectionGetFieldDof(section,point,f,&fdof);
5646:         }
5647:         if (flip) {
5648:           PetscInt i, j, k;

5650:           if (!valCopy) {
5651:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5652:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5653:             values = valCopy;
5654:           }
5655:           for (i = 0; i < fdof; i++) {
5656:             PetscScalar fval = flip[i];

5658:             for (k = 0; k < numIndices; k++) {
5659:               valCopy[numIndices * (foffset + i) + k] *= fval;
5660:               valCopy[numIndices * k + (foffset + i)] *= fval;
5661:             }
5662:           }
5663:         }
5664:         foffset += fdof;
5665:       }
5666:     }
5667:   }
5668:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5669:   if (newNumPoints) {
5670:     if (valCopy) {
5671:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5672:     }
5673:     for (f = 0; f < PetscMax(1,numFields); f++) {
5674:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5675:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5676:     }
5677:     for (f = 0; f < PetscMax(1,numFields); f++) {
5678:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5679:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5680:     }
5681:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5682:     numPoints  = newNumPoints;
5683:     numIndices = newNumIndices;
5684:     points     = newPoints;
5685:     values     = newValues;
5686:   }
5687:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5688:   if (numFields) {
5689:     PetscBool useFieldOffsets;

5691:     PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
5692:     if (useFieldOffsets) {
5693:       for (p = 0; p < numPoints; p++) {
5694:         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, indices);
5695:       }
5696:     } else {
5697:       for (p = 0; p < numPoints; p++) {
5698:         PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5699:         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5700:       }
5701:     }
5702:   } else {
5703:     for (p = 0, off = 0; p < numPoints; p++) {
5704:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5705:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5706:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5707:     }
5708:   }
5709:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5710:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5711:   if (mesh->printFEM > 1) {
5712:     PetscInt i;
5713:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5714:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5715:     PetscPrintf(PETSC_COMM_SELF, "\n");
5716:   }
5717:   if (ierr) {
5718:     PetscMPIInt    rank;
5719:     PetscErrorCode ierr2;

5721:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5722:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5723:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5724:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5725: 
5726:   }
5727:   for (f = 0; f < PetscMax(1,numFields); f++) {
5728:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5729:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5730:   }
5731:   if (newNumPoints) {
5732:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5733:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5734:   }
5735:   else {
5736:     if (valCopy) {
5737:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5738:     }
5739:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5740:   }
5741:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5742:   return(0);
5743: }

5745: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5746: {
5747:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5748:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5749:   PetscInt       *cpoints = NULL;
5750:   PetscInt       *findices, *cindices;
5751:   PetscInt        foffsets[32], coffsets[32];
5752:   CellRefiner     cellRefiner;
5753:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5754:   PetscErrorCode  ierr;

5759:   if (!fsection) {DMGetSection(dmf, &fsection);}
5761:   if (!csection) {DMGetSection(dmc, &csection);}
5763:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
5765:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
5768:   PetscSectionGetNumFields(fsection, &numFields);
5769:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5770:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5771:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5772:   /* Column indices */
5773:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5774:   maxFPoints = numCPoints;
5775:   /* Compress out points not in the section */
5776:   /*   TODO: Squeeze out points with 0 dof as well */
5777:   PetscSectionGetChart(csection, &pStart, &pEnd);
5778:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5779:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5780:       cpoints[q*2]   = cpoints[p];
5781:       cpoints[q*2+1] = cpoints[p+1];
5782:       ++q;
5783:     }
5784:   }
5785:   numCPoints = q;
5786:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5787:     PetscInt fdof;

5789:     PetscSectionGetDof(csection, cpoints[p], &dof);
5790:     if (!dof) continue;
5791:     for (f = 0; f < numFields; ++f) {
5792:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5793:       coffsets[f+1] += fdof;
5794:     }
5795:     numCIndices += dof;
5796:   }
5797:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5798:   /* Row indices */
5799:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5800:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5801:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5802:   for (r = 0, q = 0; r < numSubcells; ++r) {
5803:     /* TODO Map from coarse to fine cells */
5804:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5805:     /* Compress out points not in the section */
5806:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5807:     for (p = 0; p < numFPoints*2; p += 2) {
5808:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5809:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5810:         if (!dof) continue;
5811:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5812:         if (s < q) continue;
5813:         ftotpoints[q*2]   = fpoints[p];
5814:         ftotpoints[q*2+1] = fpoints[p+1];
5815:         ++q;
5816:       }
5817:     }
5818:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5819:   }
5820:   numFPoints = q;
5821:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5822:     PetscInt fdof;

5824:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5825:     if (!dof) continue;
5826:     for (f = 0; f < numFields; ++f) {
5827:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5828:       foffsets[f+1] += fdof;
5829:     }
5830:     numFIndices += dof;
5831:   }
5832:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5834:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5835:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5836:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5837:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5838:   if (numFields) {
5839:     const PetscInt **permsF[32] = {NULL};
5840:     const PetscInt **permsC[32] = {NULL};

5842:     for (f = 0; f < numFields; f++) {
5843:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5844:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5845:     }
5846:     for (p = 0; p < numFPoints; p++) {
5847:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5848:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5849:     }
5850:     for (p = 0; p < numCPoints; p++) {
5851:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5852:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5853:     }
5854:     for (f = 0; f < numFields; f++) {
5855:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5856:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5857:     }
5858:   } else {
5859:     const PetscInt **permsF = NULL;
5860:     const PetscInt **permsC = NULL;

5862:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5863:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5864:     for (p = 0, off = 0; p < numFPoints; p++) {
5865:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5867:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5868:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5869:     }
5870:     for (p = 0, off = 0; p < numCPoints; p++) {
5871:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5873:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5874:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5875:     }
5876:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5877:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5878:   }
5879:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5880:   /* TODO: flips */
5881:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5882:   if (ierr) {
5883:     PetscMPIInt    rank;
5884:     PetscErrorCode ierr2;

5886:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5887:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5888:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5889:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
5890:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
5891: 
5892:   }
5893:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
5894:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5895:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5896:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5897:   return(0);
5898: }

5900: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5901: {
5902:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5903:   PetscInt      *cpoints = NULL;
5904:   PetscInt       foffsets[32], coffsets[32];
5905:   CellRefiner    cellRefiner;
5906:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

5912:   if (!fsection) {DMGetSection(dmf, &fsection);}
5914:   if (!csection) {DMGetSection(dmc, &csection);}
5916:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
5918:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
5920:   PetscSectionGetNumFields(fsection, &numFields);
5921:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5922:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5923:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5924:   /* Column indices */
5925:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5926:   maxFPoints = numCPoints;
5927:   /* Compress out points not in the section */
5928:   /*   TODO: Squeeze out points with 0 dof as well */
5929:   PetscSectionGetChart(csection, &pStart, &pEnd);
5930:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5931:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5932:       cpoints[q*2]   = cpoints[p];
5933:       cpoints[q*2+1] = cpoints[p+1];
5934:       ++q;
5935:     }
5936:   }
5937:   numCPoints = q;
5938:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5939:     PetscInt fdof;

5941:     PetscSectionGetDof(csection, cpoints[p], &dof);
5942:     if (!dof) continue;
5943:     for (f = 0; f < numFields; ++f) {
5944:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5945:       coffsets[f+1] += fdof;
5946:     }
5947:     numCIndices += dof;
5948:   }
5949:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5950:   /* Row indices */
5951:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5952:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5953:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5954:   for (r = 0, q = 0; r < numSubcells; ++r) {
5955:     /* TODO Map from coarse to fine cells */
5956:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5957:     /* Compress out points not in the section */
5958:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5959:     for (p = 0; p < numFPoints*2; p += 2) {
5960:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5961:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5962:         if (!dof) continue;
5963:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5964:         if (s < q) continue;
5965:         ftotpoints[q*2]   = fpoints[p];
5966:         ftotpoints[q*2+1] = fpoints[p+1];
5967:         ++q;
5968:       }
5969:     }
5970:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5971:   }
5972:   numFPoints = q;
5973:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5974:     PetscInt fdof;

5976:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5977:     if (!dof) continue;
5978:     for (f = 0; f < numFields; ++f) {
5979:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5980:       foffsets[f+1] += fdof;
5981:     }
5982:     numFIndices += dof;
5983:   }
5984:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

5992:     for (f = 0; f < numFields; f++) {
5993:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5994:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5995:     }
5996:     for (p = 0; p < numFPoints; p++) {
5997:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5998:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5999:     }
6000:     for (p = 0; p < numCPoints; p++) {
6001:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6002:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6003:     }
6004:     for (f = 0; f < numFields; f++) {
6005:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6006:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6007:     }
6008:   } else {
6009:     const PetscInt **permsF = NULL;
6010:     const PetscInt **permsC = NULL;

6012:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6013:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6014:     for (p = 0, off = 0; p < numFPoints; p++) {
6015:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6017:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6018:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6019:     }
6020:     for (p = 0, off = 0; p < numCPoints; p++) {
6021:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6023:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6024:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6025:     }
6026:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6027:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6028:   }
6029:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6030:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6031:   return(0);
6032: }

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

6037:   Input Parameter:
6038: . dm - The DMPlex object

6040:   Output Parameters:
6041: + cMax - The first hybrid cell
6042: . fMax - The first hybrid face
6043: . eMax - The first hybrid edge
6044: - vMax - The first hybrid vertex

6046:   Level: developer

6048: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6049: @*/
6050: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6051: {
6052:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6053:   PetscInt       dim;

6058:   DMGetDimension(dm, &dim);
6059:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6060:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6061:   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6062:   if (eMax) *eMax = mesh->hybridPointMax[1];
6063:   if (vMax) *vMax = mesh->hybridPointMax[0];
6064:   return(0);
6065: }

6067: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6068: {
6069:   IS             is, his;
6070:   PetscInt       first = 0, stride;
6071:   PetscBool      isStride;

6075:   DMLabelGetStratumIS(depthLabel, d, &is);
6076:   PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6077:   if (isStride) {
6078:     ISStrideGetInfo(is, &first, &stride);
6079:   }
6080:   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6081:   ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6082:   DMLabelSetStratumIS(dimLabel, d, his);
6083:   ISDestroy(&his);
6084:   ISDestroy(&is);
6085:   return(0);
6086: }

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

6091:   Input Parameters:
6092: . dm   - The DMPlex object
6093: . cMax - The first hybrid cell
6094: . fMax - The first hybrid face
6095: . eMax - The first hybrid edge
6096: - vMax - The first hybrid vertex

6098:   Level: developer

6100: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6101: @*/
6102: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6103: {
6104:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6105:   PetscInt       dim;

6110:   DMGetDimension(dm, &dim);
6111:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6112:   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6113:   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6114:   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6115:   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6116:   return(0);
6117: }

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

6122:   Input Parameter:
6123: . dm   - The DMPlex object

6125:   Output Parameter:
6126: . cellHeight - The height of a cell

6128:   Level: developer

6130: .seealso DMPlexSetVTKCellHeight()
6131: @*/
6132: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6133: {
6134:   DM_Plex *mesh = (DM_Plex*) dm->data;

6139:   *cellHeight = mesh->vtkCellHeight;
6140:   return(0);
6141: }

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

6146:   Input Parameters:
6147: + dm   - The DMPlex object
6148: - cellHeight - The height of a cell

6150:   Level: developer

6152: .seealso DMPlexGetVTKCellHeight()
6153: @*/
6154: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6155: {
6156:   DM_Plex *mesh = (DM_Plex*) dm->data;

6160:   mesh->vtkCellHeight = cellHeight;
6161:   return(0);
6162: }

6164: /* We can easily have a form that takes an IS instead */
6165: PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6166: {
6167:   PetscSection   section, globalSection;
6168:   PetscInt      *numbers, p;

6172:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6173:   PetscSectionSetChart(section, pStart, pEnd);
6174:   for (p = pStart; p < pEnd; ++p) {
6175:     PetscSectionSetDof(section, p, 1);
6176:   }
6177:   PetscSectionSetUp(section);
6178:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6179:   PetscMalloc1(pEnd - pStart, &numbers);
6180:   for (p = pStart; p < pEnd; ++p) {
6181:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6182:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6183:     else                       numbers[p-pStart] += shift;
6184:   }
6185:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6186:   if (globalSize) {
6187:     PetscLayout layout;
6188:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6189:     PetscLayoutGetSize(layout, globalSize);
6190:     PetscLayoutDestroy(&layout);
6191:   }
6192:   PetscSectionDestroy(&section);
6193:   PetscSectionDestroy(&globalSection);
6194:   return(0);
6195: }

6197: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6198: {
6199:   PetscInt       cellHeight, cStart, cEnd, cMax;

6203:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6204:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6205:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6206:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6207:   DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6208:   return(0);
6209: }

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

6214:   Input Parameter:
6215: . dm   - The DMPlex object

6217:   Output Parameter:
6218: . globalCellNumbers - Global cell numbers for all cells on this process

6220:   Level: developer

6222: .seealso DMPlexGetVertexNumbering()
6223: @*/
6224: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6225: {
6226:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6231:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6232:   *globalCellNumbers = mesh->globalCellNumbers;
6233:   return(0);
6234: }

6236: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6237: {
6238:   PetscInt       vStart, vEnd, vMax;

6243:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6244:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6245:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6246:   DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6247:   return(0);
6248: }

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

6253:   Input Parameter:
6254: . dm   - The DMPlex object

6256:   Output Parameter:
6257: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6259:   Level: developer

6261: .seealso DMPlexGetCellNumbering()
6262: @*/
6263: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6264: {
6265:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6270:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6271:   *globalVertexNumbers = mesh->globalVertexNumbers;
6272:   return(0);
6273: }

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

6278:   Input Parameter:
6279: . dm   - The DMPlex object

6281:   Output Parameter:
6282: . globalPointNumbers - Global numbers for all points on this process

6284:   Level: developer

6286: .seealso DMPlexGetCellNumbering()
6287: @*/
6288: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6289: {
6290:   IS             nums[4];
6291:   PetscInt       depths[4], gdepths[4], starts[4];
6292:   PetscInt       depth, d, shift = 0;

6297:   DMPlexGetDepth(dm, &depth);
6298:   /* For unstratified meshes use dim instead of depth */
6299:   if (depth < 0) {DMGetDimension(dm, &depth);}
6300:   for (d = 0; d <= depth; ++d) {
6301:     PetscInt end;

6303:     depths[d] = depth-d;
6304:     DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6305:     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6306:   }
6307:   PetscSortIntWithArray(depth+1, starts, depths);
6308:   MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6309:   for (d = 0; d <= depth; ++d) {
6310:     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6311:   }
6312:   for (d = 0; d <= depth; ++d) {
6313:     PetscInt pStart, pEnd, gsize;

6315:     DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6316:     DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6317:     shift += gsize;
6318:   }
6319:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6320:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6321:   return(0);
6322: }


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

6328:   Input Parameter:
6329: . dm - The DMPlex object

6331:   Output Parameter:
6332: . ranks - The rank field

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

6337:   Level: intermediate

6339: .seealso: DMView()
6340: @*/
6341: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6342: {
6343:   DM             rdm;
6344:   PetscFE        fe;
6345:   PetscScalar   *r;
6346:   PetscMPIInt    rank;
6347:   PetscInt       dim, cStart, cEnd, c;

6353:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6354:   DMClone(dm, &rdm);
6355:   DMGetDimension(rdm, &dim);
6356:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6357:   PetscObjectSetName((PetscObject) fe, "rank");
6358:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6359:   PetscFEDestroy(&fe);
6360:   DMCreateDS(rdm);
6361:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6362:   DMCreateGlobalVector(rdm, ranks);
6363:   PetscObjectSetName((PetscObject) *ranks, "partition");
6364:   VecGetArray(*ranks, &r);
6365:   for (c = cStart; c < cEnd; ++c) {
6366:     PetscScalar *lr;

6368:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6369:     *lr = rank;
6370:   }
6371:   VecRestoreArray(*ranks, &r);
6372:   DMDestroy(&rdm);
6373:   return(0);
6374: }

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

6379:   Input Parameters:
6380: + dm    - The DMPlex
6381: - label - The DMLabel

6383:   Output Parameter:
6384: . val - The label value field

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

6389:   Level: intermediate

6391: .seealso: DMView()
6392: @*/
6393: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6394: {
6395:   DM             rdm;
6396:   PetscFE        fe;
6397:   PetscScalar   *v;
6398:   PetscInt       dim, cStart, cEnd, c;

6405:   DMClone(dm, &rdm);
6406:   DMGetDimension(rdm, &dim);
6407:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6408:   PetscObjectSetName((PetscObject) fe, "label_value");
6409:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6410:   PetscFEDestroy(&fe);
6411:   DMCreateDS(rdm);
6412:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6413:   DMCreateGlobalVector(rdm, val);
6414:   PetscObjectSetName((PetscObject) *val, "label_value");
6415:   VecGetArray(*val, &v);
6416:   for (c = cStart; c < cEnd; ++c) {
6417:     PetscScalar *lv;
6418:     PetscInt     cval;

6420:     DMPlexPointGlobalRef(rdm, c, v, &lv);
6421:     DMLabelGetValue(label, c, &cval);
6422:     *lv = cval;
6423:   }
6424:   VecRestoreArray(*val, &v);
6425:   DMDestroy(&rdm);
6426:   return(0);
6427: }

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

6432:   Input Parameter:
6433: . dm - The DMPlex object

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

6437:   Level: developer

6439: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6440: @*/
6441: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6442: {
6443:   PetscSection    coneSection, supportSection;
6444:   const PetscInt *cone, *support;
6445:   PetscInt        coneSize, c, supportSize, s;
6446:   PetscInt        pStart, pEnd, p, pp, csize, ssize;
6447:   PetscBool       storagecheck = PETSC_TRUE;
6448:   PetscErrorCode  ierr;

6452:   DMPlexGetConeSection(dm, &coneSection);
6453:   DMPlexGetSupportSection(dm, &supportSection);
6454:   /* Check that point p is found in the support of its cone points, and vice versa */
6455:   DMPlexGetChart(dm, &pStart, &pEnd);
6456:   for (p = pStart; p < pEnd; ++p) {
6457:     DMPlexGetConeSize(dm, p, &coneSize);
6458:     DMPlexGetCone(dm, p, &cone);
6459:     for (c = 0; c < coneSize; ++c) {
6460:       PetscBool dup = PETSC_FALSE;
6461:       PetscInt  d;
6462:       for (d = c-1; d >= 0; --d) {
6463:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6464:       }
6465:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6466:       DMPlexGetSupport(dm, cone[c], &support);
6467:       for (s = 0; s < supportSize; ++s) {
6468:         if (support[s] == p) break;
6469:       }
6470:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6471:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6472:         for (s = 0; s < coneSize; ++s) {
6473:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6474:         }
6475:         PetscPrintf(PETSC_COMM_SELF, "\n");
6476:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6477:         for (s = 0; s < supportSize; ++s) {
6478:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6479:         }
6480:         PetscPrintf(PETSC_COMM_SELF, "\n");
6481:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6482:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6483:       }
6484:     }
6485:     DMPlexGetTreeParent(dm, p, &pp, NULL);
6486:     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6487:     DMPlexGetSupportSize(dm, p, &supportSize);
6488:     DMPlexGetSupport(dm, p, &support);
6489:     for (s = 0; s < supportSize; ++s) {
6490:       DMPlexGetConeSize(dm, support[s], &coneSize);
6491:       DMPlexGetCone(dm, support[s], &cone);
6492:       for (c = 0; c < coneSize; ++c) {
6493:         DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
6494:         if (cone[c] != pp) { c = 0; break; }
6495:         if (cone[c] == p) break;
6496:       }
6497:       if (c >= coneSize) {
6498:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6499:         for (c = 0; c < supportSize; ++c) {
6500:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6501:         }
6502:         PetscPrintf(PETSC_COMM_SELF, "\n");
6503:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6504:         for (c = 0; c < coneSize; ++c) {
6505:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6506:         }
6507:         PetscPrintf(PETSC_COMM_SELF, "\n");
6508:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6509:       }
6510:     }
6511:   }
6512:   if (storagecheck) {
6513:     PetscSectionGetStorageSize(coneSection, &csize);
6514:     PetscSectionGetStorageSize(supportSection, &ssize);
6515:     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6516:   }
6517:   return(0);
6518: }

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

6523:   Input Parameters:
6524: + dm - The DMPlex object
6525: . isSimplex - Are the cells simplices or tensor products
6526: - cellHeight - Normally 0

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

6530:   Level: developer

6532: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6533: @*/
6534: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6535: {
6536:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6541:   DMGetDimension(dm, &dim);
6542:   switch (dim) {
6543:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6544:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6545:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6546:   default:
6547:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6548:   }
6549:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6550:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6551:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6552:   cMax = cMax >= 0 ? cMax : cEnd;
6553:   for (c = cStart; c < cMax; ++c) {
6554:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6556:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6557:     for (cl = 0; cl < closureSize*2; cl += 2) {
6558:       const PetscInt p = closure[cl];
6559:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6560:     }
6561:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6562:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6563:   }
6564:   for (c = cMax; c < cEnd; ++c) {
6565:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6567:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6568:     for (cl = 0; cl < closureSize*2; cl += 2) {
6569:       const PetscInt p = closure[cl];
6570:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6571:     }
6572:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6573:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6574:   }
6575:   return(0);
6576: }

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

6581:   Input Parameters:
6582: + dm - The DMPlex object
6583: . isSimplex - Are the cells simplices or tensor products
6584: - cellHeight - Normally 0

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

6588:   Level: developer

6590: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6591: @*/
6592: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6593: {
6594:   PetscInt       pMax[4];
6595:   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;

6600:   DMGetDimension(dm, &dim);
6601:   DMPlexGetDepth(dm, &depth);
6602:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6603:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6604:   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
6605:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6606:     for (c = cStart; c < cEnd; ++c) {
6607:       const PetscInt *cone, *ornt, *faces;
6608:       PetscInt        numFaces, faceSize, coneSize,f;
6609:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6611:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6612:       DMPlexGetConeSize(dm, c, &coneSize);
6613:       DMPlexGetCone(dm, c, &cone);
6614:       DMPlexGetConeOrientation(dm, c, &ornt);
6615:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6616:       for (cl = 0; cl < closureSize*2; cl += 2) {
6617:         const PetscInt p = closure[cl];
6618:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6619:       }
6620:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6621:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6622:       for (f = 0; f < numFaces; ++f) {
6623:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6625:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6626:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6627:           const PetscInt p = fclosure[cl];
6628:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6629:         }
6630:         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);
6631:         for (v = 0; v < fnumCorners; ++v) {
6632:           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]);
6633:         }
6634:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6635:       }
6636:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6637:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6638:     }
6639:   }
6640:   return(0);
6641: }

6643: /*@
6644:   DMPlexCheckGeometry - Check the geometry of mesh cells

6646:   Input Parameter:
6647: . dm - The DMPlex object

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

6651:   Level: developer

6653: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
6654: @*/
6655: PetscErrorCode DMPlexCheckGeometry(DM dm)
6656: {
6657:   PetscReal      detJ, J[9], refVol = 1.0;
6658:   PetscReal      vol;
6659:   PetscInt       dim, depth, d, cStart, cEnd, c;

6663:   DMGetDimension(dm, &dim);
6664:   DMPlexGetDepth(dm, &depth);
6665:   for (d = 0; d < dim; ++d) refVol *= 2.0;
6666:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6667:   for (c = cStart; c < cEnd; ++c) {
6668:     DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
6669:     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
6670:     PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
6671:     if (depth > 1) {
6672:       DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
6673:       if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
6674:       PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
6675:     }
6676:   }
6677:   return(0);
6678: }

6680: static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
6681: {
6682:   PetscInt i,l,n;
6683:   const PetscInt *cone;

6687:   *missingPoint = -1;
6688:   DMPlexGetConeSize(dm, p, &n);
6689:   DMPlexGetCone(dm, p, &cone);
6690:   for (i=0; i<n; i++) {
6691:     PetscFindInt(cone[i], npoints, points, &l);
6692:     if (l < 0) {
6693:       *missingPoint = cone[i];
6694:       break;
6695:     }
6696:   }
6697:   return(0);
6698: }

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

6703:   Input Parameters:
6704: . dm - The DMPlex object

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

6708:   Level: developer

6710: .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6711: @*/
6712: PetscErrorCode DMPlexCheckPointSF(DM dm)
6713: {
6714:   PetscSF sf;
6715:   PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
6716:   const PetscInt *locals;

6721:   DMPlexGetDepth(dm, &depth);
6722:   DMGetPointSF(dm, &sf);
6723:   PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);

6725:   /* 1) check there are no faces in 2D, cells in 3D, in interface */
6726:   DMPlexGetVTKCellHeight(dm, &d);
6727:   DMPlexGetHeightStratum(dm, d, &plo, &phi);
6728:   for (i=0; i<nleaves; i++) {
6729:     p = locals[i];
6730:     if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
6731:   }

6733:   /* 2) if some point is in interface, then all its cone points must be also in interface  */
6734:   for (i=0; i<nleaves; i++) {
6735:     p = locals[i];
6736:     DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);
6737:     if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
6738:   }
6739:   return(0);
6740: }

6742: typedef struct cell_stats
6743: {
6744:   PetscReal min, max, sum, squaresum;
6745:   PetscInt  count;
6746: } cell_stats_t;

6748: static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
6749: {
6750:   PetscInt i, N = *len;

6752:   for (i = 0; i < N; i++) {
6753:     cell_stats_t *A = (cell_stats_t *) a;
6754:     cell_stats_t *B = (cell_stats_t *) b;

6756:     B->min = PetscMin(A->min,B->min);
6757:     B->max = PetscMax(A->max,B->max);
6758:     B->sum += A->sum;
6759:     B->squaresum += A->squaresum;
6760:     B->count += A->count;
6761:   }
6762: }

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

6767:   Input Parameters:
6768: + dm - The DMPlex object
6769: - output - If true, statistics will be displayed on stdout

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

6773:   Level: developer

6775: .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6776: @*/
6777: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output)
6778: {
6779:   PetscMPIInt    rank,size;
6780:   PetscInt       dim, c, cStart, cEnd, cMax, count = 0;
6781:   cell_stats_t   stats, globalStats;
6782:   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
6783:   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
6784:   DM             dmCoarse;

6789:   stats.min   = PETSC_MAX_REAL;
6790:   stats.max   = PETSC_MIN_REAL;
6791:   stats.sum   = stats.squaresum = 0.;
6792:   stats.count = 0;

6794:   DMGetCoordinateDim(dm,&dim);
6795:   PetscMalloc2(dim * dim, &J, dim * dim, &invJ);
6796:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
6797:   DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
6798:   cMax = cMax < 0 ? cEnd : cMax;
6799:   for (c = cStart; c < cMax; c++) {
6800:     PetscInt  i;
6801:     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;

6803:     DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
6804:     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
6805:     for (i = 0; i < dim * dim; i++) {
6806:       frobJ    += J[i] * J[i];
6807:       frobInvJ += invJ[i] * invJ[i];
6808:     }
6809:     cond2 = frobJ * frobInvJ;
6810:     cond  = PetscSqrtReal(cond2);

6812:     stats.min        = PetscMin(stats.min,cond);
6813:     stats.max        = PetscMax(stats.max,cond);
6814:     stats.sum       += cond;
6815:     stats.squaresum += cond2;
6816:     stats.count++;
6817:   }

6819:   MPI_Comm_size(comm,&size);
6820:   if (size > 1) {
6821:     PetscMPIInt   blockLengths[2] = {4,1};
6822:     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
6823:     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
6824:     MPI_Op        statReduce;

6826:     MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
6827:     MPI_Type_commit(&statType);
6828:     MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
6829:     MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
6830:     MPI_Op_free(&statReduce);
6831:     MPI_Type_free(&statType);
6832:   } else {
6833:     PetscMemcpy(&globalStats,&stats,sizeof(stats));
6834:   }

6836:   MPI_Comm_rank(comm,&rank);
6837:   if (!rank) {
6838:     count = globalStats.count;
6839:     min   = globalStats.min;
6840:     max   = globalStats.max;
6841:     mean  = globalStats.sum / globalStats.count;
6842:     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
6843:   }

6845:   if (output) {
6846:     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);
6847:   }
6848:   PetscFree2(J,invJ);

6850:   DMGetCoarseDM(dm,&dmCoarse);
6851:   if (dmCoarse) {
6852:     PetscBool isplex;

6854:     PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
6855:     if (isplex) {
6856:       DMPlexCheckCellShape(dmCoarse,output);
6857:     }
6858:   }
6859:   return(0);
6860: }

6862: /* Pointwise interpolation
6863:      Just code FEM for now
6864:      u^f = I u^c
6865:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6866:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6867:      I_{ij} = psi^f_i phi^c_j
6868: */
6869: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6870: {
6871:   PetscSection   gsc, gsf;
6872:   PetscInt       m, n;
6873:   void          *ctx;
6874:   DM             cdm;
6875:   PetscBool      regular, ismatis;

6879:   DMGetGlobalSection(dmFine, &gsf);
6880:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6881:   DMGetGlobalSection(dmCoarse, &gsc);
6882:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6884:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
6885:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6886:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6887:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
6888:   DMGetApplicationContext(dmFine, &ctx);

6890:   DMGetCoarseDM(dmFine, &cdm);
6891:   DMPlexGetRegularRefinement(dmFine, &regular);
6892:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6893:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6894:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6895:   if (scaling) {
6896:     /* Use naive scaling */
6897:     DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6898:   }
6899:   return(0);
6900: }

6902: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6903: {
6905:   VecScatter     ctx;

6908:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6909:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6910:   VecScatterDestroy(&ctx);
6911:   return(0);
6912: }

6914: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6915: {
6916:   PetscSection   gsc, gsf;
6917:   PetscInt       m, n;
6918:   void          *ctx;
6919:   DM             cdm;
6920:   PetscBool      regular;

6924:   DMGetGlobalSection(dmFine, &gsf);
6925:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6926:   DMGetGlobalSection(dmCoarse, &gsc);
6927:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6929:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6930:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6931:   MatSetType(*mass, dmCoarse->mattype);
6932:   DMGetApplicationContext(dmFine, &ctx);

6934:   DMGetCoarseDM(dmFine, &cdm);
6935:   DMPlexGetRegularRefinement(dmFine, &regular);
6936:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6937:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6938:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6939:   return(0);
6940: }

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

6945:   Input Parameter:
6946: . dm - The DMPlex object

6948:   Output Parameter:
6949: . regular - The flag

6951:   Level: intermediate

6953: .seealso: DMPlexSetRegularRefinement()
6954: @*/
6955: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6956: {
6960:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6961:   return(0);
6962: }

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

6967:   Input Parameters:
6968: + dm - The DMPlex object
6969: - regular - The flag

6971:   Level: intermediate

6973: .seealso: DMPlexGetRegularRefinement()
6974: @*/
6975: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6976: {
6979:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6980:   return(0);
6981: }

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

6988:   not collective

6990:   Input Parameters:
6991: . dm - The DMPlex object

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


6998:   Level: intermediate

7000: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7001: @*/
7002: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7003: {
7004:   DM_Plex *plex = (DM_Plex *)dm->data;

7009:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7010:   if (anchorSection) *anchorSection = plex->anchorSection;
7011:   if (anchorIS) *anchorIS = plex->anchorIS;
7012:   return(0);
7013: }

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

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

7023:   collective on dm

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

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

7032:   Level: intermediate

7034: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7035: @*/
7036: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7037: {
7038:   DM_Plex        *plex = (DM_Plex *)dm->data;
7039:   PetscMPIInt    result;

7044:   if (anchorSection) {
7046:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7047:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7048:   }
7049:   if (anchorIS) {
7051:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7052:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7053:   }

7055:   PetscObjectReference((PetscObject)anchorSection);
7056:   PetscSectionDestroy(&plex->anchorSection);
7057:   plex->anchorSection = anchorSection;

7059:   PetscObjectReference((PetscObject)anchorIS);
7060:   ISDestroy(&plex->anchorIS);
7061:   plex->anchorIS = anchorIS;

7063: #if defined(PETSC_USE_DEBUG)
7064:   if (anchorIS && anchorSection) {
7065:     PetscInt size, a, pStart, pEnd;
7066:     const PetscInt *anchors;

7068:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7069:     ISGetLocalSize(anchorIS,&size);
7070:     ISGetIndices(anchorIS,&anchors);
7071:     for (a = 0; a < size; a++) {
7072:       PetscInt p;

7074:       p = anchors[a];
7075:       if (p >= pStart && p < pEnd) {
7076:         PetscInt dof;

7078:         PetscSectionGetDof(anchorSection,p,&dof);
7079:         if (dof) {
7080:           PetscErrorCode ierr2;

7082:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7083:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7084:         }
7085:       }
7086:     }
7087:     ISRestoreIndices(anchorIS,&anchors);
7088:   }
7089: #endif
7090:   /* reset the generic constraints */
7091:   DMSetDefaultConstraints(dm,NULL,NULL);
7092:   return(0);
7093: }

7095: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7096: {
7097:   PetscSection anchorSection;
7098:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

7103:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7104:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
7105:   PetscSectionGetNumFields(section,&numFields);
7106:   if (numFields) {
7107:     PetscInt f;
7108:     PetscSectionSetNumFields(*cSec,numFields);

7110:     for (f = 0; f < numFields; f++) {
7111:       PetscInt numComp;

7113:       PetscSectionGetFieldComponents(section,f,&numComp);
7114:       PetscSectionSetFieldComponents(*cSec,f,numComp);
7115:     }
7116:   }
7117:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7118:   PetscSectionGetChart(section,&sStart,&sEnd);
7119:   pStart = PetscMax(pStart,sStart);
7120:   pEnd   = PetscMin(pEnd,sEnd);
7121:   pEnd   = PetscMax(pStart,pEnd);
7122:   PetscSectionSetChart(*cSec,pStart,pEnd);
7123:   for (p = pStart; p < pEnd; p++) {
7124:     PetscSectionGetDof(anchorSection,p,&dof);
7125:     if (dof) {
7126:       PetscSectionGetDof(section,p,&dof);
7127:       PetscSectionSetDof(*cSec,p,dof);
7128:       for (f = 0; f < numFields; f++) {
7129:         PetscSectionGetFieldDof(section,p,f,&dof);
7130:         PetscSectionSetFieldDof(*cSec,p,f,dof);
7131:       }
7132:     }
7133:   }
7134:   PetscSectionSetUp(*cSec);
7135:   return(0);
7136: }

7138: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7139: {
7140:   PetscSection aSec;
7141:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7142:   const PetscInt *anchors;
7143:   PetscInt numFields, f;
7144:   IS aIS;

7149:   PetscSectionGetStorageSize(cSec, &m);
7150:   PetscSectionGetStorageSize(section, &n);
7151:   MatCreate(PETSC_COMM_SELF,cMat);
7152:   MatSetSizes(*cMat,m,n,m,n);
7153:   MatSetType(*cMat,MATSEQAIJ);
7154:   DMPlexGetAnchors(dm,&aSec,&aIS);
7155:   ISGetIndices(aIS,&anchors);
7156:   /* cSec will be a subset of aSec and section */
7157:   PetscSectionGetChart(cSec,&pStart,&pEnd);
7158:   PetscMalloc1(m+1,&i);
7159:   i[0] = 0;
7160:   PetscSectionGetNumFields(section,&numFields);
7161:   for (p = pStart; p < pEnd; p++) {
7162:     PetscInt rDof, rOff, r;

7164:     PetscSectionGetDof(aSec,p,&rDof);
7165:     if (!rDof) continue;
7166:     PetscSectionGetOffset(aSec,p,&rOff);
7167:     if (numFields) {
7168:       for (f = 0; f < numFields; f++) {
7169:         annz = 0;
7170:         for (r = 0; r < rDof; r++) {
7171:           a = anchors[rOff + r];
7172:           PetscSectionGetFieldDof(section,a,f,&aDof);
7173:           annz += aDof;
7174:         }
7175:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7176:         PetscSectionGetFieldOffset(cSec,p,f,&off);
7177:         for (q = 0; q < dof; q++) {
7178:           i[off + q + 1] = i[off + q] + annz;
7179:         }
7180:       }
7181:     }
7182:     else {
7183:       annz = 0;
7184:       for (q = 0; q < dof; q++) {
7185:         a = anchors[off + q];
7186:         PetscSectionGetDof(section,a,&aDof);
7187:         annz += aDof;
7188:       }
7189:       PetscSectionGetDof(cSec,p,&dof);
7190:       PetscSectionGetOffset(cSec,p,&off);
7191:       for (q = 0; q < dof; q++) {
7192:         i[off + q + 1] = i[off + q] + annz;
7193:       }
7194:     }
7195:   }
7196:   nnz = i[m];
7197:   PetscMalloc1(nnz,&j);
7198:   offset = 0;
7199:   for (p = pStart; p < pEnd; p++) {
7200:     if (numFields) {
7201:       for (f = 0; f < numFields; f++) {
7202:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7203:         for (q = 0; q < dof; q++) {
7204:           PetscInt rDof, rOff, r;
7205:           PetscSectionGetDof(aSec,p,&rDof);
7206:           PetscSectionGetOffset(aSec,p,&rOff);
7207:           for (r = 0; r < rDof; r++) {
7208:             PetscInt s;

7210:             a = anchors[rOff + r];
7211:             PetscSectionGetFieldDof(section,a,f,&aDof);
7212:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7213:             for (s = 0; s < aDof; s++) {
7214:               j[offset++] = aOff + s;
7215:             }
7216:           }
7217:         }
7218:       }
7219:     }
7220:     else {
7221:       PetscSectionGetDof(cSec,p,&dof);
7222:       for (q = 0; q < dof; q++) {
7223:         PetscInt rDof, rOff, r;
7224:         PetscSectionGetDof(aSec,p,&rDof);
7225:         PetscSectionGetOffset(aSec,p,&rOff);
7226:         for (r = 0; r < rDof; r++) {
7227:           PetscInt s;

7229:           a = anchors[rOff + r];
7230:           PetscSectionGetDof(section,a,&aDof);
7231:           PetscSectionGetOffset(section,a,&aOff);
7232:           for (s = 0; s < aDof; s++) {
7233:             j[offset++] = aOff + s;
7234:           }
7235:         }
7236:       }
7237:     }
7238:   }
7239:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7240:   PetscFree(i);
7241:   PetscFree(j);
7242:   ISRestoreIndices(aIS,&anchors);
7243:   return(0);
7244: }

7246: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7247: {
7248:   DM_Plex        *plex = (DM_Plex *)dm->data;
7249:   PetscSection   anchorSection, section, cSec;
7250:   Mat            cMat;

7255:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7256:   if (anchorSection) {
7257:     PetscInt Nf;

7259:     DMGetSection(dm,&section);
7260:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7261:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7262:     DMGetNumFields(dm,&Nf);
7263:     if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7264:     DMSetDefaultConstraints(dm,cSec,cMat);
7265:     PetscSectionDestroy(&cSec);
7266:     MatDestroy(&cMat);
7267:   }
7268:   return(0);
7269: }

7271: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7272: {
7273:   IS             subis;
7274:   PetscSection   section, subsection;

7278:   DMGetDefaultSection(dm, &section);
7279:   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7280:   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7281:   /* Create subdomain */
7282:   DMPlexFilter(dm, label, value, subdm);
7283:   /* Create submodel */
7284:   DMPlexCreateSubpointIS(*subdm, &subis);
7285:   PetscSectionCreateSubmeshSection(section, subis, &subsection);
7286:   ISDestroy(&subis);
7287:   DMSetDefaultSection(*subdm, subsection);
7288:   PetscSectionDestroy(&subsection);
7289:   DMCopyDisc(dm, *subdm);
7290:   /* Create map from submodel to global model */
7291:   if (is) {
7292:     PetscSection    sectionGlobal, subsectionGlobal;
7293:     IS              spIS;
7294:     const PetscInt *spmap;
7295:     PetscInt       *subIndices;
7296:     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
7297:     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];

7299:     DMPlexCreateSubpointIS(*subdm, &spIS);
7300:     ISGetIndices(spIS, &spmap);
7301:     PetscSectionGetNumFields(section, &Nf);
7302:     DMGetDefaultGlobalSection(dm, &sectionGlobal);
7303:     DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);
7304:     PetscSectionGetChart(subsection, &pStart, &pEnd);
7305:     for (p = pStart; p < pEnd; ++p) {
7306:       PetscInt gdof, pSubSize  = 0;

7308:       PetscSectionGetDof(sectionGlobal, p, &gdof);
7309:       if (gdof > 0) {
7310:         for (f = 0; f < Nf; ++f) {
7311:           PetscInt fdof, fcdof;

7313:           PetscSectionGetFieldDof(subsection, p, f, &fdof);
7314:           PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7315:           pSubSize += fdof-fcdof;
7316:         }
7317:         subSize += pSubSize;
7318:         if (pSubSize) {
7319:           if (bs < 0) {
7320:             bs = pSubSize;
7321:           } else if (bs != pSubSize) {
7322:             /* Layout does not admit a pointwise block size */
7323:             bs = 1;
7324:           }
7325:         }
7326:       }
7327:     }
7328:     /* Must have same blocksize on all procs (some might have no points) */
7329:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7330:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7331:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7332:     else                            {bs = bsMinMax[0];}
7333:     PetscMalloc1(subSize, &subIndices);
7334:     for (p = pStart; p < pEnd; ++p) {
7335:       PetscInt gdof, goff;

7337:       PetscSectionGetDof(subsectionGlobal, p, &gdof);
7338:       if (gdof > 0) {
7339:         const PetscInt point = spmap[p];

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

7345:           /* Can get rid of this loop by storing field information in the global section */
7346:           for (f2 = 0; f2 < f; ++f2) {
7347:             PetscSectionGetFieldDof(section, p, f2, &fdof);
7348:             PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7349:             poff += fdof-fcdof;
7350:           }
7351:           PetscSectionGetFieldDof(section, p, f, &fdof);
7352:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7353:           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7354:             subIndices[subOff] = goff+poff+fc;
7355:           }
7356:         }
7357:       }
7358:     }
7359:     ISRestoreIndices(spIS, &spmap);
7360:     ISDestroy(&spIS);
7361:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7362:     if (bs > 1) {
7363:       /* We need to check that the block size does not come from non-contiguous fields */
7364:       PetscInt i, j, set = 1;
7365:       for (i = 0; i < subSize; i += bs) {
7366:         for (j = 0; j < bs; ++j) {
7367:           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7368:         }
7369:       }
7370:       if (set) {ISSetBlockSize(*is, bs);}
7371:     }
7372:     /* Attach nullspace */
7373:     for (f = 0; f < Nf; ++f) {
7374:       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7375:       if ((*subdm)->nullspaceConstructors[f]) break;
7376:     }
7377:     if (f < Nf) {
7378:       MatNullSpace nullSpace;

7380:       (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7381:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7382:       MatNullSpaceDestroy(&nullSpace);
7383:     }
7384:   }
7385:   return(0);
7386: }