Actual source code: plex.c

petsc-3.11.0 2019-03-29
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:     const char *vecname;
418:     PetscInt    n, nroots;

420:     if (dm->sfNatural) {
421:       VecGetLocalSize(originalv, &n);
422:       PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
423:       if (n == nroots) {
424:         DMGetGlobalVector(dm, &v);
425:         DMPlexGlobalToNaturalBegin(dm, originalv, v);
426:         DMPlexGlobalToNaturalEnd(dm, originalv, v);
427:         PetscObjectGetName((PetscObject) originalv, &vecname);
428:         PetscObjectSetName((PetscObject) v, vecname);
429:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
430:     } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
431:   } else {
432:     /* we are viewing a natural DMPlex vec. */
433:     v = originalv;
434:   }
435:   if (ishdf5) {
436: #if defined(PETSC_HAVE_HDF5)
437:     VecView_Plex_HDF5_Native_Internal(v, viewer);
438: #else
439:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
440: #endif
441:   } else if (isvtk) {
442:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
443:   } else {
444:     PetscBool isseq;

446:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
447:     if (isseq) {VecView_Seq(v, viewer);}
448:     else       {VecView_MPI(v, viewer);}
449:   }
450:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
451:   return(0);
452: }

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

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

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

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

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

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

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

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

540: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
541: {
542:   PetscSection       coordSection;
543:   Vec                coordinates;
544:   DMLabel            depthLabel;
545:   const char        *name[4];
546:   const PetscScalar *a;
547:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
548:   PetscErrorCode     ierr;

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

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

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

595: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
596: {
597:   DM_Plex          *mesh = (DM_Plex*) dm->data;
598:   DM                cdm;
599:   DMLabel           markers;
600:   PetscSection      coordSection;
601:   Vec               coordinates;
602:   PetscViewerFormat format;
603:   PetscErrorCode    ierr;

606:   DMGetCoordinateDM(dm, &cdm);
607:   DMGetSection(cdm, &coordSection);
608:   DMGetCoordinatesLocal(dm, &coordinates);
609:   PetscViewerGetFormat(viewer, &format);
610:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
611:     const char *name;
612:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
613:     PetscInt    pStart, pEnd, p;
614:     PetscMPIInt rank, size;

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

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

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

658:       DMGetPointSF(dm, &sf);
659:       PetscSFView(sf, viewer);
660:     }
661:     PetscViewerFlush(viewer);
662:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
663:     const char  *name, *color;
664:     const char  *defcolors[3]  = {"gray", "orange", "green"};
665:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
666:     PetscReal    scale         = 2.0;
667:     PetscReal    tikzscale     = 1.0;
668:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
669:     double       tcoords[3];
670:     PetscScalar *coords;
671:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
672:     PetscMPIInt  rank, size;
673:     char         **names, **colors, **lcolors;
674:     PetscBool    plotEdges, flg;

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

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

767:         color = colors[rank%numColors];
768:         for (l = 0; l < numLabels; ++l) {
769:           PetscInt val;
770:           DMGetLabelValue(dm, names[l], e, &val);
771:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
772:         }
773:         DMPlexGetCone(dm, e, &cone);
774:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
775:       }
776:     } else {
777:       for (c = cStart; c < cEnd; ++c) {
778:         PetscInt *closure = NULL;
779:         PetscInt  closureSize, firstPoint = -1;

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

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

803:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
804:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
805:       for (p = 0; p < closureSize*2; p += 2) {
806:         const PetscInt point = closure[p];
807:         PetscInt       off;

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

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

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

958:       DMGetLabelName(dm, l, &name);
959:       DMGetLabel(dm, name, &label);
960:       DMLabelGetNumValues(label, &numValues);
961:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
962:       DMLabelGetValueIS(label, &valueIS);
963:       ISGetIndices(valueIS, &values);
964:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
965:       for (v = 0; v < numValues; ++v) {
966:         PetscInt size;

968:         DMLabelGetStratumSize(label, values[v], &size);
969:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
970:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
971:       }
972:       PetscViewerASCIIPrintf(viewer, ")\n");
973:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
974:       ISRestoreIndices(valueIS, &values);
975:       ISDestroy(&valueIS);
976:     }
977:     /* If no fields are specified, people do not want to see adjacency */
978:     if (dm->Nf) {
979:       PetscInt f;

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

984:         PetscObjectGetName(dm->fields[f].disc, &name);
985:         if (numLabels) {PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);}
986:         PetscViewerASCIIPushTab(viewer);
987:         if (dm->fields[f].label) {DMLabelView(dm->fields[f].label, viewer);}
988:         if (dm->fields[f].adjacency[0]) {
989:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");}
990:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");}
991:         } else {
992:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");}
993:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");}
994:         }
995:         PetscViewerASCIIPopTab(viewer);
996:       }
997:     }
998:     DMGetCoarseDM(dm, &cdm);
999:     if (cdm) {
1000:       PetscViewerASCIIPushTab(viewer);
1001:       DMPlexView_Ascii(cdm, viewer);
1002:       PetscViewerASCIIPopTab(viewer);
1003:     }
1004:   }
1005:   return(0);
1006: }

1008: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1009: {
1010:   PetscDraw          draw;
1011:   DM                 cdm;
1012:   PetscSection       coordSection;
1013:   Vec                coordinates;
1014:   const PetscScalar *coords;
1015:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1016:   PetscBool          isnull;
1017:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
1018:   PetscMPIInt        rank;
1019:   PetscErrorCode     ierr;

1022:   DMGetCoordinateDim(dm, &dim);
1023:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1024:   DMGetCoordinateDM(dm, &cdm);
1025:   DMGetSection(cdm, &coordSection);
1026:   DMGetCoordinatesLocal(dm, &coordinates);
1027:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1028:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

1030:   PetscViewerDrawGetDraw(viewer, 0, &draw);
1031:   PetscDrawIsNull(draw, &isnull);
1032:   if (isnull) return(0);
1033:   PetscDrawSetTitle(draw, "Mesh");

1035:   VecGetLocalSize(coordinates, &N);
1036:   VecGetArrayRead(coordinates, &coords);
1037:   for (c = 0; c < N; c += dim) {
1038:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1039:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1040:   }
1041:   VecRestoreArrayRead(coordinates, &coords);
1042:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1043:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1044:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1045:   PetscDrawClear(draw);

1047:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1048:   for (c = cStart; c < cEnd; ++c) {
1049:     PetscScalar *coords = NULL;
1050:     PetscInt     numCoords,coneSize;

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

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

1100: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1101: {
1102:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1103:   char           name[PETSC_MAX_PATH_LEN];

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

1151:     DMGetLabel(dm, name, &label);
1152:     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1153:     DMPlexCreateLabelField(dm, label, &val);
1154:     VecView(val, viewer);
1155:     VecDestroy(&val);
1156:   }
1157:   return(0);
1158: }

1160: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1161: {
1162:   PetscBool      ishdf5;

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

1187: PetscErrorCode DMDestroy_Plex(DM dm)
1188: {
1189:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1223: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1224: {
1225:   PetscSection           sectionGlobal;
1226:   PetscInt               bs = -1, mbs;
1227:   PetscInt               localSize;
1228:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1229:   PetscErrorCode         ierr;
1230:   MatType                mtype;
1231:   ISLocalToGlobalMapping ltog;

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

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

1264:       DMGetSection(dm, &section);
1265:       PetscSectionGetStorageSize(section, &size);
1266:       PetscMalloc1(size,&ltogidx);
1267:       DMPlexGetSubdomainSection(dm, &subSection);
1268:     } else {
1269:       DMGetLocalToGlobalMapping(dm,&ltog);
1270:     }
1271:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1272:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1273:       PetscInt bdof;

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

1314: /*@
1315:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1317:   Not collective

1319:   Input Parameter:
1320: . mesh - The DMPlex

1322:   Output Parameters:
1323: . subsection - The subdomain section

1325:   Level: developer

1327: .seealso:
1328: @*/
1329: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1330: {
1331:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1336:   if (!mesh->subdomainSection) {
1337:     PetscSection section;
1338:     PetscSF      sf;

1340:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1341:     DMGetSection(dm,&section);
1342:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1343:     PetscSFDestroy(&sf);
1344:   }
1345:   *subsection = mesh->subdomainSection;
1346:   return(0);
1347: }

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

1352:   Not collective

1354:   Input Parameter:
1355: . mesh - The DMPlex

1357:   Output Parameters:
1358: + pStart - The first mesh point
1359: - pEnd   - The upper bound for mesh points

1361:   Level: beginner

1363: .seealso: DMPlexCreate(), DMPlexSetChart()
1364: @*/
1365: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1366: {
1367:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1372:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1373:   return(0);
1374: }

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

1379:   Not collective

1381:   Input Parameters:
1382: + mesh - The DMPlex
1383: . pStart - The first mesh point
1384: - pEnd   - The upper bound for mesh points

1386:   Output Parameters:

1388:   Level: beginner

1390: .seealso: DMPlexCreate(), DMPlexGetChart()
1391: @*/
1392: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1393: {
1394:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1399:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1400:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1401:   return(0);
1402: }

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

1407:   Not collective

1409:   Input Parameters:
1410: + mesh - The DMPlex
1411: - p - The point, which must lie in the chart set with DMPlexSetChart()

1413:   Output Parameter:
1414: . size - The cone size for point p

1416:   Level: beginner

1418: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1419: @*/
1420: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1421: {
1422:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1428:   PetscSectionGetDof(mesh->coneSection, p, size);
1429:   return(0);
1430: }

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

1435:   Not collective

1437:   Input Parameters:
1438: + mesh - The DMPlex
1439: . p - The point, which must lie in the chart set with DMPlexSetChart()
1440: - size - The cone size for point p

1442:   Output Parameter:

1444:   Note:
1445:   This should be called after DMPlexSetChart().

1447:   Level: beginner

1449: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1450: @*/
1451: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1452: {
1453:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1460:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1461:   return(0);
1462: }

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

1467:   Not collective

1469:   Input Parameters:
1470: + mesh - The DMPlex
1471: . p - The point, which must lie in the chart set with DMPlexSetChart()
1472: - size - The additional cone size for point p

1474:   Output Parameter:

1476:   Note:
1477:   This should be called after DMPlexSetChart().

1479:   Level: beginner

1481: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1482: @*/
1483: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1484: {
1485:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1486:   PetscInt       csize;

1491:   PetscSectionAddDof(mesh->coneSection, p, size);
1492:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1494:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1495:   return(0);
1496: }

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

1501:   Not collective

1503:   Input Parameters:
1504: + dm - The DMPlex
1505: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1510:   Level: beginner

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

1516: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1517: @*/
1518: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1519: {
1520:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1521:   PetscInt       off;

1527:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1528:   *cone = &mesh->cones[off];
1529:   return(0);
1530: }

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

1535:   Not collective

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

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

1545:   Level: intermediate

1547: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1548: @*/
1549: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1550: {
1551:   PetscSection        cs, newcs;
1552:   PetscInt            *cones;
1553:   PetscInt            *newarr=NULL;
1554:   PetscInt            n;
1555:   PetscErrorCode      ierr;

1558:   DMPlexGetCones(dm, &cones);
1559:   DMPlexGetConeSection(dm, &cs);
1560:   PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1561:   if (pConesSection) *pConesSection = newcs;
1562:   if (pCones) {
1563:     PetscSectionGetStorageSize(newcs, &n);
1564:     ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1565:   }
1566:   return(0);
1567: }

1569: static PetscErrorCode DMPlexGetConeRecursive_Private(DM dm, PetscInt *n_inout, const PetscInt points[], PetscInt *offset_inout, PetscInt buf[])
1570: {
1571:   PetscInt p, n, cn, i;
1572:   const PetscInt *cone;

1576:   n = *n_inout;
1577:   *n_inout = 0;
1578:   for (i=0; i<n; i++) {
1579:     p = points[i];
1580:     DMPlexGetConeSize(dm, p, &cn);
1581:     if (!cn) {
1582:       cn = 1;
1583:       if (buf) {
1584:         buf[*offset_inout] = p;
1585:         ++(*offset_inout);
1586:       }
1587:     } else {
1588:       DMPlexGetCone(dm, p, &cone);
1589:       DMPlexGetConeRecursive_Private(dm, &cn, cone, offset_inout, buf);
1590:     }
1591:     *n_inout += cn;
1592:   }
1593:   return(0);
1594: }

1596: /*@C
1597:   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.

1599:   Not collective

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

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

1608:   Level: advanced

1610: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple()
1611: @*/
1612: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS p, IS *pCones)
1613: {
1614:   const PetscInt      *arr=NULL;
1615:   PetscInt            *cpoints=NULL;
1616:   PetscInt            n, cn;
1617:   PetscInt            zero;
1618:   PetscErrorCode      ierr;

1621:   ISGetLocalSize(p, &n);
1622:   ISGetIndices(p, &arr);
1623:   zero = 0;
1624:   /* first figure out the total number of returned points */
1625:   cn = n;
1626:   DMPlexGetConeRecursive_Private(dm, &cn, arr, &zero, NULL);
1627:   PetscMalloc1(cn, &cpoints);
1628:   /* now get recursive cones themselves */
1629:   DMPlexGetConeRecursive_Private(dm, &n, arr, &zero, cpoints);
1630:   ISCreateGeneral(PetscObjectComm((PetscObject)p), n, cpoints, PETSC_OWN_POINTER, pCones);
1631:   ISRestoreIndices(p, &arr);
1632:   return(0);
1633: }

1635: /*@
1636:   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

1638:   Not collective

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

1645:   Output Parameter:

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

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

1652:   Level: beginner

1654: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1655: @*/
1656: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1657: {
1658:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1659:   PetscInt       pStart, pEnd;
1660:   PetscInt       dof, off, c;

1665:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1666:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1668:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1669:   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);
1670:   for (c = 0; c < dof; ++c) {
1671:     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);
1672:     mesh->cones[off+c] = cone[c];
1673:   }
1674:   return(0);
1675: }

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

1680:   Not collective

1682:   Input Parameters:
1683: + mesh - The DMPlex
1684: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1692:   Level: beginner

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

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

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

1710: #if defined(PETSC_USE_DEBUG)
1711:   {
1712:     PetscInt dof;
1713:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1715:   }
1716: #endif
1717:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1719:   *coneOrientation = &mesh->coneOrientations[off];
1720:   return(0);
1721: }

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

1726:   Not collective

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

1736:   Output Parameter:

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

1741:   Level: beginner

1743: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1744: @*/
1745: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1746: {
1747:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1748:   PetscInt       pStart, pEnd;
1749:   PetscInt       dof, off, c;

1754:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1755:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1757:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1758:   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);
1759:   for (c = 0; c < dof; ++c) {
1760:     PetscInt cdof, o = coneOrientation[c];

1762:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1763:     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);
1764:     mesh->coneOrientations[off+c] = o;
1765:   }
1766:   return(0);
1767: }

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

1772:   Not collective

1774:   Input Parameters:
1775: + mesh - The DMPlex
1776: . p - The point, which must lie in the chart set with DMPlexSetChart()
1777: . conePos - The local index in the cone where the point should be put
1778: - conePoint - The mesh point to insert

1780:   Level: beginner

1782: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1783: @*/
1784: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1785: {
1786:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1787:   PetscInt       pStart, pEnd;
1788:   PetscInt       dof, off;

1793:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1794:   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);
1795:   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);
1796:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1797:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1798:   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);
1799:   mesh->cones[off+conePos] = conePoint;
1800:   return(0);
1801: }

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

1806:   Not collective

1808:   Input Parameters:
1809: + mesh - The DMPlex
1810: . p - The point, which must lie in the chart set with DMPlexSetChart()
1811: . conePos - The local index in the cone where the point should be put
1812: - coneOrientation - The point orientation to insert

1814:   Level: beginner

1816: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1817: @*/
1818: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1819: {
1820:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1821:   PetscInt       pStart, pEnd;
1822:   PetscInt       dof, off;

1827:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1828:   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);
1829:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1830:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1831:   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);
1832:   mesh->coneOrientations[off+conePos] = coneOrientation;
1833:   return(0);
1834: }

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

1839:   Not collective

1841:   Input Parameters:
1842: + mesh - The DMPlex
1843: - p - The point, which must lie in the chart set with DMPlexSetChart()

1845:   Output Parameter:
1846: . size - The support size for point p

1848:   Level: beginner

1850: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1851: @*/
1852: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1853: {
1854:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1860:   PetscSectionGetDof(mesh->supportSection, p, size);
1861:   return(0);
1862: }

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

1867:   Not collective

1869:   Input Parameters:
1870: + mesh - The DMPlex
1871: . p - The point, which must lie in the chart set with DMPlexSetChart()
1872: - size - The support size for point p

1874:   Output Parameter:

1876:   Note:
1877:   This should be called after DMPlexSetChart().

1879:   Level: beginner

1881: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1882: @*/
1883: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1884: {
1885:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1892:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1893:   return(0);
1894: }

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

1899:   Not collective

1901:   Input Parameters:
1902: + mesh - The DMPlex
1903: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1908:   Level: beginner

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

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

1916: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1917: @*/
1918: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1919: {
1920:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1921:   PetscInt       off;

1927:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1928:   *support = &mesh->supports[off];
1929:   return(0);
1930: }

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

1935:   Not collective

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

1942:   Output Parameter:

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

1947:   Level: beginner

1949: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1950: @*/
1951: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1952: {
1953:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1954:   PetscInt       pStart, pEnd;
1955:   PetscInt       dof, off, c;

1960:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1961:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1963:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1964:   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);
1965:   for (c = 0; c < dof; ++c) {
1966:     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);
1967:     mesh->supports[off+c] = support[c];
1968:   }
1969:   return(0);
1970: }

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

1975:   Not collective

1977:   Input Parameters:
1978: + mesh - The DMPlex
1979: . p - The point, which must lie in the chart set with DMPlexSetChart()
1980: . supportPos - The local index in the cone where the point should be put
1981: - supportPoint - The mesh point to insert

1983:   Level: beginner

1985: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1986: @*/
1987: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1988: {
1989:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1990:   PetscInt       pStart, pEnd;
1991:   PetscInt       dof, off;

1996:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1997:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1998:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1999:   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);
2000:   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);
2001:   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);
2002:   mesh->supports[off+supportPos] = supportPoint;
2003:   return(0);
2004: }

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

2009:   Not collective

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

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

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

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

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

2030:   Level: beginner

2032: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2033: @*/
2034: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2035: {
2036:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2037:   PetscInt       *closure, *fifo;
2038:   const PetscInt *tmp = NULL, *tmpO = NULL;
2039:   PetscInt        tmpSize, t;
2040:   PetscInt        depth       = 0, maxSize;
2041:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2042:   PetscErrorCode  ierr;

2046:   DMPlexGetDepth(dm, &depth);
2047:   /* This is only 1-level */
2048:   if (useCone) {
2049:     DMPlexGetConeSize(dm, p, &tmpSize);
2050:     DMPlexGetCone(dm, p, &tmp);
2051:     DMPlexGetConeOrientation(dm, p, &tmpO);
2052:   } else {
2053:     DMPlexGetSupportSize(dm, p, &tmpSize);
2054:     DMPlexGetSupport(dm, p, &tmp);
2055:   }
2056:   if (depth == 1) {
2057:     if (*points) {
2058:       closure = *points;
2059:     } else {
2060:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2061:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2062:     }
2063:     closure[0] = p; closure[1] = 0;
2064:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2065:       closure[closureSize]   = tmp[t];
2066:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2067:     }
2068:     if (numPoints) *numPoints = closureSize/2;
2069:     if (points)    *points    = closure;
2070:     return(0);
2071:   }
2072:   {
2073:     PetscInt c, coneSeries, s,supportSeries;

2075:     c = mesh->maxConeSize;
2076:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2077:     s = mesh->maxSupportSize;
2078:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2079:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2080:   }
2081:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2082:   if (*points) {
2083:     closure = *points;
2084:   } else {
2085:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2086:   }
2087:   closure[0] = p; closure[1] = 0;
2088:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2089:     const PetscInt cp = tmp[t];
2090:     const PetscInt co = tmpO ? tmpO[t] : 0;

2092:     closure[closureSize]   = cp;
2093:     closure[closureSize+1] = co;
2094:     fifo[fifoSize]         = cp;
2095:     fifo[fifoSize+1]       = co;
2096:   }
2097:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2098:   while (fifoSize - fifoStart) {
2099:     const PetscInt q   = fifo[fifoStart];
2100:     const PetscInt o   = fifo[fifoStart+1];
2101:     const PetscInt rev = o >= 0 ? 0 : 1;
2102:     const PetscInt off = rev ? -(o+1) : o;

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

2122:       if (rev) {
2123:         PetscInt childSize, coff;
2124:         DMPlexGetConeSize(dm, cp, &childSize);
2125:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2126:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2127:       }
2128:       /* Check for duplicate */
2129:       for (c = 0; c < closureSize; c += 2) {
2130:         if (closure[c] == cp) break;
2131:       }
2132:       if (c == closureSize) {
2133:         closure[closureSize]   = cp;
2134:         closure[closureSize+1] = co;
2135:         fifo[fifoSize]         = cp;
2136:         fifo[fifoSize+1]       = co;
2137:         closureSize           += 2;
2138:         fifoSize              += 2;
2139:       }
2140:     }
2141:     fifoStart += 2;
2142:   }
2143:   if (numPoints) *numPoints = closureSize/2;
2144:   if (points)    *points    = closure;
2145:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2146:   return(0);
2147: }

2149: /*@C
2150:   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

2152:   Not collective

2154:   Input Parameters:
2155: + mesh - The DMPlex
2156: . p - The point, which must lie in the chart set with DMPlexSetChart()
2157: . orientation - The orientation of the point
2158: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2159: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

2174:   Level: beginner

2176: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2177: @*/
2178: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2179: {
2180:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2181:   PetscInt       *closure, *fifo;
2182:   const PetscInt *tmp = NULL, *tmpO = NULL;
2183:   PetscInt        tmpSize, t;
2184:   PetscInt        depth       = 0, maxSize;
2185:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2186:   PetscErrorCode  ierr;

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

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

2238:     if (ornt < 0) {
2239:       PetscInt childSize, coff;
2240:       DMPlexGetConeSize(dm, cp, &childSize);
2241:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2242:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2243:     }
2244:     closure[closureSize]   = cp;
2245:     closure[closureSize+1] = co;
2246:     fifo[fifoSize]         = cp;
2247:     fifo[fifoSize+1]       = co;
2248:   }
2249:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2250:   while (fifoSize - fifoStart) {
2251:     const PetscInt q   = fifo[fifoStart];
2252:     const PetscInt o   = fifo[fifoStart+1];
2253:     const PetscInt rev = o >= 0 ? 0 : 1;
2254:     const PetscInt off = rev ? -(o+1) : o;

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

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

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

2304:   Not collective

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

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

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

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

2322:   Level: beginner

2324: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2325: @*/
2326: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2327: {

2334:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2335:   if (numPoints) *numPoints = 0;
2336:   return(0);
2337: }

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

2342:   Not collective

2344:   Input Parameter:
2345: . mesh - The DMPlex

2347:   Output Parameters:
2348: + maxConeSize - The maximum number of in-edges
2349: - maxSupportSize - The maximum number of out-edges

2351:   Level: beginner

2353: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2354: @*/
2355: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2356: {
2357:   DM_Plex *mesh = (DM_Plex*) dm->data;

2361:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2362:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2363:   return(0);
2364: }

2366: PetscErrorCode DMSetUp_Plex(DM dm)
2367: {
2368:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2369:   PetscInt       size;

2374:   PetscSectionSetUp(mesh->coneSection);
2375:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2376:   PetscMalloc1(size, &mesh->cones);
2377:   PetscCalloc1(size, &mesh->coneOrientations);
2378:   if (mesh->maxSupportSize) {
2379:     PetscSectionSetUp(mesh->supportSection);
2380:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2381:     PetscMalloc1(size, &mesh->supports);
2382:   }
2383:   return(0);
2384: }

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

2391:   if (subdm) {DMClone(dm, subdm);}
2392:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2393:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2394:   if (dm->useNatural && dm->sfMigration) {
2395:     PetscSF        sfMigrationInv,sfNatural;
2396:     PetscSection   section, sectionSeq;

2398:     (*subdm)->sfMigration = dm->sfMigration;
2399:     PetscObjectReference((PetscObject) dm->sfMigration);
2400:     DMGetSection((*subdm), &section);
2401:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2402:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2403:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2405:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2406:     (*subdm)->sfNatural = sfNatural;
2407:     PetscSectionDestroy(&sectionSeq);
2408:     PetscSFDestroy(&sfMigrationInv);
2409:   }
2410:   return(0);
2411: }

2413: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2414: {
2416:   PetscInt       i = 0;

2419:   DMClone(dms[0], superdm);
2420:   DMCreateSectionSuperDM(dms, len, is, superdm);
2421:   (*superdm)->useNatural = PETSC_FALSE;
2422:   for (i = 0; i < len; i++){
2423:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2424:       PetscSF        sfMigrationInv,sfNatural;
2425:       PetscSection   section, sectionSeq;

2427:       (*superdm)->sfMigration = dms[i]->sfMigration;
2428:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2429:       (*superdm)->useNatural = PETSC_TRUE;
2430:       DMGetSection((*superdm), &section);
2431:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2432:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2433:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2435:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2436:       (*superdm)->sfNatural = sfNatural;
2437:       PetscSectionDestroy(&sectionSeq);
2438:       PetscSFDestroy(&sfMigrationInv);
2439:       break;
2440:     }
2441:   }
2442:   return(0);
2443: }

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

2448:   Not collective

2450:   Input Parameter:
2451: . mesh - The DMPlex

2453:   Output Parameter:

2455:   Note:
2456:   This should be called after all calls to DMPlexSetCone()

2458:   Level: beginner

2460: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2461: @*/
2462: PetscErrorCode DMPlexSymmetrize(DM dm)
2463: {
2464:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2465:   PetscInt      *offsets;
2466:   PetscInt       supportSize;
2467:   PetscInt       pStart, pEnd, p;

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

2478:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2479:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2480:     for (c = off; c < off+dof; ++c) {
2481:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2482:     }
2483:   }
2484:   for (p = pStart; p < pEnd; ++p) {
2485:     PetscInt dof;

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

2489:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2490:   }
2491:   PetscSectionSetUp(mesh->supportSection);
2492:   /* Calculate supports */
2493:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2494:   PetscMalloc1(supportSize, &mesh->supports);
2495:   PetscCalloc1(pEnd - pStart, &offsets);
2496:   for (p = pStart; p < pEnd; ++p) {
2497:     PetscInt dof, off, c;

2499:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2500:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2501:     for (c = off; c < off+dof; ++c) {
2502:       const PetscInt q = mesh->cones[c];
2503:       PetscInt       offS;

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

2507:       mesh->supports[offS+offsets[q]] = p;
2508:       ++offsets[q];
2509:     }
2510:   }
2511:   PetscFree(offsets);
2512:   return(0);
2513: }

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

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

2523:   Collective on dm

2525:   Input Parameter:
2526: . mesh - The DMPlex

2528:   Output Parameter:

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

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

2538:   Level: beginner

2540: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2541: @*/
2542: PetscErrorCode DMPlexStratify(DM dm)
2543: {
2544:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2545:   DMLabel        label;
2546:   PetscInt       pStart, pEnd, p;
2547:   PetscInt       numRoots = 0, numLeaves = 0;
2548:   PetscInt       cMax, fMax, eMax, vMax;

2553:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2554:   /* Calculate depth */
2555:   DMPlexGetChart(dm, &pStart, &pEnd);
2556:   DMCreateLabel(dm, "depth");
2557:   DMPlexGetDepthLabel(dm, &label);
2558:   /* Initialize roots and count leaves */
2559:   for (p = pStart; p < pEnd; ++p) {
2560:     PetscInt coneSize, supportSize;

2562:     DMPlexGetConeSize(dm, p, &coneSize);
2563:     DMPlexGetSupportSize(dm, p, &supportSize);
2564:     if (!coneSize && supportSize) {
2565:       ++numRoots;
2566:       DMLabelSetValue(label, p, 0);
2567:     } else if (!supportSize && coneSize) {
2568:       ++numLeaves;
2569:     } else if (!supportSize && !coneSize) {
2570:       /* Isolated points */
2571:       DMLabelSetValue(label, p, 0);
2572:     }
2573:   }
2574:   if (numRoots + numLeaves == (pEnd - pStart)) {
2575:     for (p = pStart; p < pEnd; ++p) {
2576:       PetscInt coneSize, supportSize;

2578:       DMPlexGetConeSize(dm, p, &coneSize);
2579:       DMPlexGetSupportSize(dm, p, &supportSize);
2580:       if (!supportSize && coneSize) {
2581:         DMLabelSetValue(label, p, 1);
2582:       }
2583:     }
2584:   } else {
2585:     IS       pointIS;
2586:     PetscInt numPoints = 0, level = 0;

2588:     DMLabelGetStratumIS(label, level, &pointIS);
2589:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2590:     while (numPoints) {
2591:       const PetscInt *points;
2592:       const PetscInt  newLevel = level+1;

2594:       ISGetIndices(pointIS, &points);
2595:       for (p = 0; p < numPoints; ++p) {
2596:         const PetscInt  point = points[p];
2597:         const PetscInt *support;
2598:         PetscInt        supportSize, s;

2600:         DMPlexGetSupportSize(dm, point, &supportSize);
2601:         DMPlexGetSupport(dm, point, &support);
2602:         for (s = 0; s < supportSize; ++s) {
2603:           DMLabelSetValue(label, support[s], newLevel);
2604:         }
2605:       }
2606:       ISRestoreIndices(pointIS, &points);
2607:       ++level;
2608:       ISDestroy(&pointIS);
2609:       DMLabelGetStratumIS(label, level, &pointIS);
2610:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2611:       else         {numPoints = 0;}
2612:     }
2613:     ISDestroy(&pointIS);
2614:   }
2615:   { /* just in case there is an empty process */
2616:     PetscInt numValues, maxValues = 0, v;

2618:     DMLabelGetNumValues(label,&numValues);
2619:     for (v = 0; v < numValues; v++) {
2620:       IS pointIS;

2622:       DMLabelGetStratumIS(label, v, &pointIS);
2623:       if (pointIS) {
2624:         PetscInt  min, max, numPoints;
2625:         PetscInt  start;
2626:         PetscBool contig;

2628:         ISGetLocalSize(pointIS, &numPoints);
2629:         ISGetMinMax(pointIS, &min, &max);
2630:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2631:         if (start == 0 && contig) {
2632:           ISDestroy(&pointIS);
2633:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2634:           DMLabelSetStratumIS(label, v, pointIS);
2635:         }
2636:       }
2637:       ISDestroy(&pointIS);
2638:     }
2639:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2640:     for (v = numValues; v < maxValues; v++) {
2641:       DMLabelAddStratum(label,v);
2642:     }
2643:   }
2644:   PetscObjectStateGet((PetscObject) label, &mesh->depthState);

2646:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2647:   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2648:     DMLabel  dimLabel;
2649:     PetscInt dim;

2651:     DMGetDimension(dm, &dim);
2652:     DMGetLabel(dm, "dim", &dimLabel);
2653:     if (!dimLabel) {
2654:       DMCreateLabel(dm, "dim");
2655:       DMGetLabel(dm, "dim", &dimLabel);
2656:     }
2657:     if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2658:     if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2659:     if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2660:     if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2661:   }
2662:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2663:   return(0);
2664: }

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

2669:   Not Collective

2671:   Input Parameters:
2672: + dm - The DMPlex object
2673: . numPoints - The number of input points for the join
2674: - points - The input points

2676:   Output Parameters:
2677: + numCoveredPoints - The number of points in the join
2678: - coveredPoints - The points in the join

2680:   Level: intermediate

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

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

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

2690: .keywords: mesh
2691: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2692: @*/
2693: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2694: {
2695:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2696:   PetscInt      *join[2];
2697:   PetscInt       joinSize, i = 0;
2698:   PetscInt       dof, off, p, c, m;

2706:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2707:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2708:   /* Copy in support of first point */
2709:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2710:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2711:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2712:     join[i][joinSize] = mesh->supports[off+joinSize];
2713:   }
2714:   /* Check each successive support */
2715:   for (p = 1; p < numPoints; ++p) {
2716:     PetscInt newJoinSize = 0;

2718:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2719:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2720:     for (c = 0; c < dof; ++c) {
2721:       const PetscInt point = mesh->supports[off+c];

2723:       for (m = 0; m < joinSize; ++m) {
2724:         if (point == join[i][m]) {
2725:           join[1-i][newJoinSize++] = point;
2726:           break;
2727:         }
2728:       }
2729:     }
2730:     joinSize = newJoinSize;
2731:     i        = 1-i;
2732:   }
2733:   *numCoveredPoints = joinSize;
2734:   *coveredPoints    = join[i];
2735:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2736:   return(0);
2737: }

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

2742:   Not Collective

2744:   Input Parameters:
2745: + dm - The DMPlex object
2746: . numPoints - The number of input points for the join
2747: - points - The input points

2749:   Output Parameters:
2750: + numCoveredPoints - The number of points in the join
2751: - coveredPoints - The points in the join

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

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

2759:   Level: intermediate

2761: .keywords: mesh
2762: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2763: @*/
2764: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2765: {

2773:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2774:   if (numCoveredPoints) *numCoveredPoints = 0;
2775:   return(0);
2776: }

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

2781:   Not Collective

2783:   Input Parameters:
2784: + dm - The DMPlex object
2785: . numPoints - The number of input points for the join
2786: - points - The input points

2788:   Output Parameters:
2789: + numCoveredPoints - The number of points in the join
2790: - coveredPoints - The points in the join

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

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

2798:   Level: intermediate

2800: .keywords: mesh
2801: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2802: @*/
2803: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2804: {
2805:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2806:   PetscInt      *offsets, **closures;
2807:   PetscInt      *join[2];
2808:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2809:   PetscInt       p, d, c, m, ms;


2818:   DMPlexGetDepth(dm, &depth);
2819:   PetscCalloc1(numPoints, &closures);
2820:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2821:   ms      = mesh->maxSupportSize;
2822:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2823:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2824:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

2826:   for (p = 0; p < numPoints; ++p) {
2827:     PetscInt closureSize;

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

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

2835:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2836:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2837:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2838:           offsets[p*(depth+2)+d+1] = i;
2839:           break;
2840:         }
2841:       }
2842:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2843:     }
2844:     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);
2845:   }
2846:   for (d = 0; d < depth+1; ++d) {
2847:     PetscInt dof;

2849:     /* Copy in support of first point */
2850:     dof = offsets[d+1] - offsets[d];
2851:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2852:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2853:     }
2854:     /* Check each successive cone */
2855:     for (p = 1; p < numPoints && joinSize; ++p) {
2856:       PetscInt newJoinSize = 0;

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

2862:         for (m = 0; m < joinSize; ++m) {
2863:           if (point == join[i][m]) {
2864:             join[1-i][newJoinSize++] = point;
2865:             break;
2866:           }
2867:         }
2868:       }
2869:       joinSize = newJoinSize;
2870:       i        = 1-i;
2871:     }
2872:     if (joinSize) break;
2873:   }
2874:   *numCoveredPoints = joinSize;
2875:   *coveredPoints    = join[i];
2876:   for (p = 0; p < numPoints; ++p) {
2877:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2878:   }
2879:   PetscFree(closures);
2880:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2881:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2882:   return(0);
2883: }

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

2888:   Not Collective

2890:   Input Parameters:
2891: + dm - The DMPlex object
2892: . numPoints - The number of input points for the meet
2893: - points - The input points

2895:   Output Parameters:
2896: + numCoveredPoints - The number of points in the meet
2897: - coveredPoints - The points in the meet

2899:   Level: intermediate

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

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

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

2909: .keywords: mesh
2910: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2911: @*/
2912: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2913: {
2914:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2915:   PetscInt      *meet[2];
2916:   PetscInt       meetSize, i = 0;
2917:   PetscInt       dof, off, p, c, m;

2925:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2926:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2927:   /* Copy in cone of first point */
2928:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2929:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2930:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2931:     meet[i][meetSize] = mesh->cones[off+meetSize];
2932:   }
2933:   /* Check each successive cone */
2934:   for (p = 1; p < numPoints; ++p) {
2935:     PetscInt newMeetSize = 0;

2937:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2938:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2939:     for (c = 0; c < dof; ++c) {
2940:       const PetscInt point = mesh->cones[off+c];

2942:       for (m = 0; m < meetSize; ++m) {
2943:         if (point == meet[i][m]) {
2944:           meet[1-i][newMeetSize++] = point;
2945:           break;
2946:         }
2947:       }
2948:     }
2949:     meetSize = newMeetSize;
2950:     i        = 1-i;
2951:   }
2952:   *numCoveringPoints = meetSize;
2953:   *coveringPoints    = meet[i];
2954:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2955:   return(0);
2956: }

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

2961:   Not Collective

2963:   Input Parameters:
2964: + dm - The DMPlex object
2965: . numPoints - The number of input points for the meet
2966: - points - The input points

2968:   Output Parameters:
2969: + numCoveredPoints - The number of points in the meet
2970: - coveredPoints - The points in the meet

2972:   Level: intermediate

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

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

2980: .keywords: mesh
2981: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2982: @*/
2983: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2984: {

2992:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2993:   if (numCoveredPoints) *numCoveredPoints = 0;
2994:   return(0);
2995: }

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

3000:   Not Collective

3002:   Input Parameters:
3003: + dm - The DMPlex object
3004: . numPoints - The number of input points for the meet
3005: - points - The input points

3007:   Output Parameters:
3008: + numCoveredPoints - The number of points in the meet
3009: - coveredPoints - The points in the meet

3011:   Level: intermediate

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

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

3019: .keywords: mesh
3020: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3021: @*/
3022: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3023: {
3024:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3025:   PetscInt      *offsets, **closures;
3026:   PetscInt      *meet[2];
3027:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
3028:   PetscInt       p, h, c, m, mc;


3037:   DMPlexGetDepth(dm, &height);
3038:   PetscMalloc1(numPoints, &closures);
3039:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3040:   mc      = mesh->maxConeSize;
3041:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3042:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3043:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

3045:   for (p = 0; p < numPoints; ++p) {
3046:     PetscInt closureSize;

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

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

3054:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3055:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3056:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3057:           offsets[p*(height+2)+h+1] = i;
3058:           break;
3059:         }
3060:       }
3061:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3062:     }
3063:     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);
3064:   }
3065:   for (h = 0; h < height+1; ++h) {
3066:     PetscInt dof;

3068:     /* Copy in cone of first point */
3069:     dof = offsets[h+1] - offsets[h];
3070:     for (meetSize = 0; meetSize < dof; ++meetSize) {
3071:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3072:     }
3073:     /* Check each successive cone */
3074:     for (p = 1; p < numPoints && meetSize; ++p) {
3075:       PetscInt newMeetSize = 0;

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

3081:         for (m = 0; m < meetSize; ++m) {
3082:           if (point == meet[i][m]) {
3083:             meet[1-i][newMeetSize++] = point;
3084:             break;
3085:           }
3086:         }
3087:       }
3088:       meetSize = newMeetSize;
3089:       i        = 1-i;
3090:     }
3091:     if (meetSize) break;
3092:   }
3093:   *numCoveredPoints = meetSize;
3094:   *coveredPoints    = meet[i];
3095:   for (p = 0; p < numPoints; ++p) {
3096:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3097:   }
3098:   PetscFree(closures);
3099:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3100:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3101:   return(0);
3102: }

3104: /*@C
3105:   DMPlexEqual - Determine if two DMs have the same topology

3107:   Not Collective

3109:   Input Parameters:
3110: + dmA - A DMPlex object
3111: - dmB - A DMPlex object

3113:   Output Parameters:
3114: . equal - PETSC_TRUE if the topologies are identical

3116:   Level: intermediate

3118:   Notes:
3119:   We are not solving graph isomorphism, so we do not permutation.

3121: .keywords: mesh
3122: .seealso: DMPlexGetCone()
3123: @*/
3124: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3125: {
3126:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


3134:   *equal = PETSC_FALSE;
3135:   DMPlexGetDepth(dmA, &depth);
3136:   DMPlexGetDepth(dmB, &depthB);
3137:   if (depth != depthB) return(0);
3138:   DMPlexGetChart(dmA, &pStart,  &pEnd);
3139:   DMPlexGetChart(dmB, &pStartB, &pEndB);
3140:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3141:   for (p = pStart; p < pEnd; ++p) {
3142:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3143:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

3145:     DMPlexGetConeSize(dmA, p, &coneSize);
3146:     DMPlexGetCone(dmA, p, &cone);
3147:     DMPlexGetConeOrientation(dmA, p, &ornt);
3148:     DMPlexGetConeSize(dmB, p, &coneSizeB);
3149:     DMPlexGetCone(dmB, p, &coneB);
3150:     DMPlexGetConeOrientation(dmB, p, &orntB);
3151:     if (coneSize != coneSizeB) return(0);
3152:     for (c = 0; c < coneSize; ++c) {
3153:       if (cone[c] != coneB[c]) return(0);
3154:       if (ornt[c] != orntB[c]) return(0);
3155:     }
3156:     DMPlexGetSupportSize(dmA, p, &supportSize);
3157:     DMPlexGetSupport(dmA, p, &support);
3158:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
3159:     DMPlexGetSupport(dmB, p, &supportB);
3160:     if (supportSize != supportSizeB) return(0);
3161:     for (s = 0; s < supportSize; ++s) {
3162:       if (support[s] != supportB[s]) return(0);
3163:     }
3164:   }
3165:   *equal = PETSC_TRUE;
3166:   return(0);
3167: }

3169: /*@C
3170:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

3172:   Not Collective

3174:   Input Parameters:
3175: + dm         - The DMPlex
3176: . cellDim    - The cell dimension
3177: - numCorners - The number of vertices on a cell

3179:   Output Parameters:
3180: . numFaceVertices - The number of vertices on a face

3182:   Level: developer

3184:   Notes:
3185:   Of course this can only work for a restricted set of symmetric shapes

3187: .seealso: DMPlexGetCone()
3188: @*/
3189: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3190: {
3191:   MPI_Comm       comm;

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

3258: /*@
3259:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3261:   Not Collective

3263:   Input Parameter:
3264: . dm    - The DMPlex object

3266:   Output Parameter:
3267: . depthLabel - The DMLabel recording point depth

3269:   Level: developer

3271: .keywords: mesh, points
3272: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3273: @*/
3274: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3275: {

3281:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3282:   *depthLabel = dm->depthLabel;
3283:   return(0);
3284: }

3286: /*@
3287:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3289:   Not Collective

3291:   Input Parameter:
3292: . dm    - The DMPlex object

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

3297:   Level: developer

3299: .keywords: mesh, points
3300: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3301: @*/
3302: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3303: {
3304:   DMLabel        label;
3305:   PetscInt       d = 0;

3311:   DMPlexGetDepthLabel(dm, &label);
3312:   if (label) {DMLabelGetNumValues(label, &d);}
3313:   *depth = d-1;
3314:   return(0);
3315: }

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

3320:   Not Collective

3322:   Input Parameters:
3323: + dm           - The DMPlex object
3324: - stratumValue - The requested depth

3326:   Output Parameters:
3327: + start - The first point at this depth
3328: - end   - One beyond the last point at this depth

3330:   Level: developer

3332: .keywords: mesh, points
3333: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3334: @*/
3335: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3336: {
3337:   DMLabel        label;
3338:   PetscInt       pStart, pEnd;

3345:   DMPlexGetChart(dm, &pStart, &pEnd);
3346:   if (pStart == pEnd) return(0);
3347:   if (stratumValue < 0) {
3348:     if (start) *start = pStart;
3349:     if (end)   *end   = pEnd;
3350:     return(0);
3351:   }
3352:   DMPlexGetDepthLabel(dm, &label);
3353:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3354:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3355:   return(0);
3356: }

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

3361:   Not Collective

3363:   Input Parameters:
3364: + dm           - The DMPlex object
3365: - stratumValue - The requested height

3367:   Output Parameters:
3368: + start - The first point at this height
3369: - end   - One beyond the last point at this height

3371:   Level: developer

3373: .keywords: mesh, points
3374: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3375: @*/
3376: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3377: {
3378:   DMLabel        label;
3379:   PetscInt       depth, pStart, pEnd;

3386:   DMPlexGetChart(dm, &pStart, &pEnd);
3387:   if (pStart == pEnd) return(0);
3388:   if (stratumValue < 0) {
3389:     if (start) *start = pStart;
3390:     if (end)   *end   = pEnd;
3391:     return(0);
3392:   }
3393:   DMPlexGetDepthLabel(dm, &label);
3394:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3395:   DMLabelGetNumValues(label, &depth);
3396:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3397:   return(0);
3398: }

3400: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3401: {
3402:   PetscSection   section, s;
3403:   Mat            m;
3404:   PetscInt       maxHeight;

3408:   DMClone(dm, cdm);
3409:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3410:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3411:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3412:   DMSetSection(*cdm, section);
3413:   PetscSectionDestroy(&section);
3414:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3415:   MatCreate(PETSC_COMM_SELF, &m);
3416:   DMSetDefaultConstraints(*cdm, s, m);
3417:   PetscSectionDestroy(&s);
3418:   MatDestroy(&m);

3420:   DMSetNumFields(*cdm, 1);
3421:   DMCreateDS(*cdm);
3422:   return(0);
3423: }

3425: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3426: {
3427:   Vec            coordsLocal;
3428:   DM             coordsDM;

3432:   *field = NULL;
3433:   DMGetCoordinatesLocal(dm,&coordsLocal);
3434:   DMGetCoordinateDM(dm,&coordsDM);
3435:   if (coordsLocal && coordsDM) {
3436:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3437:   }
3438:   return(0);
3439: }

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

3444:   Not Collective

3446:   Input Parameters:
3447: . dm        - The DMPlex object

3449:   Output Parameter:
3450: . section - The PetscSection object

3452:   Level: developer

3454: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3455: @*/
3456: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3457: {
3458:   DM_Plex *mesh = (DM_Plex*) dm->data;

3462:   if (section) *section = mesh->coneSection;
3463:   return(0);
3464: }

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

3469:   Not Collective

3471:   Input Parameters:
3472: . dm        - The DMPlex object

3474:   Output Parameter:
3475: . section - The PetscSection object

3477:   Level: developer

3479: .seealso: DMPlexGetConeSection()
3480: @*/
3481: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3482: {
3483:   DM_Plex *mesh = (DM_Plex*) dm->data;

3487:   if (section) *section = mesh->supportSection;
3488:   return(0);
3489: }

3491: /*@C
3492:   DMPlexGetCones - Return cone data

3494:   Not Collective

3496:   Input Parameters:
3497: . dm        - The DMPlex object

3499:   Output Parameter:
3500: . cones - The cone for each point

3502:   Level: developer

3504: .seealso: DMPlexGetConeSection()
3505: @*/
3506: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3507: {
3508:   DM_Plex *mesh = (DM_Plex*) dm->data;

3512:   if (cones) *cones = mesh->cones;
3513:   return(0);
3514: }

3516: /*@C
3517:   DMPlexGetConeOrientations - Return cone orientation data

3519:   Not Collective

3521:   Input Parameters:
3522: . dm        - The DMPlex object

3524:   Output Parameter:
3525: . coneOrientations - The cone orientation for each point

3527:   Level: developer

3529: .seealso: DMPlexGetConeSection()
3530: @*/
3531: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3532: {
3533:   DM_Plex *mesh = (DM_Plex*) dm->data;

3537:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3538:   return(0);
3539: }

3541: /******************************** FEM Support **********************************/

3543: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3544: {
3545:   DMLabel        label;
3546:   PetscInt      *perm;
3547:   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3551:   if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3552:   DMGetDimension(dm, &dim);
3553:   DMPlexGetDepthLabel(dm, &label);
3554:   DMLabelGetValue(label, point, &depth);
3555:   if (depth == 1) {eStart = point;}
3556:   else if  (depth == dim) {
3557:     const PetscInt *cone;

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

3587:          v_lb, {e_b}, v_rb,
3588:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3589:          v_lt, reverse {e_t}, v_rt
3590:       */
3591:       {
3592:         const PetscInt of   = 0;
3593:         const PetscInt oeb  = of   + PetscSqr(k-1);
3594:         const PetscInt oer  = oeb  + (k-1);
3595:         const PetscInt oet  = oer  + (k-1);
3596:         const PetscInt oel  = oet  + (k-1);
3597:         const PetscInt ovlb = oel  + (k-1);
3598:         const PetscInt ovrb = ovlb + 1;
3599:         const PetscInt ovrt = ovrb + 1;
3600:         const PetscInt ovlt = ovrt + 1;
3601:         PetscInt       o;

3603:         /* bottom */
3604:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3605:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3606:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3607:         /* middle */
3608:         for (i = 0; i < k-1; ++i) {
3609:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3610:           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;
3611:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3612:         }
3613:         /* top */
3614:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3615:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3616:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3617:         foffset = offset;
3618:       }
3619:       break;
3620:     case 3:
3621:       /* The original hex closure is

3623:          {c,
3624:           f_b, f_t, f_f, f_b, f_r, f_l,
3625:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3626:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3627:       */
3628:       PetscSectionGetFieldDof(section, eStart, f, &k);
3629:       PetscSectionGetFieldComponents(section, f, &Nc);
3630:       k = k/Nc + 1;
3631:       /* The SEM order is
3632:          Bottom Slice
3633:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3634:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3635:          v_blb, {e_bb}, v_brb,

3637:          Middle Slice (j)
3638:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3639:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3640:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

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

3677:         /* Bottom Slice */
3678:         /*   bottom */
3679:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3680:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3681:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3682:         /*   middle */
3683:         for (i = 0; i < k-1; ++i) {
3684:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3685:           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;}
3686:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3687:         }
3688:         /*   top */
3689:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3690:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3691:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3693:         /* Middle Slice */
3694:         for (j = 0; j < k-1; ++j) {
3695:           /*   bottom */
3696:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3697:           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;
3698:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3699:           /*   middle */
3700:           for (i = 0; i < k-1; ++i) {
3701:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3702:             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;
3703:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3704:           }
3705:           /*   top */
3706:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3707:           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;
3708:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3709:         }

3711:         /* Top Slice */
3712:         /*   bottom */
3713:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3714:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3715:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3716:         /*   middle */
3717:         for (i = 0; i < k-1; ++i) {
3718:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3719:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3720:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3721:         }
3722:         /*   top */
3723:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3724:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3725:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3727:         foffset = offset;
3728:       }
3729:       break;
3730:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3731:     }
3732:   }
3733:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3734:   /* Check permutation */
3735:   {
3736:     PetscInt *check;

3738:     PetscMalloc1(size, &check);
3739:     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]);}
3740:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3741:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3742:     PetscFree(check);
3743:   }
3744:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3745:   return(0);
3746: }

3748: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3749: {
3750:   PetscDS        prob;
3751:   PetscInt       depth, Nf, h;
3752:   DMLabel        label;

3756:   DMGetDS(dm, &prob);
3757:   Nf      = prob->Nf;
3758:   label   = dm->depthLabel;
3759:   *dspace = NULL;
3760:   if (field < Nf) {
3761:     PetscObject disc = prob->disc[field];

3763:     if (disc->classid == PETSCFE_CLASSID) {
3764:       PetscDualSpace dsp;

3766:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3767:       DMLabelGetNumValues(label,&depth);
3768:       DMLabelGetValue(label,point,&h);
3769:       h    = depth - 1 - h;
3770:       if (h) {
3771:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3772:       } else {
3773:         *dspace = dsp;
3774:       }
3775:     }
3776:   }
3777:   return(0);
3778: }


3781: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3782: {
3783:   PetscScalar    *array, *vArray;
3784:   const PetscInt *cone, *coneO;
3785:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3786:   PetscErrorCode  ierr;

3789:   PetscSectionGetChart(section, &pStart, &pEnd);
3790:   DMPlexGetConeSize(dm, point, &numPoints);
3791:   DMPlexGetCone(dm, point, &cone);
3792:   DMPlexGetConeOrientation(dm, point, &coneO);
3793:   if (!values || !*values) {
3794:     if ((point >= pStart) && (point < pEnd)) {
3795:       PetscInt dof;

3797:       PetscSectionGetDof(section, point, &dof);
3798:       size += dof;
3799:     }
3800:     for (p = 0; p < numPoints; ++p) {
3801:       const PetscInt cp = cone[p];
3802:       PetscInt       dof;

3804:       if ((cp < pStart) || (cp >= pEnd)) continue;
3805:       PetscSectionGetDof(section, cp, &dof);
3806:       size += dof;
3807:     }
3808:     if (!values) {
3809:       if (csize) *csize = size;
3810:       return(0);
3811:     }
3812:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
3813:   } else {
3814:     array = *values;
3815:   }
3816:   size = 0;
3817:   VecGetArray(v, &vArray);
3818:   if ((point >= pStart) && (point < pEnd)) {
3819:     PetscInt     dof, off, d;
3820:     PetscScalar *varr;

3822:     PetscSectionGetDof(section, point, &dof);
3823:     PetscSectionGetOffset(section, point, &off);
3824:     varr = &vArray[off];
3825:     for (d = 0; d < dof; ++d, ++offset) {
3826:       array[offset] = varr[d];
3827:     }
3828:     size += dof;
3829:   }
3830:   for (p = 0; p < numPoints; ++p) {
3831:     const PetscInt cp = cone[p];
3832:     PetscInt       o  = coneO[p];
3833:     PetscInt       dof, off, d;
3834:     PetscScalar   *varr;

3836:     if ((cp < pStart) || (cp >= pEnd)) continue;
3837:     PetscSectionGetDof(section, cp, &dof);
3838:     PetscSectionGetOffset(section, cp, &off);
3839:     varr = &vArray[off];
3840:     if (o >= 0) {
3841:       for (d = 0; d < dof; ++d, ++offset) {
3842:         array[offset] = varr[d];
3843:       }
3844:     } else {
3845:       for (d = dof-1; d >= 0; --d, ++offset) {
3846:         array[offset] = varr[d];
3847:       }
3848:     }
3849:     size += dof;
3850:   }
3851:   VecRestoreArray(v, &vArray);
3852:   if (!*values) {
3853:     if (csize) *csize = size;
3854:     *values = array;
3855:   } else {
3856:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3857:     *csize = size;
3858:   }
3859:   return(0);
3860: }

3862: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3863: {
3864:   const PetscInt *cla;
3865:   PetscInt       np, *pts = NULL;

3869:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3870:   if (!*clPoints) {
3871:     PetscInt pStart, pEnd, p, q;

3873:     PetscSectionGetChart(section, &pStart, &pEnd);
3874:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3875:     /* Compress out points not in the section */
3876:     for (p = 0, q = 0; p < np; p++) {
3877:       PetscInt r = pts[2*p];
3878:       if ((r >= pStart) && (r < pEnd)) {
3879:         pts[q*2]   = r;
3880:         pts[q*2+1] = pts[2*p+1];
3881:         ++q;
3882:       }
3883:     }
3884:     np = q;
3885:     cla = NULL;
3886:   } else {
3887:     PetscInt dof, off;

3889:     PetscSectionGetDof(*clSec, point, &dof);
3890:     PetscSectionGetOffset(*clSec, point, &off);
3891:     ISGetIndices(*clPoints, &cla);
3892:     np   = dof/2;
3893:     pts  = (PetscInt *) &cla[off];
3894:   }
3895:   *numPoints = np;
3896:   *points    = pts;
3897:   *clp       = cla;

3899:   return(0);
3900: }

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

3907:   if (!*clPoints) {
3908:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3909:   } else {
3910:     ISRestoreIndices(*clPoints, clp);
3911:   }
3912:   *numPoints = 0;
3913:   *points    = NULL;
3914:   *clSec     = NULL;
3915:   *clPoints  = NULL;
3916:   *clp       = NULL;
3917:   return(0);
3918: }

3920: 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[])
3921: {
3922:   PetscInt          offset = 0, p;
3923:   const PetscInt    **perms = NULL;
3924:   const PetscScalar **flips = NULL;
3925:   PetscErrorCode    ierr;

3928:   *size = 0;
3929:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3930:   for (p = 0; p < numPoints; p++) {
3931:     const PetscInt    point = points[2*p];
3932:     const PetscInt    *perm = perms ? perms[p] : NULL;
3933:     const PetscScalar *flip = flips ? flips[p] : NULL;
3934:     PetscInt          dof, off, d;
3935:     const PetscScalar *varr;

3937:     PetscSectionGetDof(section, point, &dof);
3938:     PetscSectionGetOffset(section, point, &off);
3939:     varr = &vArray[off];
3940:     if (clperm) {
3941:       if (perm) {
3942:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3943:       } else {
3944:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3945:       }
3946:       if (flip) {
3947:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3948:       }
3949:     } else {
3950:       if (perm) {
3951:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3952:       } else {
3953:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3954:       }
3955:       if (flip) {
3956:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3957:       }
3958:     }
3959:     offset += dof;
3960:   }
3961:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3962:   *size = offset;
3963:   return(0);
3964: }

3966: 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[])
3967: {
3968:   PetscInt          offset = 0, f;
3969:   PetscErrorCode    ierr;

3972:   *size = 0;
3973:   for (f = 0; f < numFields; ++f) {
3974:     PetscInt          p;
3975:     const PetscInt    **perms = NULL;
3976:     const PetscScalar **flips = NULL;

3978:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3979:     for (p = 0; p < numPoints; p++) {
3980:       const PetscInt    point = points[2*p];
3981:       PetscInt          fdof, foff, b;
3982:       const PetscScalar *varr;
3983:       const PetscInt    *perm = perms ? perms[p] : NULL;
3984:       const PetscScalar *flip = flips ? flips[p] : NULL;

3986:       PetscSectionGetFieldDof(section, point, f, &fdof);
3987:       PetscSectionGetFieldOffset(section, point, f, &foff);
3988:       varr = &vArray[foff];
3989:       if (clperm) {
3990:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
3991:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
3992:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
3993:       } else {
3994:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
3995:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
3996:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
3997:       }
3998:       offset += fdof;
3999:     }
4000:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4001:   }
4002:   *size = offset;
4003:   return(0);
4004: }

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

4009:   Not collective

4011:   Input Parameters:
4012: + dm - The DM
4013: . section - The section describing the layout in v, or NULL to use the default section
4014: . v - The local vector
4015: . point - The point in the DM
4016: . csize - The size of the input values array, or NULL
4017: - values - An array to use for the values, or NULL to have it allocated automatically

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

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

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

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

4054:   Level: intermediate

4056: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4057: @*/
4058: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4059: {
4060:   PetscSection       clSection;
4061:   IS                 clPoints;
4062:   PetscScalar       *array;
4063:   const PetscScalar *vArray;
4064:   PetscInt          *points = NULL;
4065:   const PetscInt    *clp, *perm;
4066:   PetscInt           depth, numFields, numPoints, size;
4067:   PetscErrorCode     ierr;

4071:   if (!section) {DMGetSection(dm, &section);}
4074:   DMPlexGetDepth(dm, &depth);
4075:   PetscSectionGetNumFields(section, &numFields);
4076:   if (depth == 1 && numFields < 2) {
4077:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4078:     return(0);
4079:   }
4080:   /* Get points */
4081:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4082:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4083:   /* Get array */
4084:   if (!values || !*values) {
4085:     PetscInt asize = 0, dof, p;

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

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

4121:   Not collective

4123:   Input Parameters:
4124: + dm - The DM
4125: . section - The section describing the layout in v, or NULL to use the default section
4126: . v - The local vector
4127: . point - The point in the DM
4128: . csize - The number of values in the closure, or NULL
4129: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

4139:   Level: intermediate

4141: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4142: @*/
4143: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4144: {
4145:   PetscInt       size = 0;

4149:   /* Should work without recalculating size */
4150:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4151:   *values = NULL;
4152:   return(0);
4153: }

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

4158: 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[])
4159: {
4160:   PetscInt        cdof;   /* The number of constraints on this point */
4161:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4162:   PetscScalar    *a;
4163:   PetscInt        off, cind = 0, k;
4164:   PetscErrorCode  ierr;

4167:   PetscSectionGetConstraintDof(section, point, &cdof);
4168:   PetscSectionGetOffset(section, point, &off);
4169:   a    = &array[off];
4170:   if (!cdof || setBC) {
4171:     if (clperm) {
4172:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4173:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4174:     } else {
4175:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4176:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4177:     }
4178:   } else {
4179:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4180:     if (clperm) {
4181:       if (perm) {for (k = 0; k < dof; ++k) {
4182:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4183:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4184:         }
4185:       } else {
4186:         for (k = 0; k < dof; ++k) {
4187:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4188:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4189:         }
4190:       }
4191:     } else {
4192:       if (perm) {
4193:         for (k = 0; k < dof; ++k) {
4194:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4195:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4196:         }
4197:       } else {
4198:         for (k = 0; k < dof; ++k) {
4199:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4200:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4201:         }
4202:       }
4203:     }
4204:   }
4205:   return(0);
4206: }

4208: 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[])
4209: {
4210:   PetscInt        cdof;   /* The number of constraints on this point */
4211:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4212:   PetscScalar    *a;
4213:   PetscInt        off, cind = 0, k;
4214:   PetscErrorCode  ierr;

4217:   PetscSectionGetConstraintDof(section, point, &cdof);
4218:   PetscSectionGetOffset(section, point, &off);
4219:   a    = &array[off];
4220:   if (cdof) {
4221:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4222:     if (clperm) {
4223:       if (perm) {
4224:         for (k = 0; k < dof; ++k) {
4225:           if ((cind < cdof) && (k == cdofs[cind])) {
4226:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4227:             cind++;
4228:           }
4229:         }
4230:       } else {
4231:         for (k = 0; k < dof; ++k) {
4232:           if ((cind < cdof) && (k == cdofs[cind])) {
4233:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4234:             cind++;
4235:           }
4236:         }
4237:       }
4238:     } else {
4239:       if (perm) {
4240:         for (k = 0; k < dof; ++k) {
4241:           if ((cind < cdof) && (k == cdofs[cind])) {
4242:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4243:             cind++;
4244:           }
4245:         }
4246:       } else {
4247:         for (k = 0; k < dof; ++k) {
4248:           if ((cind < cdof) && (k == cdofs[cind])) {
4249:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4250:             cind++;
4251:           }
4252:         }
4253:       }
4254:     }
4255:   }
4256:   return(0);
4257: }

4259: 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[])
4260: {
4261:   PetscScalar    *a;
4262:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4263:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4264:   PetscInt        cind = 0, b;
4265:   PetscErrorCode  ierr;

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

4312: 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[])
4313: {
4314:   PetscScalar    *a;
4315:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4316:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4317:   PetscInt        cind = 0, ncind = 0, b;
4318:   PetscBool       ncSet, fcSet;
4319:   PetscErrorCode  ierr;

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

4403: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4404: {
4405:   PetscScalar    *array;
4406:   const PetscInt *cone, *coneO;
4407:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4408:   PetscErrorCode  ierr;

4411:   PetscSectionGetChart(section, &pStart, &pEnd);
4412:   DMPlexGetConeSize(dm, point, &numPoints);
4413:   DMPlexGetCone(dm, point, &cone);
4414:   DMPlexGetConeOrientation(dm, point, &coneO);
4415:   VecGetArray(v, &array);
4416:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4417:     const PetscInt cp = !p ? point : cone[p-1];
4418:     const PetscInt o  = !p ? 0     : coneO[p-1];

4420:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4421:     PetscSectionGetDof(section, cp, &dof);
4422:     /* ADD_VALUES */
4423:     {
4424:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4425:       PetscScalar    *a;
4426:       PetscInt        cdof, coff, cind = 0, k;

4428:       PetscSectionGetConstraintDof(section, cp, &cdof);
4429:       PetscSectionGetOffset(section, cp, &coff);
4430:       a    = &array[coff];
4431:       if (!cdof) {
4432:         if (o >= 0) {
4433:           for (k = 0; k < dof; ++k) {
4434:             a[k] += values[off+k];
4435:           }
4436:         } else {
4437:           for (k = 0; k < dof; ++k) {
4438:             a[k] += values[off+dof-k-1];
4439:           }
4440:         }
4441:       } else {
4442:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4443:         if (o >= 0) {
4444:           for (k = 0; k < dof; ++k) {
4445:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4446:             a[k] += values[off+k];
4447:           }
4448:         } else {
4449:           for (k = 0; k < dof; ++k) {
4450:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4451:             a[k] += values[off+dof-k-1];
4452:           }
4453:         }
4454:       }
4455:     }
4456:   }
4457:   VecRestoreArray(v, &array);
4458:   return(0);
4459: }

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

4464:   Not collective

4466:   Input Parameters:
4467: + dm - The DM
4468: . section - The section describing the layout in v, or NULL to use the default section
4469: . v - The local vector
4470: . point - The point in the DM
4471: . values - The array of values
4472: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4473:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4478:   Level: intermediate

4480: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4481: @*/
4482: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4483: {
4484:   PetscSection    clSection;
4485:   IS              clPoints;
4486:   PetscScalar    *array;
4487:   PetscInt       *points = NULL;
4488:   const PetscInt *clp, *clperm;
4489:   PetscInt        depth, numFields, numPoints, p;
4490:   PetscErrorCode  ierr;

4494:   if (!section) {DMGetSection(dm, &section);}
4497:   DMPlexGetDepth(dm, &depth);
4498:   PetscSectionGetNumFields(section, &numFields);
4499:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4500:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4501:     return(0);
4502:   }
4503:   /* Get points */
4504:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4505:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4506:   /* Get array */
4507:   VecGetArray(v, &array);
4508:   /* Get values */
4509:   if (numFields > 0) {
4510:     PetscInt offset = 0, f;
4511:     for (f = 0; f < numFields; ++f) {
4512:       const PetscInt    **perms = NULL;
4513:       const PetscScalar **flips = NULL;

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

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

4631: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4632: {
4633:   PetscSection      clSection;
4634:   IS                clPoints;
4635:   PetscScalar       *array;
4636:   PetscInt          *points = NULL;
4637:   const PetscInt    *clp, *clperm;
4638:   PetscInt          numFields, numPoints, p;
4639:   PetscInt          offset = 0, f;
4640:   PetscErrorCode    ierr;

4644:   if (!section) {DMGetSection(dm, &section);}
4647:   PetscSectionGetNumFields(section, &numFields);
4648:   /* Get points */
4649:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4650:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4651:   /* Get array */
4652:   VecGetArray(v, &array);
4653:   /* Get values */
4654:   for (f = 0; f < numFields; ++f) {
4655:     const PetscInt    **perms = NULL;
4656:     const PetscScalar **flips = NULL;

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

4715: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4716: {
4717:   PetscMPIInt    rank;
4718:   PetscInt       i, j;

4722:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4723:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4724:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4725:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4726:   numCIndices = numCIndices ? numCIndices : numRIndices;
4727:   for (i = 0; i < numRIndices; i++) {
4728:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4729:     for (j = 0; j < numCIndices; j++) {
4730: #if defined(PETSC_USE_COMPLEX)
4731:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4732: #else
4733:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4734: #endif
4735:     }
4736:     PetscViewerASCIIPrintf(viewer, "\n");
4737:   }
4738:   return(0);
4739: }

4741: /* . off - The global offset of this point */
4742: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4743: {
4744:   PetscInt        dof;    /* The number of unknowns on this point */
4745:   PetscInt        cdof;   /* The number of constraints on this point */
4746:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4747:   PetscInt        cind = 0, k;
4748:   PetscErrorCode  ierr;

4751:   PetscSectionGetDof(section, point, &dof);
4752:   PetscSectionGetConstraintDof(section, point, &cdof);
4753:   if (!cdof || setBC) {
4754:     if (perm) {
4755:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4756:     } else {
4757:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4758:     }
4759:   } else {
4760:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4761:     if (perm) {
4762:       for (k = 0; k < dof; ++k) {
4763:         if ((cind < cdof) && (k == cdofs[cind])) {
4764:           /* Insert check for returning constrained indices */
4765:           indices[*loff+perm[k]] = -(off+k+1);
4766:           ++cind;
4767:         } else {
4768:           indices[*loff+perm[k]] = off+k-cind;
4769:         }
4770:       }
4771:     } else {
4772:       for (k = 0; k < dof; ++k) {
4773:         if ((cind < cdof) && (k == cdofs[cind])) {
4774:           /* Insert check for returning constrained indices */
4775:           indices[*loff+k] = -(off+k+1);
4776:           ++cind;
4777:         } else {
4778:           indices[*loff+k] = off+k-cind;
4779:         }
4780:       }
4781:     }
4782:   }
4783:   *loff += dof;
4784:   return(0);
4785: }

4787: /*
4788:   This version only believes the point offset from the globalSection

4790:  . off - The global offset of this point
4791: */
4792: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4793: {
4794:   PetscInt       numFields, foff, f;

4798:   PetscSectionGetNumFields(section, &numFields);
4799:   for (f = 0, foff = 0; f < numFields; ++f) {
4800:     PetscInt        fdof, cfdof;
4801:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4802:     PetscInt        cind = 0, b;
4803:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4805:     PetscSectionGetFieldDof(section, point, f, &fdof);
4806:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4807:     if (!cfdof || setBC) {
4808:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4809:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4810:     } else {
4811:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4812:       if (perm) {
4813:         for (b = 0; b < fdof; b++) {
4814:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4815:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4816:             ++cind;
4817:           } else {
4818:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4819:           }
4820:         }
4821:       } else {
4822:         for (b = 0; b < fdof; b++) {
4823:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4824:             indices[foffs[f]+b] = -(off+foff+b+1);
4825:             ++cind;
4826:           } else {
4827:             indices[foffs[f]+b] = off+foff+b-cind;
4828:           }
4829:         }
4830:       }
4831:     }
4832:     foff     += (setBC ? fdof : (fdof - cfdof));
4833:     foffs[f] += fdof;
4834:   }
4835:   return(0);
4836: }

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

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

4849:   PetscSectionGetNumFields(section, &numFields);
4850:   for (f = 0; f < numFields; ++f) {
4851:     PetscInt        fdof, cfdof;
4852:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4853:     PetscInt        cind = 0, b;
4854:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4856:     PetscSectionGetFieldDof(section, point, f, &fdof);
4857:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4858:     PetscSectionGetFieldOffset(globalSection, point, f, &foff);
4859:     if (!cfdof || setBC) {
4860:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = foff+b;}}
4861:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = foff+b;}}
4862:     } else {
4863:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4864:       if (perm) {
4865:         for (b = 0; b < fdof; b++) {
4866:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4867:             indices[foffs[f]+perm[b]] = -(foff+b+1);
4868:             ++cind;
4869:           } else {
4870:             indices[foffs[f]+perm[b]] = foff+b-cind;
4871:           }
4872:         }
4873:       } else {
4874:         for (b = 0; b < fdof; b++) {
4875:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4876:             indices[foffs[f]+b] = -(foff+b+1);
4877:             ++cind;
4878:           } else {
4879:             indices[foffs[f]+b] = foff+b-cind;
4880:           }
4881:         }
4882:       }
4883:     }
4884:     foffs[f] += fdof;
4885:   }
4886:   return(0);
4887: }

4889: 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)
4890: {
4891:   Mat             cMat;
4892:   PetscSection    aSec, cSec;
4893:   IS              aIS;
4894:   PetscInt        aStart = -1, aEnd = -1;
4895:   const PetscInt  *anchors;
4896:   PetscInt        numFields, f, p, q, newP = 0;
4897:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4898:   PetscInt        *newPoints, *indices, *newIndices;
4899:   PetscInt        maxAnchor, maxDof;
4900:   PetscInt        newOffsets[32];
4901:   PetscInt        *pointMatOffsets[32];
4902:   PetscInt        *newPointOffsets[32];
4903:   PetscScalar     *pointMat[32];
4904:   PetscScalar     *newValues=NULL,*tmpValues;
4905:   PetscBool       anyConstrained = PETSC_FALSE;
4906:   PetscErrorCode  ierr;

4911:   PetscSectionGetNumFields(section, &numFields);

4913:   DMPlexGetAnchors(dm,&aSec,&aIS);
4914:   /* if there are point-to-point constraints */
4915:   if (aSec) {
4916:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4917:     ISGetIndices(aIS,&anchors);
4918:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4919:     /* figure out how many points are going to be in the new element matrix
4920:      * (we allow double counting, because it's all just going to be summed
4921:      * into the global matrix anyway) */
4922:     for (p = 0; p < 2*numPoints; p+=2) {
4923:       PetscInt b    = points[p];
4924:       PetscInt bDof = 0, bSecDof;

4926:       PetscSectionGetDof(section,b,&bSecDof);
4927:       if (!bSecDof) {
4928:         continue;
4929:       }
4930:       if (b >= aStart && b < aEnd) {
4931:         PetscSectionGetDof(aSec,b,&bDof);
4932:       }
4933:       if (bDof) {
4934:         /* this point is constrained */
4935:         /* it is going to be replaced by its anchors */
4936:         PetscInt bOff, q;

4938:         anyConstrained = PETSC_TRUE;
4939:         newNumPoints  += bDof;
4940:         PetscSectionGetOffset(aSec,b,&bOff);
4941:         for (q = 0; q < bDof; q++) {
4942:           PetscInt a = anchors[bOff + q];
4943:           PetscInt aDof;

4945:           PetscSectionGetDof(section,a,&aDof);
4946:           newNumIndices += aDof;
4947:           for (f = 0; f < numFields; ++f) {
4948:             PetscInt fDof;

4950:             PetscSectionGetFieldDof(section, a, f, &fDof);
4951:             newOffsets[f+1] += fDof;
4952:           }
4953:         }
4954:       }
4955:       else {
4956:         /* this point is not constrained */
4957:         newNumPoints++;
4958:         newNumIndices += bSecDof;
4959:         for (f = 0; f < numFields; ++f) {
4960:           PetscInt fDof;

4962:           PetscSectionGetFieldDof(section, b, f, &fDof);
4963:           newOffsets[f+1] += fDof;
4964:         }
4965:       }
4966:     }
4967:   }
4968:   if (!anyConstrained) {
4969:     if (outNumPoints)  *outNumPoints  = 0;
4970:     if (outNumIndices) *outNumIndices = 0;
4971:     if (outPoints)     *outPoints     = NULL;
4972:     if (outValues)     *outValues     = NULL;
4973:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4974:     return(0);
4975:   }

4977:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4978:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4982:   if (!outPoints && !outValues) {
4983:     if (offsets) {
4984:       for (f = 0; f <= numFields; f++) {
4985:         offsets[f] = newOffsets[f];
4986:       }
4987:     }
4988:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4989:     return(0);
4990:   }

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

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

4996:   /* workspaces */
4997:   if (numFields) {
4998:     for (f = 0; f < numFields; f++) {
4999:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5000:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5001:     }
5002:   }
5003:   else {
5004:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5005:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5006:   }

5008:   /* get workspaces for the point-to-point matrices */
5009:   if (numFields) {
5010:     PetscInt totalOffset, totalMatOffset;

5012:     for (p = 0; p < numPoints; p++) {
5013:       PetscInt b    = points[2*p];
5014:       PetscInt bDof = 0, bSecDof;

5016:       PetscSectionGetDof(section,b,&bSecDof);
5017:       if (!bSecDof) {
5018:         for (f = 0; f < numFields; f++) {
5019:           newPointOffsets[f][p + 1] = 0;
5020:           pointMatOffsets[f][p + 1] = 0;
5021:         }
5022:         continue;
5023:       }
5024:       if (b >= aStart && b < aEnd) {
5025:         PetscSectionGetDof(aSec, b, &bDof);
5026:       }
5027:       if (bDof) {
5028:         for (f = 0; f < numFields; f++) {
5029:           PetscInt fDof, q, bOff, allFDof = 0;

5031:           PetscSectionGetFieldDof(section, b, f, &fDof);
5032:           PetscSectionGetOffset(aSec, b, &bOff);
5033:           for (q = 0; q < bDof; q++) {
5034:             PetscInt a = anchors[bOff + q];
5035:             PetscInt aFDof;

5037:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5038:             allFDof += aFDof;
5039:           }
5040:           newPointOffsets[f][p+1] = allFDof;
5041:           pointMatOffsets[f][p+1] = fDof * allFDof;
5042:         }
5043:       }
5044:       else {
5045:         for (f = 0; f < numFields; f++) {
5046:           PetscInt fDof;

5048:           PetscSectionGetFieldDof(section, b, f, &fDof);
5049:           newPointOffsets[f][p+1] = fDof;
5050:           pointMatOffsets[f][p+1] = 0;
5051:         }
5052:       }
5053:     }
5054:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5055:       newPointOffsets[f][0] = totalOffset;
5056:       pointMatOffsets[f][0] = totalMatOffset;
5057:       for (p = 0; p < numPoints; p++) {
5058:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5059:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5060:       }
5061:       totalOffset    = newPointOffsets[f][numPoints];
5062:       totalMatOffset = pointMatOffsets[f][numPoints];
5063:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5064:     }
5065:   }
5066:   else {
5067:     for (p = 0; p < numPoints; p++) {
5068:       PetscInt b    = points[2*p];
5069:       PetscInt bDof = 0, bSecDof;

5071:       PetscSectionGetDof(section,b,&bSecDof);
5072:       if (!bSecDof) {
5073:         newPointOffsets[0][p + 1] = 0;
5074:         pointMatOffsets[0][p + 1] = 0;
5075:         continue;
5076:       }
5077:       if (b >= aStart && b < aEnd) {
5078:         PetscSectionGetDof(aSec, b, &bDof);
5079:       }
5080:       if (bDof) {
5081:         PetscInt bOff, q, allDof = 0;

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

5087:           PetscSectionGetDof(section, a, &aDof);
5088:           allDof += aDof;
5089:         }
5090:         newPointOffsets[0][p+1] = allDof;
5091:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5092:       }
5093:       else {
5094:         newPointOffsets[0][p+1] = bSecDof;
5095:         pointMatOffsets[0][p+1] = 0;
5096:       }
5097:     }
5098:     newPointOffsets[0][0] = 0;
5099:     pointMatOffsets[0][0] = 0;
5100:     for (p = 0; p < numPoints; p++) {
5101:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5102:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5103:     }
5104:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5105:   }

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

5110:   /* get the point-to-point matrices; construct newPoints */
5111:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5112:   PetscSectionGetMaxDof(section, &maxDof);
5113:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5114:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5115:   if (numFields) {
5116:     for (p = 0, newP = 0; p < numPoints; p++) {
5117:       PetscInt b    = points[2*p];
5118:       PetscInt o    = points[2*p+1];
5119:       PetscInt bDof = 0, bSecDof;

5121:       PetscSectionGetDof(section, b, &bSecDof);
5122:       if (!bSecDof) {
5123:         continue;
5124:       }
5125:       if (b >= aStart && b < aEnd) {
5126:         PetscSectionGetDof(aSec, b, &bDof);
5127:       }
5128:       if (bDof) {
5129:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5131:         fStart[0] = 0;
5132:         fEnd[0]   = 0;
5133:         for (f = 0; f < numFields; f++) {
5134:           PetscInt fDof;

5136:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5137:           fStart[f+1] = fStart[f] + fDof;
5138:           fEnd[f+1]   = fStart[f+1];
5139:         }
5140:         PetscSectionGetOffset(cSec, b, &bOff);
5141:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

5143:         fAnchorStart[0] = 0;
5144:         fAnchorEnd[0]   = 0;
5145:         for (f = 0; f < numFields; f++) {
5146:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5148:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5149:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5150:         }
5151:         PetscSectionGetOffset(aSec, b, &bOff);
5152:         for (q = 0; q < bDof; q++) {
5153:           PetscInt a = anchors[bOff + q], aOff;

5155:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5156:           newPoints[2*(newP + q)]     = a;
5157:           newPoints[2*(newP + q) + 1] = 0;
5158:           PetscSectionGetOffset(section, a, &aOff);
5159:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5160:         }
5161:         newP += bDof;

5163:         if (outValues) {
5164:           /* get the point-to-point submatrix */
5165:           for (f = 0; f < numFields; f++) {
5166:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5167:           }
5168:         }
5169:       }
5170:       else {
5171:         newPoints[2 * newP]     = b;
5172:         newPoints[2 * newP + 1] = o;
5173:         newP++;
5174:       }
5175:     }
5176:   } else {
5177:     for (p = 0; p < numPoints; p++) {
5178:       PetscInt b    = points[2*p];
5179:       PetscInt o    = points[2*p+1];
5180:       PetscInt bDof = 0, bSecDof;

5182:       PetscSectionGetDof(section, b, &bSecDof);
5183:       if (!bSecDof) {
5184:         continue;
5185:       }
5186:       if (b >= aStart && b < aEnd) {
5187:         PetscSectionGetDof(aSec, b, &bDof);
5188:       }
5189:       if (bDof) {
5190:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5201:           newPoints[2*(newP + q)]     = a;
5202:           newPoints[2*(newP + q) + 1] = 0;
5203:           PetscSectionGetOffset(section, a, &aOff);
5204:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5205:         }
5206:         newP += bDof;

5208:         /* get the point-to-point submatrix */
5209:         if (outValues) {
5210:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5211:         }
5212:       }
5213:       else {
5214:         newPoints[2 * newP]     = b;
5215:         newPoints[2 * newP + 1] = o;
5216:         newP++;
5217:       }
5218:     }
5219:   }

5221:   if (outValues) {
5222:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5223:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5224:     /* multiply constraints on the right */
5225:     if (numFields) {
5226:       for (f = 0; f < numFields; f++) {
5227:         PetscInt oldOff = offsets[f];

5229:         for (p = 0; p < numPoints; p++) {
5230:           PetscInt cStart = newPointOffsets[f][p];
5231:           PetscInt b      = points[2 * p];
5232:           PetscInt c, r, k;
5233:           PetscInt dof;

5235:           PetscSectionGetFieldDof(section,b,f,&dof);
5236:           if (!dof) {
5237:             continue;
5238:           }
5239:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5240:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5241:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5243:             for (r = 0; r < numIndices; r++) {
5244:               for (c = 0; c < nCols; c++) {
5245:                 for (k = 0; k < dof; k++) {
5246:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5247:                 }
5248:               }
5249:             }
5250:           }
5251:           else {
5252:             /* copy this column as is */
5253:             for (r = 0; r < numIndices; r++) {
5254:               for (c = 0; c < dof; c++) {
5255:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5256:               }
5257:             }
5258:           }
5259:           oldOff += dof;
5260:         }
5261:       }
5262:     }
5263:     else {
5264:       PetscInt oldOff = 0;
5265:       for (p = 0; p < numPoints; p++) {
5266:         PetscInt cStart = newPointOffsets[0][p];
5267:         PetscInt b      = points[2 * p];
5268:         PetscInt c, r, k;
5269:         PetscInt dof;

5271:         PetscSectionGetDof(section,b,&dof);
5272:         if (!dof) {
5273:           continue;
5274:         }
5275:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5276:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5277:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5279:           for (r = 0; r < numIndices; r++) {
5280:             for (c = 0; c < nCols; c++) {
5281:               for (k = 0; k < dof; k++) {
5282:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5283:               }
5284:             }
5285:           }
5286:         }
5287:         else {
5288:           /* copy this column as is */
5289:           for (r = 0; r < numIndices; r++) {
5290:             for (c = 0; c < dof; c++) {
5291:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5292:             }
5293:           }
5294:         }
5295:         oldOff += dof;
5296:       }
5297:     }

5299:     if (multiplyLeft) {
5300:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5301:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5302:       /* multiply constraints transpose on the left */
5303:       if (numFields) {
5304:         for (f = 0; f < numFields; f++) {
5305:           PetscInt oldOff = offsets[f];

5307:           for (p = 0; p < numPoints; p++) {
5308:             PetscInt rStart = newPointOffsets[f][p];
5309:             PetscInt b      = points[2 * p];
5310:             PetscInt c, r, k;
5311:             PetscInt dof;

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

5318:               for (r = 0; r < nRows; r++) {
5319:                 for (c = 0; c < newNumIndices; c++) {
5320:                   for (k = 0; k < dof; k++) {
5321:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5322:                   }
5323:                 }
5324:               }
5325:             }
5326:             else {
5327:               /* copy this row as is */
5328:               for (r = 0; r < dof; r++) {
5329:                 for (c = 0; c < newNumIndices; c++) {
5330:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5331:                 }
5332:               }
5333:             }
5334:             oldOff += dof;
5335:           }
5336:         }
5337:       }
5338:       else {
5339:         PetscInt oldOff = 0;

5341:         for (p = 0; p < numPoints; p++) {
5342:           PetscInt rStart = newPointOffsets[0][p];
5343:           PetscInt b      = points[2 * p];
5344:           PetscInt c, r, k;
5345:           PetscInt dof;

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

5352:             for (r = 0; r < nRows; r++) {
5353:               for (c = 0; c < newNumIndices; c++) {
5354:                 for (k = 0; k < dof; k++) {
5355:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5356:                 }
5357:               }
5358:             }
5359:           }
5360:           else {
5361:             /* copy this row as is */
5362:             for (r = 0; r < dof; r++) {
5363:               for (c = 0; c < newNumIndices; c++) {
5364:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5365:               }
5366:             }
5367:           }
5368:           oldOff += dof;
5369:         }
5370:       }

5372:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5373:     }
5374:     else {
5375:       newValues = tmpValues;
5376:     }
5377:   }

5379:   /* clean up */
5380:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5381:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5383:   if (numFields) {
5384:     for (f = 0; f < numFields; f++) {
5385:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5386:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5387:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5388:     }
5389:   }
5390:   else {
5391:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5392:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5393:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5394:   }
5395:   ISRestoreIndices(aIS,&anchors);

5397:   /* output */
5398:   if (outPoints) {
5399:     *outPoints = newPoints;
5400:   }
5401:   else {
5402:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5403:   }
5404:   if (outValues) {
5405:     *outValues = newValues;
5406:   }
5407:   for (f = 0; f <= numFields; f++) {
5408:     offsets[f] = newOffsets[f];
5409:   }
5410:   return(0);
5411: }

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

5416:   Not collective

5418:   Input Parameters:
5419: + dm - The DM
5420: . section - The section describing the layout in v, or NULL to use the default section
5421: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5422: - point - The mesh point

5424:   Output parameters:
5425: + numIndices - The number of indices
5426: . indices - The indices
5427: - outOffsets - Field offset if not NULL

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

5431:   Level: advanced

5433: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5434: @*/
5435: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5436: {
5437:   PetscSection    clSection;
5438:   IS              clPoints;
5439:   const PetscInt *clp;
5440:   const PetscInt  **perms[32] = {NULL};
5441:   PetscInt       *points = NULL, *pointsNew;
5442:   PetscInt        numPoints, numPointsNew;
5443:   PetscInt        offsets[32];
5444:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5445:   PetscErrorCode  ierr;

5453:   PetscSectionGetNumFields(section, &Nf);
5454:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5455:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5456:   /* Get points in closure */
5457:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5458:   /* Get number of indices and indices per field */
5459:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5460:     PetscInt dof, fdof;

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

5501:       for (f = 0; f <= Nf; f++) {
5502:         outOffsets[f] = offsets[f];
5503:       }
5504:     }
5505:     for (p = 0; p < numPoints; p++) {
5506:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5507:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5508:     }
5509:   } else {
5510:     for (p = 0, off = 0; p < numPoints; p++) {
5511:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5513:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5514:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5515:     }
5516:   }
5517:   /* Cleanup points */
5518:   for (f = 0; f < PetscMax(1,Nf); f++) {
5519:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5520:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5521:   }
5522:   if (numPointsNew) {
5523:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5524:   } else {
5525:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5526:   }
5527:   if (numIndices) *numIndices = Nind;
5528:   return(0);
5529: }

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

5534:   Not collective

5536:   Input Parameters:
5537: + dm - The DM
5538: . section - The section describing the layout in v, or NULL to use the default section
5539: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5540: . point - The mesh point
5541: . numIndices - The number of indices
5542: . indices - The indices
5543: - outOffsets - Field offset if not NULL

5545:   Level: advanced

5547: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5548: @*/
5549: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5550: {

5556:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5557:   return(0);
5558: }

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

5563:   Not collective

5565:   Input Parameters:
5566: + dm - The DM
5567: . section - The section describing the layout in v, or NULL to use the default section
5568: . globalSection - The section describing the layout in v, or NULL to use the default global section
5569: . A - The matrix
5570: . point - The point in the DM
5571: . values - The array of values
5572: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5577:   Level: intermediate

5579: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5580: @*/
5581: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5582: {
5583:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5584:   PetscSection        clSection;
5585:   IS                  clPoints;
5586:   PetscInt           *points = NULL, *newPoints;
5587:   const PetscInt     *clp;
5588:   PetscInt           *indices;
5589:   PetscInt            offsets[32];
5590:   const PetscInt    **perms[32] = {NULL};
5591:   const PetscScalar **flips[32] = {NULL};
5592:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5593:   PetscScalar        *valCopy = NULL;
5594:   PetscScalar        *newValues;
5595:   PetscErrorCode      ierr;

5599:   if (!section) {DMGetSection(dm, &section);}
5601:   if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5604:   PetscSectionGetNumFields(section, &numFields);
5605:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5606:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5607:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5608:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5609:     PetscInt fdof;

5611:     PetscSectionGetDof(section, points[p], &dof);
5612:     for (f = 0; f < numFields; ++f) {
5613:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5614:       offsets[f+1] += fdof;
5615:     }
5616:     numIndices += dof;
5617:   }
5618:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5632:         if (!numFields) {
5633:           PetscSectionGetDof(section,point,&fdof);
5634:         } else {
5635:           PetscSectionGetFieldDof(section,point,f,&fdof);
5636:         }
5637:         if (flip) {
5638:           PetscInt i, j, k;

5640:           if (!valCopy) {
5641:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5642:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5643:             values = valCopy;
5644:           }
5645:           for (i = 0; i < fdof; i++) {
5646:             PetscScalar fval = flip[i];

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

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

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

5735: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5736: {
5737:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5738:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5739:   PetscInt       *cpoints = NULL;
5740:   PetscInt       *findices, *cindices;
5741:   PetscInt        foffsets[32], coffsets[32];
5742:   CellRefiner     cellRefiner;
5743:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5744:   PetscErrorCode  ierr;

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

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

5814:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5815:     if (!dof) continue;
5816:     for (f = 0; f < numFields; ++f) {
5817:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5818:       foffsets[f+1] += fdof;
5819:     }
5820:     numFIndices += dof;
5821:   }
5822:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5824:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5825:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5826:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5827:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5828:   if (numFields) {
5829:     const PetscInt **permsF[32] = {NULL};
5830:     const PetscInt **permsC[32] = {NULL};

5832:     for (f = 0; f < numFields; f++) {
5833:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5834:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5835:     }
5836:     for (p = 0; p < numFPoints; p++) {
5837:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5838:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5839:     }
5840:     for (p = 0; p < numCPoints; p++) {
5841:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5842:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5843:     }
5844:     for (f = 0; f < numFields; f++) {
5845:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5846:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5847:     }
5848:   } else {
5849:     const PetscInt **permsF = NULL;
5850:     const PetscInt **permsC = NULL;

5852:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5853:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5854:     for (p = 0, off = 0; p < numFPoints; p++) {
5855:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5857:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5858:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5859:     }
5860:     for (p = 0, off = 0; p < numCPoints; p++) {
5861:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5863:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5864:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5865:     }
5866:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5867:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5868:   }
5869:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5870:   /* TODO: flips */
5871:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5872:   if (ierr) {
5873:     PetscMPIInt    rank;
5874:     PetscErrorCode ierr2;

5876:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5877:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5878:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5879:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
5880:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
5881: 
5882:   }
5883:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
5884:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5885:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5886:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5887:   return(0);
5888: }

5890: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5891: {
5892:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5893:   PetscInt      *cpoints = NULL;
5894:   PetscInt       foffsets[32], coffsets[32];
5895:   CellRefiner    cellRefiner;
5896:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

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

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

5966:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5967:     if (!dof) continue;
5968:     for (f = 0; f < numFields; ++f) {
5969:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5970:       foffsets[f+1] += fdof;
5971:     }
5972:     numFIndices += dof;
5973:   }
5974:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

5982:     for (f = 0; f < numFields; f++) {
5983:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5984:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5985:     }
5986:     for (p = 0; p < numFPoints; p++) {
5987:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5988:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5989:     }
5990:     for (p = 0; p < numCPoints; p++) {
5991:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5992:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5993:     }
5994:     for (f = 0; f < numFields; f++) {
5995:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5996:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5997:     }
5998:   } else {
5999:     const PetscInt **permsF = NULL;
6000:     const PetscInt **permsC = NULL;

6002:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6003:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6004:     for (p = 0, off = 0; p < numFPoints; p++) {
6005:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6007:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6008:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6009:     }
6010:     for (p = 0, off = 0; p < numCPoints; p++) {
6011:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6013:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6014:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6015:     }
6016:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6017:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6018:   }
6019:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6020:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6021:   return(0);
6022: }

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

6027:   Input Parameter:
6028: . dm - The DMPlex object

6030:   Output Parameters:
6031: + cMax - The first hybrid cell
6032: . fMax - The first hybrid face
6033: . eMax - The first hybrid edge
6034: - vMax - The first hybrid vertex

6036:   Level: developer

6038: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6039: @*/
6040: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6041: {
6042:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6043:   PetscInt       dim;

6048:   DMGetDimension(dm, &dim);
6049:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6050:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6051:   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6052:   if (eMax) *eMax = mesh->hybridPointMax[1];
6053:   if (vMax) *vMax = mesh->hybridPointMax[0];
6054:   return(0);
6055: }

6057: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6058: {
6059:   IS             is, his;
6060:   PetscInt       first = 0, stride;
6061:   PetscBool      isStride;

6065:   DMLabelGetStratumIS(depthLabel, d, &is);
6066:   PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6067:   if (isStride) {
6068:     ISStrideGetInfo(is, &first, &stride);
6069:   }
6070:   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6071:   ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6072:   DMLabelSetStratumIS(dimLabel, d, his);
6073:   ISDestroy(&his);
6074:   ISDestroy(&is);
6075:   return(0);
6076: }

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

6081:   Input Parameters:
6082: . dm   - The DMPlex object
6083: . cMax - The first hybrid cell
6084: . fMax - The first hybrid face
6085: . eMax - The first hybrid edge
6086: - vMax - The first hybrid vertex

6088:   Level: developer

6090: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6091: @*/
6092: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6093: {
6094:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6095:   PetscInt       dim;

6100:   DMGetDimension(dm, &dim);
6101:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6102:   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6103:   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6104:   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6105:   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6106:   return(0);
6107: }

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

6112:   Input Parameter:
6113: . dm   - The DMPlex object

6115:   Output Parameter:
6116: . cellHeight - The height of a cell

6118:   Level: developer

6120: .seealso DMPlexSetVTKCellHeight()
6121: @*/
6122: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6123: {
6124:   DM_Plex *mesh = (DM_Plex*) dm->data;

6129:   *cellHeight = mesh->vtkCellHeight;
6130:   return(0);
6131: }

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

6136:   Input Parameters:
6137: + dm   - The DMPlex object
6138: - cellHeight - The height of a cell

6140:   Level: developer

6142: .seealso DMPlexGetVTKCellHeight()
6143: @*/
6144: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6145: {
6146:   DM_Plex *mesh = (DM_Plex*) dm->data;

6150:   mesh->vtkCellHeight = cellHeight;
6151:   return(0);
6152: }

6154: /* We can easily have a form that takes an IS instead */
6155: PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6156: {
6157:   PetscSection   section, globalSection;
6158:   PetscInt      *numbers, p;

6162:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6163:   PetscSectionSetChart(section, pStart, pEnd);
6164:   for (p = pStart; p < pEnd; ++p) {
6165:     PetscSectionSetDof(section, p, 1);
6166:   }
6167:   PetscSectionSetUp(section);
6168:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6169:   PetscMalloc1(pEnd - pStart, &numbers);
6170:   for (p = pStart; p < pEnd; ++p) {
6171:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6172:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6173:     else                       numbers[p-pStart] += shift;
6174:   }
6175:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6176:   if (globalSize) {
6177:     PetscLayout layout;
6178:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6179:     PetscLayoutGetSize(layout, globalSize);
6180:     PetscLayoutDestroy(&layout);
6181:   }
6182:   PetscSectionDestroy(&section);
6183:   PetscSectionDestroy(&globalSection);
6184:   return(0);
6185: }

6187: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6188: {
6189:   PetscInt       cellHeight, cStart, cEnd, cMax;

6193:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6194:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6195:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6196:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6197:   DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6198:   return(0);
6199: }

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

6204:   Input Parameter:
6205: . dm   - The DMPlex object

6207:   Output Parameter:
6208: . globalCellNumbers - Global cell numbers for all cells on this process

6210:   Level: developer

6212: .seealso DMPlexGetVertexNumbering()
6213: @*/
6214: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6215: {
6216:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6221:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6222:   *globalCellNumbers = mesh->globalCellNumbers;
6223:   return(0);
6224: }

6226: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6227: {
6228:   PetscInt       vStart, vEnd, vMax;

6233:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6234:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6235:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6236:   DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6237:   return(0);
6238: }

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

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

6246:   Output Parameter:
6247: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6249:   Level: developer

6251: .seealso DMPlexGetCellNumbering()
6252: @*/
6253: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6254: {
6255:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6260:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6261:   *globalVertexNumbers = mesh->globalVertexNumbers;
6262:   return(0);
6263: }

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

6268:   Input Parameter:
6269: . dm   - The DMPlex object

6271:   Output Parameter:
6272: . globalPointNumbers - Global numbers for all points on this process

6274:   Level: developer

6276: .seealso DMPlexGetCellNumbering()
6277: @*/
6278: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6279: {
6280:   IS             nums[4];
6281:   PetscInt       depths[4], gdepths[4], starts[4];
6282:   PetscInt       depth, d, shift = 0;

6287:   DMPlexGetDepth(dm, &depth);
6288:   /* For unstratified meshes use dim instead of depth */
6289:   if (depth < 0) {DMGetDimension(dm, &depth);}
6290:   for (d = 0; d <= depth; ++d) {
6291:     PetscInt end;

6293:     depths[d] = depth-d;
6294:     DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6295:     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6296:   }
6297:   PetscSortIntWithArray(depth+1, starts, depths);
6298:   MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6299:   for (d = 0; d <= depth; ++d) {
6300:     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6301:   }
6302:   for (d = 0; d <= depth; ++d) {
6303:     PetscInt pStart, pEnd, gsize;

6305:     DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6306:     DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6307:     shift += gsize;
6308:   }
6309:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6310:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6311:   return(0);
6312: }


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

6318:   Input Parameter:
6319: . dm - The DMPlex object

6321:   Output Parameter:
6322: . ranks - The rank field

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

6327:   Level: intermediate

6329: .seealso: DMView()
6330: @*/
6331: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6332: {
6333:   DM             rdm;
6334:   PetscFE        fe;
6335:   PetscScalar   *r;
6336:   PetscMPIInt    rank;
6337:   PetscInt       dim, cStart, cEnd, c;

6343:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6344:   DMClone(dm, &rdm);
6345:   DMGetDimension(rdm, &dim);
6346:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6347:   PetscObjectSetName((PetscObject) fe, "rank");
6348:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6349:   PetscFEDestroy(&fe);
6350:   DMCreateDS(rdm);
6351:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6352:   DMCreateGlobalVector(rdm, ranks);
6353:   PetscObjectSetName((PetscObject) *ranks, "partition");
6354:   VecGetArray(*ranks, &r);
6355:   for (c = cStart; c < cEnd; ++c) {
6356:     PetscScalar *lr;

6358:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6359:     *lr = rank;
6360:   }
6361:   VecRestoreArray(*ranks, &r);
6362:   DMDestroy(&rdm);
6363:   return(0);
6364: }

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

6369:   Input Parameters:
6370: + dm    - The DMPlex
6371: - label - The DMLabel

6373:   Output Parameter:
6374: . val - The label value field

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

6379:   Level: intermediate

6381: .seealso: DMView()
6382: @*/
6383: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6384: {
6385:   DM             rdm;
6386:   PetscFE        fe;
6387:   PetscScalar   *v;
6388:   PetscInt       dim, cStart, cEnd, c;

6395:   DMClone(dm, &rdm);
6396:   DMGetDimension(rdm, &dim);
6397:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6398:   PetscObjectSetName((PetscObject) fe, "label_value");
6399:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6400:   PetscFEDestroy(&fe);
6401:   DMCreateDS(rdm);
6402:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6403:   DMCreateGlobalVector(rdm, val);
6404:   PetscObjectSetName((PetscObject) *val, "label_value");
6405:   VecGetArray(*val, &v);
6406:   for (c = cStart; c < cEnd; ++c) {
6407:     PetscScalar *lv;
6408:     PetscInt     cval;

6410:     DMPlexPointGlobalRef(rdm, c, v, &lv);
6411:     DMLabelGetValue(label, c, &cval);
6412:     *lv = cval;
6413:   }
6414:   VecRestoreArray(*val, &v);
6415:   DMDestroy(&rdm);
6416:   return(0);
6417: }

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

6422:   Input Parameter:
6423: . dm - The DMPlex object

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

6427:   Level: developer

6429: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6430: @*/
6431: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6432: {
6433:   PetscSection    coneSection, supportSection;
6434:   const PetscInt *cone, *support;
6435:   PetscInt        coneSize, c, supportSize, s;
6436:   PetscInt        pStart, pEnd, p, pp, csize, ssize;
6437:   PetscBool       storagecheck = PETSC_TRUE;
6438:   PetscErrorCode  ierr;

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

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

6513:   Input Parameters:
6514: + dm - The DMPlex object
6515: . isSimplex - Are the cells simplices or tensor products
6516: - cellHeight - Normally 0

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

6520:   Level: developer

6522: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6523: @*/
6524: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6525: {
6526:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6531:   DMGetDimension(dm, &dim);
6532:   switch (dim) {
6533:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6534:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6535:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6536:   default:
6537:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6538:   }
6539:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6540:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6541:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6542:   cMax = cMax >= 0 ? cMax : cEnd;
6543:   for (c = cStart; c < cMax; ++c) {
6544:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6546:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6547:     for (cl = 0; cl < closureSize*2; cl += 2) {
6548:       const PetscInt p = closure[cl];
6549:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6550:     }
6551:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6552:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6553:   }
6554:   for (c = cMax; c < cEnd; ++c) {
6555:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

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

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

6571:   Input Parameters:
6572: + dm - The DMPlex object
6573: . isSimplex - Are the cells simplices or tensor products
6574: - cellHeight - Normally 0

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

6578:   Level: developer

6580: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6581: @*/
6582: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6583: {
6584:   PetscInt       pMax[4];
6585:   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;

6590:   DMGetDimension(dm, &dim);
6591:   DMPlexGetDepth(dm, &depth);
6592:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6593:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6594:   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
6595:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6596:     for (c = cStart; c < cEnd; ++c) {
6597:       const PetscInt *cone, *ornt, *faces;
6598:       PetscInt        numFaces, faceSize, coneSize,f;
6599:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6601:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6602:       DMPlexGetConeSize(dm, c, &coneSize);
6603:       DMPlexGetCone(dm, c, &cone);
6604:       DMPlexGetConeOrientation(dm, c, &ornt);
6605:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6606:       for (cl = 0; cl < closureSize*2; cl += 2) {
6607:         const PetscInt p = closure[cl];
6608:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6609:       }
6610:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6611:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6612:       for (f = 0; f < numFaces; ++f) {
6613:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6615:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6616:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6617:           const PetscInt p = fclosure[cl];
6618:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6619:         }
6620:         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);
6621:         for (v = 0; v < fnumCorners; ++v) {
6622:           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]);
6623:         }
6624:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6625:       }
6626:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6627:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6628:     }
6629:   }
6630:   return(0);
6631: }

6633: /*@
6634:   DMPlexCheckGeometry - Check the geometry of mesh cells

6636:   Input Parameter:
6637: . dm - The DMPlex object

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

6641:   Level: developer

6643: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
6644: @*/
6645: PetscErrorCode DMPlexCheckGeometry(DM dm)
6646: {
6647:   PetscReal      detJ, J[9], refVol = 1.0;
6648:   PetscReal      vol;
6649:   PetscInt       dim, depth, d, cStart, cEnd, c;

6653:   DMGetDimension(dm, &dim);
6654:   DMPlexGetDepth(dm, &depth);
6655:   for (d = 0; d < dim; ++d) refVol *= 2.0;
6656:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6657:   for (c = cStart; c < cEnd; ++c) {
6658:     DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
6659:     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
6660:     PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
6661:     if (depth > 1) {
6662:       DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
6663:       if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
6664:       PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
6665:     }
6666:   }
6667:   return(0);
6668: }

6670: static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
6671: {
6672:   PetscInt i,l,n;
6673:   const PetscInt *cone;

6677:   *missingPoint = -1;
6678:   DMPlexGetConeSize(dm, p, &n);
6679:   DMPlexGetCone(dm, p, &cone);
6680:   for (i=0; i<n; i++) {
6681:     PetscFindInt(cone[i], npoints, points, &l);
6682:     if (l < 0) {
6683:       *missingPoint = cone[i];
6684:       break;
6685:     }
6686:   }
6687:   return(0);
6688: }

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

6693:   Input Parameters:
6694: . dm - The DMPlex object

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

6698:   Level: developer

6700: .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6701: @*/
6702: PetscErrorCode DMPlexCheckPointSF(DM dm)
6703: {
6704:   PetscSF sf;
6705:   PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
6706:   const PetscInt *locals;

6711:   DMPlexGetDepth(dm, &depth);
6712:   DMGetPointSF(dm, &sf);
6713:   PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);

6715:   /* 1) check there are no faces in 2D, cells in 3D, in interface */
6716:   DMPlexGetVTKCellHeight(dm, &d);
6717:   DMPlexGetHeightStratum(dm, d, &plo, &phi);
6718:   for (i=0; i<nleaves; i++) {
6719:     p = locals[i];
6720:     if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
6721:   }

6723:   /* 2) if some point is in interface, then all its cone points must be also in interface  */
6724:   for (i=0; i<nleaves; i++) {
6725:     p = locals[i];
6726:     DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);
6727:     if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
6728:   }
6729:   return(0);
6730: }

6732: typedef struct cell_stats
6733: {
6734:   PetscReal min, max, sum, squaresum;
6735:   PetscInt  count;
6736: } cell_stats_t;

6738: static void cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
6739: {
6740:   PetscInt i, N = *len;

6742:   for (i = 0; i < N; i++) {
6743:     cell_stats_t *A = (cell_stats_t *) a;
6744:     cell_stats_t *B = (cell_stats_t *) b;

6746:     B->min = PetscMin(A->min,B->min);
6747:     B->max = PetscMax(A->max,B->max);
6748:     B->sum += A->sum;
6749:     B->squaresum += A->squaresum;
6750:     B->count += A->count;
6751:   }
6752: }

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

6757:   Input Parameters:
6758: + dm - The DMPlex object
6759: - output - If true, statistics will be displayed on stdout

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

6763:   Level: developer

6765: .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6766: @*/
6767: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output)
6768: {
6769:   PetscMPIInt    rank,size;
6770:   PetscInt       dim, c, cStart, cEnd, cMax, count = 0;
6771:   cell_stats_t   stats, globalStats;
6772:   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
6773:   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
6774:   DM             dmCoarse;

6779:   stats.min   = PETSC_MAX_REAL;
6780:   stats.max   = PETSC_MIN_REAL;
6781:   stats.sum   = stats.squaresum = 0.;
6782:   stats.count = 0;

6784:   DMGetCoordinateDim(dm,&dim);
6785:   PetscMalloc2(dim * dim, &J, dim * dim, &invJ);
6786:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
6787:   DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
6788:   cMax = cMax < 0 ? cEnd : cMax;
6789:   for (c = cStart; c < cMax; c++) {
6790:     PetscInt  i;
6791:     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;

6793:     DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
6794:     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
6795:     for (i = 0; i < dim * dim; i++) {
6796:       frobJ    += J[i] * J[i];
6797:       frobInvJ += invJ[i] * invJ[i];
6798:     }
6799:     cond2 = frobJ * frobInvJ;
6800:     cond  = PetscSqrtReal(cond2);

6802:     stats.min        = PetscMin(stats.min,cond);
6803:     stats.max        = PetscMax(stats.max,cond);
6804:     stats.sum       += cond;
6805:     stats.squaresum += cond2;
6806:     stats.count++;
6807:   }

6809:   MPI_Comm_size(comm,&size);
6810:   if (size > 1) {
6811:     PetscMPIInt   blockLengths[2] = {4,1};
6812:     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
6813:     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
6814:     MPI_Op        statReduce;

6816:     MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
6817:     MPI_Type_commit(&statType);
6818:     MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
6819:     MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
6820:     MPI_Op_free(&statReduce);
6821:     MPI_Type_free(&statType);
6822:   } else {
6823:     PetscMemcpy(&globalStats,&stats,sizeof(stats));
6824:   }

6826:   MPI_Comm_rank(comm,&rank);
6827:   if (!rank) {
6828:     count = globalStats.count;
6829:     min   = globalStats.min;
6830:     max   = globalStats.max;
6831:     mean  = globalStats.sum / globalStats.count;
6832:     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
6833:   }

6835:   if (output) {
6836:     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);
6837:   }
6838:   PetscFree2(J,invJ);

6840:   DMGetCoarseDM(dm,&dmCoarse);
6841:   if (dmCoarse) {
6842:     PetscBool isplex;

6844:     PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
6845:     if (isplex) {
6846:       DMPlexCheckCellShape(dmCoarse,output);
6847:     }
6848:   }
6849:   return(0);
6850: }

6852: /* Pointwise interpolation
6853:      Just code FEM for now
6854:      u^f = I u^c
6855:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6856:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6857:      I_{ij} = psi^f_i phi^c_j
6858: */
6859: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6860: {
6861:   PetscSection   gsc, gsf;
6862:   PetscInt       m, n;
6863:   void          *ctx;
6864:   DM             cdm;
6865:   PetscBool      regular, ismatis;

6869:   DMGetGlobalSection(dmFine, &gsf);
6870:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6871:   DMGetGlobalSection(dmCoarse, &gsc);
6872:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6874:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
6875:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6876:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6877:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
6878:   DMGetApplicationContext(dmFine, &ctx);

6880:   DMGetCoarseDM(dmFine, &cdm);
6881:   DMPlexGetRegularRefinement(dmFine, &regular);
6882:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6883:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6884:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6885:   if (scaling) {
6886:     /* Use naive scaling */
6887:     DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6888:   }
6889:   return(0);
6890: }

6892: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6893: {
6895:   VecScatter     ctx;

6898:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6899:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6900:   VecScatterDestroy(&ctx);
6901:   return(0);
6902: }

6904: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6905: {
6906:   PetscSection   gsc, gsf;
6907:   PetscInt       m, n;
6908:   void          *ctx;
6909:   DM             cdm;
6910:   PetscBool      regular;

6914:   DMGetGlobalSection(dmFine, &gsf);
6915:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6916:   DMGetGlobalSection(dmCoarse, &gsc);
6917:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6919:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6920:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6921:   MatSetType(*mass, dmCoarse->mattype);
6922:   DMGetApplicationContext(dmFine, &ctx);

6924:   DMGetCoarseDM(dmFine, &cdm);
6925:   DMPlexGetRegularRefinement(dmFine, &regular);
6926:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6927:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6928:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6929:   return(0);
6930: }

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

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

6938:   Output Parameter:
6939: . regular - The flag

6941:   Level: intermediate

6943: .seealso: DMPlexSetRegularRefinement()
6944: @*/
6945: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6946: {
6950:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6951:   return(0);
6952: }

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

6957:   Input Parameters:
6958: + dm - The DMPlex object
6959: - regular - The flag

6961:   Level: intermediate

6963: .seealso: DMPlexGetRegularRefinement()
6964: @*/
6965: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6966: {
6969:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6970:   return(0);
6971: }

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

6978:   not collective

6980:   Input Parameters:
6981: . dm - The DMPlex object

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


6988:   Level: intermediate

6990: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6991: @*/
6992: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6993: {
6994:   DM_Plex *plex = (DM_Plex *)dm->data;

6999:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7000:   if (anchorSection) *anchorSection = plex->anchorSection;
7001:   if (anchorIS) *anchorIS = plex->anchorIS;
7002:   return(0);
7003: }

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

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

7013:   collective on dm

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

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

7022:   Level: intermediate

7024: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7025: @*/
7026: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7027: {
7028:   DM_Plex        *plex = (DM_Plex *)dm->data;
7029:   PetscMPIInt    result;

7034:   if (anchorSection) {
7036:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7037:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7038:   }
7039:   if (anchorIS) {
7041:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7042:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7043:   }

7045:   PetscObjectReference((PetscObject)anchorSection);
7046:   PetscSectionDestroy(&plex->anchorSection);
7047:   plex->anchorSection = anchorSection;

7049:   PetscObjectReference((PetscObject)anchorIS);
7050:   ISDestroy(&plex->anchorIS);
7051:   plex->anchorIS = anchorIS;

7053: #if defined(PETSC_USE_DEBUG)
7054:   if (anchorIS && anchorSection) {
7055:     PetscInt size, a, pStart, pEnd;
7056:     const PetscInt *anchors;

7058:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7059:     ISGetLocalSize(anchorIS,&size);
7060:     ISGetIndices(anchorIS,&anchors);
7061:     for (a = 0; a < size; a++) {
7062:       PetscInt p;

7064:       p = anchors[a];
7065:       if (p >= pStart && p < pEnd) {
7066:         PetscInt dof;

7068:         PetscSectionGetDof(anchorSection,p,&dof);
7069:         if (dof) {
7070:           PetscErrorCode ierr2;

7072:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7073:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7074:         }
7075:       }
7076:     }
7077:     ISRestoreIndices(anchorIS,&anchors);
7078:   }
7079: #endif
7080:   /* reset the generic constraints */
7081:   DMSetDefaultConstraints(dm,NULL,NULL);
7082:   return(0);
7083: }

7085: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7086: {
7087:   PetscSection anchorSection;
7088:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

7093:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7094:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
7095:   PetscSectionGetNumFields(section,&numFields);
7096:   if (numFields) {
7097:     PetscInt f;
7098:     PetscSectionSetNumFields(*cSec,numFields);

7100:     for (f = 0; f < numFields; f++) {
7101:       PetscInt numComp;

7103:       PetscSectionGetFieldComponents(section,f,&numComp);
7104:       PetscSectionSetFieldComponents(*cSec,f,numComp);
7105:     }
7106:   }
7107:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7108:   PetscSectionGetChart(section,&sStart,&sEnd);
7109:   pStart = PetscMax(pStart,sStart);
7110:   pEnd   = PetscMin(pEnd,sEnd);
7111:   pEnd   = PetscMax(pStart,pEnd);
7112:   PetscSectionSetChart(*cSec,pStart,pEnd);
7113:   for (p = pStart; p < pEnd; p++) {
7114:     PetscSectionGetDof(anchorSection,p,&dof);
7115:     if (dof) {
7116:       PetscSectionGetDof(section,p,&dof);
7117:       PetscSectionSetDof(*cSec,p,dof);
7118:       for (f = 0; f < numFields; f++) {
7119:         PetscSectionGetFieldDof(section,p,f,&dof);
7120:         PetscSectionSetFieldDof(*cSec,p,f,dof);
7121:       }
7122:     }
7123:   }
7124:   PetscSectionSetUp(*cSec);
7125:   return(0);
7126: }

7128: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7129: {
7130:   PetscSection aSec;
7131:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7132:   const PetscInt *anchors;
7133:   PetscInt numFields, f;
7134:   IS aIS;

7139:   PetscSectionGetStorageSize(cSec, &m);
7140:   PetscSectionGetStorageSize(section, &n);
7141:   MatCreate(PETSC_COMM_SELF,cMat);
7142:   MatSetSizes(*cMat,m,n,m,n);
7143:   MatSetType(*cMat,MATSEQAIJ);
7144:   DMPlexGetAnchors(dm,&aSec,&aIS);
7145:   ISGetIndices(aIS,&anchors);
7146:   /* cSec will be a subset of aSec and section */
7147:   PetscSectionGetChart(cSec,&pStart,&pEnd);
7148:   PetscMalloc1(m+1,&i);
7149:   i[0] = 0;
7150:   PetscSectionGetNumFields(section,&numFields);
7151:   for (p = pStart; p < pEnd; p++) {
7152:     PetscInt rDof, rOff, r;

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

7200:             a = anchors[rOff + r];
7201:             PetscSectionGetFieldDof(section,a,f,&aDof);
7202:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7203:             for (s = 0; s < aDof; s++) {
7204:               j[offset++] = aOff + s;
7205:             }
7206:           }
7207:         }
7208:       }
7209:     }
7210:     else {
7211:       PetscSectionGetDof(cSec,p,&dof);
7212:       for (q = 0; q < dof; q++) {
7213:         PetscInt rDof, rOff, r;
7214:         PetscSectionGetDof(aSec,p,&rDof);
7215:         PetscSectionGetOffset(aSec,p,&rOff);
7216:         for (r = 0; r < rDof; r++) {
7217:           PetscInt s;

7219:           a = anchors[rOff + r];
7220:           PetscSectionGetDof(section,a,&aDof);
7221:           PetscSectionGetOffset(section,a,&aOff);
7222:           for (s = 0; s < aDof; s++) {
7223:             j[offset++] = aOff + s;
7224:           }
7225:         }
7226:       }
7227:     }
7228:   }
7229:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7230:   PetscFree(i);
7231:   PetscFree(j);
7232:   ISRestoreIndices(aIS,&anchors);
7233:   return(0);
7234: }

7236: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7237: {
7238:   DM_Plex        *plex = (DM_Plex *)dm->data;
7239:   PetscSection   anchorSection, section, cSec;
7240:   Mat            cMat;

7245:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7246:   if (anchorSection) {
7247:     PetscInt Nf;

7249:     DMGetSection(dm,&section);
7250:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7251:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7252:     DMGetNumFields(dm,&Nf);
7253:     if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7254:     DMSetDefaultConstraints(dm,cSec,cMat);
7255:     PetscSectionDestroy(&cSec);
7256:     MatDestroy(&cMat);
7257:   }
7258:   return(0);
7259: }

7261: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7262: {
7263:   IS             subis;
7264:   PetscSection   section, subsection;

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

7289:     DMPlexCreateSubpointIS(*subdm, &spIS);
7290:     ISGetIndices(spIS, &spmap);
7291:     PetscSectionGetNumFields(section, &Nf);
7292:     DMGetDefaultGlobalSection(dm, &sectionGlobal);
7293:     DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);
7294:     PetscSectionGetChart(subsection, &pStart, &pEnd);
7295:     for (p = pStart; p < pEnd; ++p) {
7296:       PetscInt gdof, pSubSize  = 0;

7298:       PetscSectionGetDof(sectionGlobal, p, &gdof);
7299:       if (gdof > 0) {
7300:         for (f = 0; f < Nf; ++f) {
7301:           PetscInt fdof, fcdof;

7303:           PetscSectionGetFieldDof(subsection, p, f, &fdof);
7304:           PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7305:           pSubSize += fdof-fcdof;
7306:         }
7307:         subSize += pSubSize;
7308:         if (pSubSize) {
7309:           if (bs < 0) {
7310:             bs = pSubSize;
7311:           } else if (bs != pSubSize) {
7312:             /* Layout does not admit a pointwise block size */
7313:             bs = 1;
7314:           }
7315:         }
7316:       }
7317:     }
7318:     /* Must have same blocksize on all procs (some might have no points) */
7319:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7320:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7321:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7322:     else                            {bs = bsMinMax[0];}
7323:     PetscMalloc1(subSize, &subIndices);
7324:     for (p = pStart; p < pEnd; ++p) {
7325:       PetscInt gdof, goff;

7327:       PetscSectionGetDof(subsectionGlobal, p, &gdof);
7328:       if (gdof > 0) {
7329:         const PetscInt point = spmap[p];

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

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

7370:       (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7371:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7372:       MatNullSpaceDestroy(&nullSpace);
7373:     }
7374:   }
7375:   return(0);
7376: }