Actual source code: plex.c

petsc-master 2018-05-24
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, PETSCPARTITIONER_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;

 42:   DMGetDimension(dm, &dim);
 43:   DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
 44:   if (cMax >= 0 || fMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle hybrid meshes yet");
 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:         cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
 57:       break;
 58:       case 4:
 59:         cellRefiner = REFINER_NOOP;
 60:       break;
 61:       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
 62:       }
 63:     break;
 64:     case 3:
 65:       switch (coneSize) {
 66:       case 4:
 67:         cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
 68:       break;
 69:       case 6:
 70:         cellRefiner = REFINER_NOOP;
 71:       break;
 72:       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
 73:       }
 74:     break;
 75:     default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
 76:     }
 77:   }
 78:   /* return if we don't need to refine */
 79:   lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
 80:   MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
 81:   if (allnoop) {
 82:     *dmRefined = NULL;
 83:     return(0);
 84:   }
 85:   DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
 86:   DMCopyBoundary(dm, *dmRefined);
 87:   DMGetCoordinatesLocalized(dm, &localized);
 88:   if (localized) {
 89:     DMLocalizeCoordinates(*dmRefined);
 90:   }
 91:   return(0);
 92: }

 94: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
 95: {
 96:   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior;
 97:   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];

101:   *ft  = PETSC_VTK_POINT_FIELD;
102:   DMGetDimension(dm, &dim);
103:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
104:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
105:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
106:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
107:   PetscSectionGetChart(section, &pStart, &pEnd);
108:   if (field >= 0) {
109:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);}
110:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);}
111:   } else {
112:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vcdof[0]);}
113:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &vcdof[1]);}
114:   }
115:   MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
116:   if (globalvcdof[0]) {
117:     *sStart = vStart;
118:     *sEnd   = vEnd;
119:     if (globalvcdof[0] == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
120:     else                       *ft = PETSC_VTK_POINT_FIELD;
121:   } else if (globalvcdof[1]) {
122:     *sStart = cStart;
123:     *sEnd   = cEnd;
124:     if (globalvcdof[1] == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
125:     else                       *ft = PETSC_VTK_CELL_FIELD;
126:   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
127:   return(0);
128: }

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

148:   PetscViewerDrawGetDraw(viewer, 0, &draw);
149:   PetscDrawIsNull(draw, &isnull);
150:   if (isnull) return(0);

152:   VecGetDM(v, &dm);
153:   DMGetCoordinateDim(dm, &dim);
154:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
155:   DMGetDefaultSection(dm, &s);
156:   PetscSectionGetNumFields(s, &Nf);
157:   DMGetCoarsenLevel(dm, &level);
158:   DMGetCoordinateDM(dm, &cdm);
159:   DMGetDefaultSection(cdm, &coordSection);
160:   DMGetCoordinatesLocal(dm, &coordinates);
161:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
162:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

164:   PetscObjectGetName((PetscObject) v, &name);
165:   DMGetOutputSequenceNumber(dm, &step, &time);

167:   VecGetLocalSize(coordinates, &N);
168:   VecGetArrayRead(coordinates, &coords);
169:   for (c = 0; c < N; c += dim) {
170:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
171:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
172:   }
173:   VecRestoreArrayRead(coordinates, &coords);
174:   PetscDrawClear(draw);

176:   /* Could implement something like DMDASelectFields() */
177:   for (f = 0; f < Nf; ++f) {
178:     DM   fdm = dm;
179:     Vec  fv  = v;
180:     IS   fis;
181:     char prefix[PETSC_MAX_PATH_LEN];
182:     const char *fname;

184:     PetscSectionGetFieldComponents(s, f, &Nc);
185:     PetscSectionGetFieldName(s, f, &fname);

187:     if (v->hdr.prefix) {PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));}
188:     else               {prefix[0] = '\0';}
189:     if (Nf > 1) {
190:       DMCreateSubDM(dm, 1, &f, &fis, &fdm);
191:       VecGetSubVector(v, fis, &fv);
192:       PetscStrlcat(prefix, fname,sizeof(prefix));
193:       PetscStrlcat(prefix, "_",sizeof(prefix));
194:     }
195:     for (comp = 0; comp < Nc; ++comp, ++w) {
196:       PetscInt nmax = 2;

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

203:       /* TODO Get max and min only for this component */
204:       PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
205:       if (!flg) {
206:         VecMin(fv, NULL, &vbound[0]);
207:         VecMax(fv, NULL, &vbound[1]);
208:         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
209:       }
210:       PetscDrawGetPopup(draw, &popup);
211:       PetscDrawScalePopup(popup, vbound[0], vbound[1]);
212:       PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);

214:       VecGetArrayRead(fv, &array);
215:       for (c = cStart; c < cEnd; ++c) {
216:         PetscScalar *coords = NULL, *a = NULL;
217:         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};

219:         DMPlexPointLocalRead(fdm, c, array, &a);
220:         if (a) {
221:           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
222:           color[1] = color[2] = color[3] = color[0];
223:         } else {
224:           PetscScalar *vals = NULL;
225:           PetscInt     numVals, va;

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

269: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
270: {
271:   DM                      dm;
272:   Vec                     locv;
273:   const char              *name;
274:   PetscSection            section;
275:   PetscInt                pStart, pEnd;
276:   PetscViewerVTKFieldType ft;
277:   PetscErrorCode          ierr;

280:   VecGetDM(v, &dm);
281:   DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
282:   PetscObjectGetName((PetscObject) v, &name);
283:   PetscObjectSetName((PetscObject) locv, name);
284:   VecCopy(v, locv);
285:   DMGetDefaultSection(dm, &section);
286:   DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
287:   PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) locv);
288:   return(0);
289: }

291: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
292: {
293:   DM             dm;
294:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

298:   VecGetDM(v, &dm);
299:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
300:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
301:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
302:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
303:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
304:   if (isvtk || ishdf5 || isdraw || isglvis) {
305:     PetscInt    i,numFields;
306:     PetscObject fe;
307:     PetscBool   fem = PETSC_FALSE;
308:     Vec         locv = v;
309:     const char  *name;
310:     PetscInt    step;
311:     PetscReal   time;

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

345:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
346:     if (isseq) {VecView_Seq(v, viewer);}
347:     else       {VecView_MPI(v, viewer);}
348:   }
349:   return(0);
350: }

352: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
353: {
354:   DM             dm;
355:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

359:   VecGetDM(v, &dm);
360:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
361:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
362:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
363:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
364:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
365:   if (isvtk || isdraw || isglvis) {
366:     Vec         locv;
367:     const char *name;

369:     DMGetLocalVector(dm, &locv);
370:     PetscObjectGetName((PetscObject) v, &name);
371:     PetscObjectSetName((PetscObject) locv, name);
372:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
373:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
374:     VecView_Plex_Local(locv, viewer);
375:     DMRestoreLocalVector(dm, &locv);
376:   } else if (ishdf5) {
377: #if defined(PETSC_HAVE_HDF5)
378:     VecView_Plex_HDF5_Internal(v, viewer);
379: #else
380:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
381: #endif
382:   } else {
383:     PetscBool isseq;

385:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
386:     if (isseq) {VecView_Seq(v, viewer);}
387:     else       {VecView_MPI(v, viewer);}
388:   }
389:   return(0);
390: }

392: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
393: {
394:   DM                dm;
395:   MPI_Comm          comm;
396:   PetscViewerFormat format;
397:   Vec               v;
398:   PetscBool         isvtk, ishdf5;
399:   PetscErrorCode    ierr;

402:   VecGetDM(originalv, &dm);
403:   PetscObjectGetComm((PetscObject) originalv, &comm);
404:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
405:   PetscViewerGetFormat(viewer, &format);
406:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
407:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
408:   if (format == PETSC_VIEWER_NATIVE) {
409:     const char *vecname;
410:     PetscInt    n, nroots;

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

438:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
439:     if (isseq) {VecView_Seq(v, viewer);}
440:     else       {VecView_MPI(v, viewer);}
441:   }
442:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
443:   return(0);
444: }

446: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
447: {
448:   DM             dm;
449:   PetscBool      ishdf5;

453:   VecGetDM(v, &dm);
454:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
455:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
456:   if (ishdf5) {
457:     DM          dmBC;
458:     Vec         gv;
459:     const char *name;

461:     DMGetOutputDM(dm, &dmBC);
462:     DMGetGlobalVector(dmBC, &gv);
463:     PetscObjectGetName((PetscObject) v, &name);
464:     PetscObjectSetName((PetscObject) gv, name);
465:     VecLoad_Default(gv, viewer);
466:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
467:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
468:     DMRestoreGlobalVector(dmBC, &gv);
469:   } else {
470:     VecLoad_Default(v, viewer);
471:   }
472:   return(0);
473: }

475: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
476: {
477:   DM             dm;
478:   PetscBool      ishdf5;

482:   VecGetDM(v, &dm);
483:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
484:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
485:   if (ishdf5) {
486: #if defined(PETSC_HAVE_HDF5)
487:     VecLoad_Plex_HDF5_Internal(v, viewer);
488: #else
489:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
490: #endif
491:   } else {
492:     VecLoad_Default(v, viewer);
493:   }
494:   return(0);
495: }

497: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
498: {
499:   DM                dm;
500:   PetscViewerFormat format;
501:   PetscBool         ishdf5;
502:   PetscErrorCode    ierr;

505:   VecGetDM(originalv, &dm);
506:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
507:   PetscViewerGetFormat(viewer, &format);
508:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
509:   if (format == PETSC_VIEWER_NATIVE) {
510:     if (dm->sfNatural) {
511:       if (ishdf5) {
512: #if defined(PETSC_HAVE_HDF5)
513:         Vec         v;
514:         const char *vecname;

516:         DMGetGlobalVector(dm, &v);
517:         PetscObjectGetName((PetscObject) originalv, &vecname);
518:         PetscObjectSetName((PetscObject) v, vecname);
519:         VecLoad_Plex_HDF5_Native_Internal(v, viewer);
520:         DMPlexNaturalToGlobalBegin(dm, v, originalv);
521:         DMPlexNaturalToGlobalEnd(dm, v, originalv);
522:         DMRestoreGlobalVector(dm, &v);
523: #else
524:         SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
525: #endif
526:       } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
527:     }
528:   }
529:   return(0);
530: }

532: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
533: {
534:   PetscSection       coordSection;
535:   Vec                coordinates;
536:   DMLabel            depthLabel;
537:   const char        *name[4];
538:   const PetscScalar *a;
539:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
540:   PetscErrorCode     ierr;

543:   DMGetDimension(dm, &dim);
544:   DMGetCoordinatesLocal(dm, &coordinates);
545:   DMGetCoordinateSection(dm, &coordSection);
546:   DMPlexGetDepthLabel(dm, &depthLabel);
547:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
548:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
549:   VecGetArrayRead(coordinates, &a);
550:   name[0]     = "vertex";
551:   name[1]     = "edge";
552:   name[dim-1] = "face";
553:   name[dim]   = "cell";
554:   for (c = cStart; c < cEnd; ++c) {
555:     PetscInt *closure = NULL;
556:     PetscInt  closureSize, cl;

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

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

587: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
588: {
589:   DM_Plex          *mesh = (DM_Plex*) dm->data;
590:   DM                cdm;
591:   DMLabel           markers;
592:   PetscSection      coordSection;
593:   Vec               coordinates;
594:   PetscViewerFormat format;
595:   PetscErrorCode    ierr;

598:   DMGetCoordinateDM(dm, &cdm);
599:   DMGetDefaultSection(cdm, &coordSection);
600:   DMGetCoordinatesLocal(dm, &coordinates);
601:   PetscViewerGetFormat(viewer, &format);
602:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
603:     const char *name;
604:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
605:     PetscInt    pStart, pEnd, p;
606:     PetscMPIInt rank, size;

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

624:       PetscSectionGetDof(mesh->supportSection, p, &dof);
625:       PetscSectionGetOffset(mesh->supportSection, p, &off);
626:       for (s = off; s < off+dof; ++s) {
627:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
628:       }
629:     }
630:     PetscViewerFlush(viewer);
631:     PetscViewerASCIIPrintf(viewer, "Cones:\n", name);
632:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);
633:     for (p = pStart; p < pEnd; ++p) {
634:       PetscInt dof, off, c;

636:       PetscSectionGetDof(mesh->coneSection, p, &dof);
637:       PetscSectionGetOffset(mesh->coneSection, p, &off);
638:       for (c = off; c < off+dof; ++c) {
639:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
640:       }
641:     }
642:     PetscViewerFlush(viewer);
643:     PetscViewerASCIIPopSynchronized(viewer);
644:     PetscSectionGetChart(coordSection, &pStart, NULL);
645:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
646:     DMGetLabel(dm, "marker", &markers);
647:     DMLabelView(markers,viewer);
648:     if (size > 1) {
649:       PetscSF sf;

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

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

718:       PetscSectionGetDof(coordSection, v, &dof);
719:       PetscSectionGetOffset(coordSection, v, &off);
720:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
721:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
722:       for (d = 0; d < dof; ++d) {
723:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
724:         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
725:       }
726:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
727:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
728:       for (d = 0; d < dof; ++d) {
729:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
730:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
731:       }
732:       color = colors[rank%numColors];
733:       for (l = 0; l < numLabels; ++l) {
734:         PetscInt val;
735:         DMGetLabelValue(dm, names[l], v, &val);
736:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
737:       }
738:       if (useNumbers) {
739:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
740:       } else {
741:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
742:       }
743:     }
744:     VecRestoreArray(coordinates, &coords);
745:     PetscViewerFlush(viewer);
746:     /* Plot edges */
747:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
748:     if (dim < 3 && useNumbers) {
749:       VecGetArray(coordinates, &coords);
750:       PetscViewerASCIIPrintf(viewer, "\\path\n");
751:       for (e = eStart; e < eEnd; ++e) {
752:         const PetscInt *cone;
753:         PetscInt        coneSize, offA, offB, dof, d;

755:         DMPlexGetConeSize(dm, e, &coneSize);
756:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
757:         DMPlexGetCone(dm, e, &cone);
758:         PetscSectionGetDof(coordSection, cone[0], &dof);
759:         PetscSectionGetOffset(coordSection, cone[0], &offA);
760:         PetscSectionGetOffset(coordSection, cone[1], &offB);
761:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
762:         for (d = 0; d < dof; ++d) {
763:           tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
764:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
765:         }
766:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
767:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
768:         for (d = 0; d < dof; ++d) {
769:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
770:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
771:         }
772:         color = colors[rank%numColors];
773:         for (l = 0; l < numLabels; ++l) {
774:           PetscInt val;
775:           DMGetLabelValue(dm, names[l], v, &val);
776:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
777:         }
778:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
779:       }
780:       VecRestoreArray(coordinates, &coords);
781:       PetscViewerFlush(viewer);
782:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
783:     }
784:     /* Plot cells */
785:     if (dim == 3 || !useNumbers) {
786:       for (e = eStart; e < eEnd; ++e) {
787:         const PetscInt *cone;

789:         color = colors[rank%numColors];
790:         for (l = 0; l < numLabels; ++l) {
791:           PetscInt val;
792:           DMGetLabelValue(dm, names[l], e, &val);
793:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
794:         }
795:         DMPlexGetCone(dm, e, &cone);
796:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
797:       }
798:     } else {
799:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
800:       for (c = cStart; c < cEnd; ++c) {
801:         PetscInt *closure = NULL;
802:         PetscInt  closureSize, firstPoint = -1;

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

809:           if ((point < vStart) || (point >= vEnd)) continue;
810:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
811:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
812:           if (firstPoint < 0) firstPoint = point;
813:         }
814:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
815:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
816:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
817:       }
818:     }
819:     PetscViewerFlush(viewer);
820:     PetscViewerASCIIPopSynchronized(viewer);
821:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
822:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
823:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
824:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
825:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
826:     PetscFree3(names, colors, lcolors);
827:   } else {
828:     MPI_Comm    comm;
829:     PetscInt   *sizes, *hybsizes;
830:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
831:     PetscInt    pStart, pEnd, p;
832:     PetscInt    numLabels, l;
833:     const char *name;
834:     PetscMPIInt size;

836:     PetscObjectGetComm((PetscObject)dm,&comm);
837:     MPI_Comm_size(comm, &size);
838:     DMGetDimension(dm, &dim);
839:     DMPlexGetVTKCellHeight(dm, &cellHeight);
840:     PetscObjectGetName((PetscObject) dm, &name);
841:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
842:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
843:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
844:     DMPlexGetDepth(dm, &locDepth);
845:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
846:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
847:     PetscMalloc2(size,&sizes,size,&hybsizes);
848:     if (depth == 1) {
849:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
850:       pEnd = pEnd - pStart;
851:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
852:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
853:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
854:       PetscViewerASCIIPrintf(viewer, "\n");
855:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
856:       pEnd = pEnd - pStart;
857:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
858:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
859:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
860:       PetscViewerASCIIPrintf(viewer, "\n");
861:     } else {
862:       PetscMPIInt rank;
863:       MPI_Comm_rank(comm, &rank);
864:       for (d = 0; d <= dim; d++) {
865:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
866:         pEnd    -= pStart;
867:         pMax[d] -= pStart;
868:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
869:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
870:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
871:         for (p = 0; p < size; ++p) {
872:           if (!rank) {
873:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
874:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
875:           }
876:         }
877:         PetscViewerASCIIPrintf(viewer, "\n");
878:       }
879:     }
880:     PetscFree2(sizes,hybsizes);
881:     DMGetNumLabels(dm, &numLabels);
882:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
883:     for (l = 0; l < numLabels; ++l) {
884:       DMLabel         label;
885:       const char     *name;
886:       IS              valueIS;
887:       const PetscInt *values;
888:       PetscInt        numValues, v;

890:       DMGetLabelName(dm, l, &name);
891:       DMGetLabel(dm, name, &label);
892:       DMLabelGetNumValues(label, &numValues);
893:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
894:       DMLabelGetValueIS(label, &valueIS);
895:       ISGetIndices(valueIS, &values);
896:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
897:       for (v = 0; v < numValues; ++v) {
898:         PetscInt size;

900:         DMLabelGetStratumSize(label, values[v], &size);
901:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
902:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
903:       }
904:       PetscViewerASCIIPrintf(viewer, ")\n");
905:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
906:       ISRestoreIndices(valueIS, &values);
907:       ISDestroy(&valueIS);
908:     }
909:     DMGetCoarseDM(dm, &cdm);
910:     if (cdm) {
911:       PetscViewerASCIIPushTab(viewer);
912:       DMPlexView_Ascii(cdm, viewer);
913:       PetscViewerASCIIPopTab(viewer);
914:     }
915:   }
916:   return(0);
917: }

919: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
920: {
921:   PetscDraw          draw;
922:   DM                 cdm;
923:   PetscSection       coordSection;
924:   Vec                coordinates;
925:   const PetscScalar *coords;
926:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
927:   PetscBool          isnull;
928:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
929:   PetscErrorCode     ierr;

932:   DMGetCoordinateDim(dm, &dim);
933:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
934:   DMGetCoordinateDM(dm, &cdm);
935:   DMGetDefaultSection(cdm, &coordSection);
936:   DMGetCoordinatesLocal(dm, &coordinates);
937:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
938:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

940:   PetscViewerDrawGetDraw(viewer, 0, &draw);
941:   PetscDrawIsNull(draw, &isnull);
942:   if (isnull) return(0);
943:   PetscDrawSetTitle(draw, "Mesh");

945:   VecGetLocalSize(coordinates, &N);
946:   VecGetArrayRead(coordinates, &coords);
947:   for (c = 0; c < N; c += dim) {
948:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
949:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
950:   }
951:   VecRestoreArrayRead(coordinates, &coords);
952:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
953:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
954:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
955:   PetscDrawClear(draw);

957:   for (c = cStart; c < cEnd; ++c) {
958:     PetscScalar *coords = NULL;
959:     PetscInt     numCoords,coneSize;

961:     DMPlexGetConeSize(dm, c, &coneSize);
962:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
963:     switch (coneSize) {
964:     case 3:
965:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
966:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
967:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
968:       break;
969:     case 4:
970:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
971:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
972:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
973:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
974:       break;
975:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
976:     }
977:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
978:   }
979:   PetscDrawFlush(draw);
980:   PetscDrawPause(draw);
981:   PetscDrawSave(draw);
982:   return(0);
983: }

985: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
986: {
987:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
988:   PetscErrorCode    ierr;

993:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
994:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
995:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
996:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
997:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
998:   if (iascii) {
999:     PetscViewerFormat format;
1000:     PetscViewerGetFormat(viewer, &format);
1001:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1002:       DMPlexView_GLVis(dm, viewer);
1003:     } else {
1004:       DMPlexView_Ascii(dm, viewer);
1005:     }
1006:   } else if (ishdf5) {
1007: #if defined(PETSC_HAVE_HDF5)
1008:     DMPlexView_HDF5_Internal(dm, viewer);
1009: #else
1010:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1011: #endif
1012:   } else if (isvtk) {
1013:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
1014:   } else if (isdraw) {
1015:     DMPlexView_Draw(dm, viewer);
1016:   } else if (isglvis) {
1017:     DMPlexView_GLVis(dm, viewer);
1018:   }
1019:   /* Optionally view the partition */
1020:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1021:   if (flg) {
1022:     Vec ranks;
1023:     DMPlexCreateRankField(dm, &ranks);
1024:     VecView(ranks, viewer);
1025:     VecDestroy(&ranks);
1026:   }
1027:   return(0);
1028: }

1030: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1031: {
1032:   PetscBool      isbinary, ishdf5;

1038:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
1039:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1040:   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
1041:   else if (ishdf5) {
1042: #if defined(PETSC_HAVE_HDF5)
1043:     PetscViewerFormat format;
1044:     PetscViewerGetFormat(viewer, &format);
1045:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1046:       DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1047:     } else {
1048:       DMPlexLoad_HDF5_Internal(dm, viewer);
1049:     }
1050: #else
1051:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1052: #endif
1053:   }
1054:   return(0);
1055: }

1057: PetscErrorCode DMDestroy_Plex(DM dm)
1058: {
1059:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1063:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1064:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1065:   if (--mesh->refct > 0) return(0);
1066:   PetscSectionDestroy(&mesh->coneSection);
1067:   PetscFree(mesh->cones);
1068:   PetscFree(mesh->coneOrientations);
1069:   PetscSectionDestroy(&mesh->supportSection);
1070:   PetscSectionDestroy(&mesh->subdomainSection);
1071:   PetscFree(mesh->supports);
1072:   PetscFree(mesh->facesTmp);
1073:   PetscFree(mesh->tetgenOpts);
1074:   PetscFree(mesh->triangleOpts);
1075:   PetscPartitionerDestroy(&mesh->partitioner);
1076:   DMLabelDestroy(&mesh->subpointMap);
1077:   ISDestroy(&mesh->globalVertexNumbers);
1078:   ISDestroy(&mesh->globalCellNumbers);
1079:   PetscSectionDestroy(&mesh->anchorSection);
1080:   ISDestroy(&mesh->anchorIS);
1081:   PetscSectionDestroy(&mesh->parentSection);
1082:   PetscFree(mesh->parents);
1083:   PetscFree(mesh->childIDs);
1084:   PetscSectionDestroy(&mesh->childSection);
1085:   PetscFree(mesh->children);
1086:   DMDestroy(&mesh->referenceTree);
1087:   PetscGridHashDestroy(&mesh->lbox);
1088:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1089:   PetscFree(mesh);
1090:   return(0);
1091: }

1093: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1094: {
1095:   PetscSection           sectionGlobal;
1096:   PetscInt               bs = -1, mbs;
1097:   PetscInt               localSize;
1098:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1099:   PetscErrorCode         ierr;
1100:   MatType                mtype;
1101:   ISLocalToGlobalMapping ltog;

1104:   MatInitializePackage();
1105:   mtype = dm->mattype;
1106:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
1107:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1108:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1109:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1110:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1111:   MatSetType(*J, mtype);
1112:   MatSetFromOptions(*J);
1113:   MatGetBlockSize(*J, &mbs);
1114:   if (mbs > 1) bs = mbs;
1115:   PetscStrcmp(mtype, MATSHELL, &isShell);
1116:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1117:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1118:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1119:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1120:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1121:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1122:   PetscStrcmp(mtype, MATIS, &isMatIS);
1123:   if (!isShell) {
1124:     PetscSection subSection;
1125:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1126:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1127:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1134:       DMGetDefaultSection(dm, &section);
1135:       PetscSectionGetStorageSize(section, &size);
1136:       PetscMalloc1(size,&ltogidx);
1137:       DMPlexGetSubdomainSection(dm, &subSection);
1138:     } else {
1139:       DMGetLocalToGlobalMapping(dm,&ltog);
1140:     }
1141:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1142:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1143:       PetscInt bdof;

1145:       PetscSectionGetDof(sectionGlobal, p, &dof);
1146:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1147:       dof  = dof < 0 ? -(dof+1) : dof;
1148:       bdof = cdof && (dof-cdof) ? 1 : dof;
1149:       if (dof) {
1150:         if (bs < 0)          {bs = bdof;}
1151:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1152:       }
1153:       if (isMatIS) {
1154:         PetscInt loff,c,off;
1155:         PetscSectionGetOffset(subSection, p, &loff);
1156:         PetscSectionGetOffset(sectionGlobal, p, &off);
1157:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1158:       }
1159:     }
1160:     /* Must have same blocksize on all procs (some might have no points) */
1161:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1162:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1163:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1164:     else                            {bs = bsMinMax[0];}
1165:     bs = bs < 0 ? 1 : bs;
1166:     if (isMatIS) {
1167:       PetscInt l;
1168:       /* Must reduce indices by blocksize */
1169:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1170:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1171:     }
1172:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1173:     if (isMatIS) {
1174:       ISLocalToGlobalMappingDestroy(&ltog);
1175:     }
1176:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1177:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1178:     PetscFree4(dnz, onz, dnzu, onzu);
1179:   }
1180:   MatSetDM(*J, dm);
1181:   return(0);
1182: }

1184: /*@
1185:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1187:   Not collective

1189:   Input Parameter:
1190: . mesh - The DMPlex

1192:   Output Parameters:
1193: . subsection - The subdomain section

1195:   Level: developer

1197: .seealso:
1198: @*/
1199: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1200: {
1201:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1206:   if (!mesh->subdomainSection) {
1207:     PetscSection section;
1208:     PetscSF      sf;

1210:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1211:     DMGetDefaultSection(dm,&section);
1212:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1213:     PetscSFDestroy(&sf);
1214:   }
1215:   *subsection = mesh->subdomainSection;
1216:   return(0);
1217: }

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

1222:   Not collective

1224:   Input Parameter:
1225: . mesh - The DMPlex

1227:   Output Parameters:
1228: + pStart - The first mesh point
1229: - pEnd   - The upper bound for mesh points

1231:   Level: beginner

1233: .seealso: DMPlexCreate(), DMPlexSetChart()
1234: @*/
1235: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1236: {
1237:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1242:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1243:   return(0);
1244: }

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

1249:   Not collective

1251:   Input Parameters:
1252: + mesh - The DMPlex
1253: . pStart - The first mesh point
1254: - pEnd   - The upper bound for mesh points

1256:   Output Parameters:

1258:   Level: beginner

1260: .seealso: DMPlexCreate(), DMPlexGetChart()
1261: @*/
1262: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1263: {
1264:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1269:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1270:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1271:   return(0);
1272: }

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

1277:   Not collective

1279:   Input Parameters:
1280: + mesh - The DMPlex
1281: - p - The point, which must lie in the chart set with DMPlexSetChart()

1283:   Output Parameter:
1284: . size - The cone size for point p

1286:   Level: beginner

1288: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1289: @*/
1290: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1291: {
1292:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1298:   PetscSectionGetDof(mesh->coneSection, p, size);
1299:   return(0);
1300: }

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

1305:   Not collective

1307:   Input Parameters:
1308: + mesh - The DMPlex
1309: . p - The point, which must lie in the chart set with DMPlexSetChart()
1310: - size - The cone size for point p

1312:   Output Parameter:

1314:   Note:
1315:   This should be called after DMPlexSetChart().

1317:   Level: beginner

1319: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1320: @*/
1321: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1322: {
1323:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1330:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1331:   return(0);
1332: }

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

1337:   Not collective

1339:   Input Parameters:
1340: + mesh - The DMPlex
1341: . p - The point, which must lie in the chart set with DMPlexSetChart()
1342: - size - The additional cone size for point p

1344:   Output Parameter:

1346:   Note:
1347:   This should be called after DMPlexSetChart().

1349:   Level: beginner

1351: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1352: @*/
1353: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1354: {
1355:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1356:   PetscInt       csize;

1361:   PetscSectionAddDof(mesh->coneSection, p, size);
1362:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1364:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1365:   return(0);
1366: }

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

1371:   Not collective

1373:   Input Parameters:
1374: + mesh - The DMPlex
1375: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1380:   Level: beginner

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

1386:   You must also call DMPlexRestoreCone() after you finish using the returned array.

1388: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1389: @*/
1390: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1391: {
1392:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1393:   PetscInt       off;

1399:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1400:   *cone = &mesh->cones[off];
1401:   return(0);
1402: }

1404: /*@
1405:   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

1407:   Not collective

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

1414:   Output Parameter:

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

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

1421:   Level: beginner

1423: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1424: @*/
1425: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1426: {
1427:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1428:   PetscInt       pStart, pEnd;
1429:   PetscInt       dof, off, c;

1434:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1435:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1437:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1438:   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);
1439:   for (c = 0; c < dof; ++c) {
1440:     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);
1441:     mesh->cones[off+c] = cone[c];
1442:   }
1443:   return(0);
1444: }

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

1449:   Not collective

1451:   Input Parameters:
1452: + mesh - The DMPlex
1453: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1461:   Level: beginner

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

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

1469: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1470: @*/
1471: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1472: {
1473:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1474:   PetscInt       off;

1479: #if defined(PETSC_USE_DEBUG)
1480:   {
1481:     PetscInt dof;
1482:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1484:   }
1485: #endif
1486:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1488:   *coneOrientation = &mesh->coneOrientations[off];
1489:   return(0);
1490: }

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

1495:   Not collective

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

1505:   Output Parameter:

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

1510:   Level: beginner

1512: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1513: @*/
1514: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1515: {
1516:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1517:   PetscInt       pStart, pEnd;
1518:   PetscInt       dof, off, c;

1523:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1524:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1526:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1527:   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);
1528:   for (c = 0; c < dof; ++c) {
1529:     PetscInt cdof, o = coneOrientation[c];

1531:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1532:     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);
1533:     mesh->coneOrientations[off+c] = o;
1534:   }
1535:   return(0);
1536: }

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

1541:   Not collective

1543:   Input Parameters:
1544: + mesh - The DMPlex
1545: . p - The point, which must lie in the chart set with DMPlexSetChart()
1546: . conePos - The local index in the cone where the point should be put
1547: - conePoint - The mesh point to insert

1549:   Level: beginner

1551: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1552: @*/
1553: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1554: {
1555:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1556:   PetscInt       pStart, pEnd;
1557:   PetscInt       dof, off;

1562:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1563:   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);
1564:   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);
1565:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1566:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1567:   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);
1568:   mesh->cones[off+conePos] = conePoint;
1569:   return(0);
1570: }

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

1575:   Not collective

1577:   Input Parameters:
1578: + mesh - The DMPlex
1579: . p - The point, which must lie in the chart set with DMPlexSetChart()
1580: . conePos - The local index in the cone where the point should be put
1581: - coneOrientation - The point orientation to insert

1583:   Level: beginner

1585: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1586: @*/
1587: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1588: {
1589:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1590:   PetscInt       pStart, pEnd;
1591:   PetscInt       dof, off;

1596:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1597:   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);
1598:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1599:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1600:   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);
1601:   mesh->coneOrientations[off+conePos] = coneOrientation;
1602:   return(0);
1603: }

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

1608:   Not collective

1610:   Input Parameters:
1611: + mesh - The DMPlex
1612: - p - The point, which must lie in the chart set with DMPlexSetChart()

1614:   Output Parameter:
1615: . size - The support size for point p

1617:   Level: beginner

1619: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1620: @*/
1621: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1622: {
1623:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1629:   PetscSectionGetDof(mesh->supportSection, p, size);
1630:   return(0);
1631: }

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

1636:   Not collective

1638:   Input Parameters:
1639: + mesh - The DMPlex
1640: . p - The point, which must lie in the chart set with DMPlexSetChart()
1641: - size - The support size for point p

1643:   Output Parameter:

1645:   Note:
1646:   This should be called after DMPlexSetChart().

1648:   Level: beginner

1650: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1651: @*/
1652: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1653: {
1654:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1661:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1662:   return(0);
1663: }

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

1668:   Not collective

1670:   Input Parameters:
1671: + mesh - The DMPlex
1672: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1677:   Level: beginner

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

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

1685: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1686: @*/
1687: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1688: {
1689:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1690:   PetscInt       off;

1696:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1697:   *support = &mesh->supports[off];
1698:   return(0);
1699: }

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

1704:   Not collective

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

1711:   Output Parameter:

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

1716:   Level: beginner

1718: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1719: @*/
1720: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1721: {
1722:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1723:   PetscInt       pStart, pEnd;
1724:   PetscInt       dof, off, c;

1729:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1730:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1732:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1733:   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);
1734:   for (c = 0; c < dof; ++c) {
1735:     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);
1736:     mesh->supports[off+c] = support[c];
1737:   }
1738:   return(0);
1739: }

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

1744:   Not collective

1746:   Input Parameters:
1747: + mesh - The DMPlex
1748: . p - The point, which must lie in the chart set with DMPlexSetChart()
1749: . supportPos - The local index in the cone where the point should be put
1750: - supportPoint - The mesh point to insert

1752:   Level: beginner

1754: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1755: @*/
1756: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1757: {
1758:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1759:   PetscInt       pStart, pEnd;
1760:   PetscInt       dof, off;

1765:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1766:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1767:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1768:   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1769:   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);
1770:   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);
1771:   mesh->supports[off+supportPos] = supportPoint;
1772:   return(0);
1773: }

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

1778:   Not collective

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

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

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

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

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

1799:   Level: beginner

1801: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1802: @*/
1803: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1804: {
1805:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1806:   PetscInt       *closure, *fifo;
1807:   const PetscInt *tmp = NULL, *tmpO = NULL;
1808:   PetscInt        tmpSize, t;
1809:   PetscInt        depth       = 0, maxSize;
1810:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1811:   PetscErrorCode  ierr;

1815:   DMPlexGetDepth(dm, &depth);
1816:   /* This is only 1-level */
1817:   if (useCone) {
1818:     DMPlexGetConeSize(dm, p, &tmpSize);
1819:     DMPlexGetCone(dm, p, &tmp);
1820:     DMPlexGetConeOrientation(dm, p, &tmpO);
1821:   } else {
1822:     DMPlexGetSupportSize(dm, p, &tmpSize);
1823:     DMPlexGetSupport(dm, p, &tmp);
1824:   }
1825:   if (depth == 1) {
1826:     if (*points) {
1827:       closure = *points;
1828:     } else {
1829:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1830:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1831:     }
1832:     closure[0] = p; closure[1] = 0;
1833:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1834:       closure[closureSize]   = tmp[t];
1835:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1836:     }
1837:     if (numPoints) *numPoints = closureSize/2;
1838:     if (points)    *points    = closure;
1839:     return(0);
1840:   }
1841:   {
1842:     PetscInt c, coneSeries, s,supportSeries;

1844:     c = mesh->maxConeSize;
1845:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1846:     s = mesh->maxSupportSize;
1847:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1848:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1849:   }
1850:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
1851:   if (*points) {
1852:     closure = *points;
1853:   } else {
1854:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1855:   }
1856:   closure[0] = p; closure[1] = 0;
1857:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1858:     const PetscInt cp = tmp[t];
1859:     const PetscInt co = tmpO ? tmpO[t] : 0;

1861:     closure[closureSize]   = cp;
1862:     closure[closureSize+1] = co;
1863:     fifo[fifoSize]         = cp;
1864:     fifo[fifoSize+1]       = co;
1865:   }
1866:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1867:   while (fifoSize - fifoStart) {
1868:     const PetscInt q   = fifo[fifoStart];
1869:     const PetscInt o   = fifo[fifoStart+1];
1870:     const PetscInt rev = o >= 0 ? 0 : 1;
1871:     const PetscInt off = rev ? -(o+1) : o;

1873:     if (useCone) {
1874:       DMPlexGetConeSize(dm, q, &tmpSize);
1875:       DMPlexGetCone(dm, q, &tmp);
1876:       DMPlexGetConeOrientation(dm, q, &tmpO);
1877:     } else {
1878:       DMPlexGetSupportSize(dm, q, &tmpSize);
1879:       DMPlexGetSupport(dm, q, &tmp);
1880:       tmpO = NULL;
1881:     }
1882:     for (t = 0; t < tmpSize; ++t) {
1883:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1884:       const PetscInt cp = tmp[i];
1885:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1886:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1887:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1888:       PetscInt       co = tmpO ? tmpO[i] : 0;
1889:       PetscInt       c;

1891:       if (rev) {
1892:         PetscInt childSize, coff;
1893:         DMPlexGetConeSize(dm, cp, &childSize);
1894:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1895:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1896:       }
1897:       /* Check for duplicate */
1898:       for (c = 0; c < closureSize; c += 2) {
1899:         if (closure[c] == cp) break;
1900:       }
1901:       if (c == closureSize) {
1902:         closure[closureSize]   = cp;
1903:         closure[closureSize+1] = co;
1904:         fifo[fifoSize]         = cp;
1905:         fifo[fifoSize+1]       = co;
1906:         closureSize           += 2;
1907:         fifoSize              += 2;
1908:       }
1909:     }
1910:     fifoStart += 2;
1911:   }
1912:   if (numPoints) *numPoints = closureSize/2;
1913:   if (points)    *points    = closure;
1914:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
1915:   return(0);
1916: }

1918: /*@C
1919:   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

1921:   Not collective

1923:   Input Parameters:
1924: + mesh - The DMPlex
1925: . p - The point, which must lie in the chart set with DMPlexSetChart()
1926: . orientation - The orientation of the point
1927: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1928: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

1943:   Level: beginner

1945: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1946: @*/
1947: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1948: {
1949:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1950:   PetscInt       *closure, *fifo;
1951:   const PetscInt *tmp = NULL, *tmpO = NULL;
1952:   PetscInt        tmpSize, t;
1953:   PetscInt        depth       = 0, maxSize;
1954:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1955:   PetscErrorCode  ierr;

1959:   DMPlexGetDepth(dm, &depth);
1960:   /* This is only 1-level */
1961:   if (useCone) {
1962:     DMPlexGetConeSize(dm, p, &tmpSize);
1963:     DMPlexGetCone(dm, p, &tmp);
1964:     DMPlexGetConeOrientation(dm, p, &tmpO);
1965:   } else {
1966:     DMPlexGetSupportSize(dm, p, &tmpSize);
1967:     DMPlexGetSupport(dm, p, &tmp);
1968:   }
1969:   if (depth == 1) {
1970:     if (*points) {
1971:       closure = *points;
1972:     } else {
1973:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1974:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1975:     }
1976:     closure[0] = p; closure[1] = ornt;
1977:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1978:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1979:       closure[closureSize]   = tmp[i];
1980:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1981:     }
1982:     if (numPoints) *numPoints = closureSize/2;
1983:     if (points)    *points    = closure;
1984:     return(0);
1985:   }
1986:   {
1987:     PetscInt c, coneSeries, s,supportSeries;

1989:     c = mesh->maxConeSize;
1990:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1991:     s = mesh->maxSupportSize;
1992:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1993:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1994:   }
1995:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
1996:   if (*points) {
1997:     closure = *points;
1998:   } else {
1999:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2000:   }
2001:   closure[0] = p; closure[1] = ornt;
2002:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2003:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2004:     const PetscInt cp = tmp[i];
2005:     PetscInt       co = tmpO ? tmpO[i] : 0;

2007:     if (ornt < 0) {
2008:       PetscInt childSize, coff;
2009:       DMPlexGetConeSize(dm, cp, &childSize);
2010:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2011:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2012:     }
2013:     closure[closureSize]   = cp;
2014:     closure[closureSize+1] = co;
2015:     fifo[fifoSize]         = cp;
2016:     fifo[fifoSize+1]       = co;
2017:   }
2018:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2019:   while (fifoSize - fifoStart) {
2020:     const PetscInt q   = fifo[fifoStart];
2021:     const PetscInt o   = fifo[fifoStart+1];
2022:     const PetscInt rev = o >= 0 ? 0 : 1;
2023:     const PetscInt off = rev ? -(o+1) : o;

2025:     if (useCone) {
2026:       DMPlexGetConeSize(dm, q, &tmpSize);
2027:       DMPlexGetCone(dm, q, &tmp);
2028:       DMPlexGetConeOrientation(dm, q, &tmpO);
2029:     } else {
2030:       DMPlexGetSupportSize(dm, q, &tmpSize);
2031:       DMPlexGetSupport(dm, q, &tmp);
2032:       tmpO = NULL;
2033:     }
2034:     for (t = 0; t < tmpSize; ++t) {
2035:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2036:       const PetscInt cp = tmp[i];
2037:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2038:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2039:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2040:       PetscInt       co = tmpO ? tmpO[i] : 0;
2041:       PetscInt       c;

2043:       if (rev) {
2044:         PetscInt childSize, coff;
2045:         DMPlexGetConeSize(dm, cp, &childSize);
2046:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2047:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2048:       }
2049:       /* Check for duplicate */
2050:       for (c = 0; c < closureSize; c += 2) {
2051:         if (closure[c] == cp) break;
2052:       }
2053:       if (c == closureSize) {
2054:         closure[closureSize]   = cp;
2055:         closure[closureSize+1] = co;
2056:         fifo[fifoSize]         = cp;
2057:         fifo[fifoSize+1]       = co;
2058:         closureSize           += 2;
2059:         fifoSize              += 2;
2060:       }
2061:     }
2062:     fifoStart += 2;
2063:   }
2064:   if (numPoints) *numPoints = closureSize/2;
2065:   if (points)    *points    = closure;
2066:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2067:   return(0);
2068: }

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

2073:   Not collective

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

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

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

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

2091:   Level: beginner

2093: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2094: @*/
2095: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2096: {

2103:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2104:   if (numPoints) *numPoints = 0;
2105:   return(0);
2106: }

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

2111:   Not collective

2113:   Input Parameter:
2114: . mesh - The DMPlex

2116:   Output Parameters:
2117: + maxConeSize - The maximum number of in-edges
2118: - maxSupportSize - The maximum number of out-edges

2120:   Level: beginner

2122: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2123: @*/
2124: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2125: {
2126:   DM_Plex *mesh = (DM_Plex*) dm->data;

2130:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2131:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2132:   return(0);
2133: }

2135: PetscErrorCode DMSetUp_Plex(DM dm)
2136: {
2137:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2138:   PetscInt       size;

2143:   PetscSectionSetUp(mesh->coneSection);
2144:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2145:   PetscMalloc1(size, &mesh->cones);
2146:   PetscCalloc1(size, &mesh->coneOrientations);
2147:   if (mesh->maxSupportSize) {
2148:     PetscSectionSetUp(mesh->supportSection);
2149:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2150:     PetscMalloc1(size, &mesh->supports);
2151:   }
2152:   return(0);
2153: }

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

2160:   if (subdm) {DMClone(dm, subdm);}
2161:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2162:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2163:   if (dm->useNatural && dm->sfMigration) {
2164:     PetscSF        sfMigrationInv,sfNatural;
2165:     PetscSection   section, sectionSeq;

2167:     (*subdm)->sfMigration = dm->sfMigration;
2168:     PetscObjectReference((PetscObject) dm->sfMigration);
2169:     DMGetDefaultSection((*subdm), &section);
2170:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2171:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2172:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2173: 
2174:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2175:     (*subdm)->sfNatural = sfNatural;
2176:     PetscSectionDestroy(&sectionSeq);
2177:     PetscSFDestroy(&sfMigrationInv);
2178:   }
2179:   return(0);
2180: }

2182: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2183: {
2185:   PetscInt       i = 0;

2188:   if (superdm) {DMClone(dms[0], superdm);}
2189:   DMCreateSuperDM_Section_Private(dms, len, is, superdm);
2190:   (*superdm)->useNatural = PETSC_FALSE;
2191:   for (i = 0; i < len; i++){
2192:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2193:       PetscSF        sfMigrationInv,sfNatural;
2194:       PetscSection   section, sectionSeq;

2196:       (*superdm)->sfMigration = dms[i]->sfMigration;
2197:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2198:       (*superdm)->useNatural = PETSC_TRUE;
2199:       DMGetDefaultSection((*superdm), &section);
2200:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2201:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2202:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2203: 
2204:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2205:       (*superdm)->sfNatural = sfNatural;
2206:       PetscSectionDestroy(&sectionSeq);
2207:       PetscSFDestroy(&sfMigrationInv);
2208:       break;
2209:     }
2210:   }
2211:   return(0);
2212: }

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

2217:   Not collective

2219:   Input Parameter:
2220: . mesh - The DMPlex

2222:   Output Parameter:

2224:   Note:
2225:   This should be called after all calls to DMPlexSetCone()

2227:   Level: beginner

2229: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2230: @*/
2231: PetscErrorCode DMPlexSymmetrize(DM dm)
2232: {
2233:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2234:   PetscInt      *offsets;
2235:   PetscInt       supportSize;
2236:   PetscInt       pStart, pEnd, p;

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

2247:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2248:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2249:     for (c = off; c < off+dof; ++c) {
2250:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2251:     }
2252:   }
2253:   for (p = pStart; p < pEnd; ++p) {
2254:     PetscInt dof;

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

2258:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2259:   }
2260:   PetscSectionSetUp(mesh->supportSection);
2261:   /* Calculate supports */
2262:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2263:   PetscMalloc1(supportSize, &mesh->supports);
2264:   PetscCalloc1(pEnd - pStart, &offsets);
2265:   for (p = pStart; p < pEnd; ++p) {
2266:     PetscInt dof, off, c;

2268:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2269:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2270:     for (c = off; c < off+dof; ++c) {
2271:       const PetscInt q = mesh->cones[c];
2272:       PetscInt       offS;

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

2276:       mesh->supports[offS+offsets[q]] = p;
2277:       ++offsets[q];
2278:     }
2279:   }
2280:   PetscFree(offsets);
2281:   return(0);
2282: }

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

2290:   Collective on dm

2292:   Input Parameter:
2293: . mesh - The DMPlex

2295:   Output Parameter:

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

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

2305:   Level: beginner

2307: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2308: @*/
2309: PetscErrorCode DMPlexStratify(DM dm)
2310: {
2311:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2312:   DMLabel        label;
2313:   PetscInt       pStart, pEnd, p;
2314:   PetscInt       numRoots = 0, numLeaves = 0;

2319:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2320:   /* Calculate depth */
2321:   DMPlexGetChart(dm, &pStart, &pEnd);
2322:   DMCreateLabel(dm, "depth");
2323:   DMPlexGetDepthLabel(dm, &label);
2324:   /* Initialize roots and count leaves */
2325:   for (p = pStart; p < pEnd; ++p) {
2326:     PetscInt coneSize, supportSize;

2328:     DMPlexGetConeSize(dm, p, &coneSize);
2329:     DMPlexGetSupportSize(dm, p, &supportSize);
2330:     if (!coneSize && supportSize) {
2331:       ++numRoots;
2332:       DMLabelSetValue(label, p, 0);
2333:     } else if (!supportSize && coneSize) {
2334:       ++numLeaves;
2335:     } else if (!supportSize && !coneSize) {
2336:       /* Isolated points */
2337:       DMLabelSetValue(label, p, 0);
2338:     }
2339:   }
2340:   if (numRoots + numLeaves == (pEnd - pStart)) {
2341:     for (p = pStart; p < pEnd; ++p) {
2342:       PetscInt coneSize, supportSize;

2344:       DMPlexGetConeSize(dm, p, &coneSize);
2345:       DMPlexGetSupportSize(dm, p, &supportSize);
2346:       if (!supportSize && coneSize) {
2347:         DMLabelSetValue(label, p, 1);
2348:       }
2349:     }
2350:   } else {
2351:     IS       pointIS;
2352:     PetscInt numPoints = 0, level = 0;

2354:     DMLabelGetStratumIS(label, level, &pointIS);
2355:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2356:     while (numPoints) {
2357:       const PetscInt *points;
2358:       const PetscInt  newLevel = level+1;

2360:       ISGetIndices(pointIS, &points);
2361:       for (p = 0; p < numPoints; ++p) {
2362:         const PetscInt  point = points[p];
2363:         const PetscInt *support;
2364:         PetscInt        supportSize, s;

2366:         DMPlexGetSupportSize(dm, point, &supportSize);
2367:         DMPlexGetSupport(dm, point, &support);
2368:         for (s = 0; s < supportSize; ++s) {
2369:           DMLabelSetValue(label, support[s], newLevel);
2370:         }
2371:       }
2372:       ISRestoreIndices(pointIS, &points);
2373:       ++level;
2374:       ISDestroy(&pointIS);
2375:       DMLabelGetStratumIS(label, level, &pointIS);
2376:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2377:       else         {numPoints = 0;}
2378:     }
2379:     ISDestroy(&pointIS);
2380:   }
2381:   { /* just in case there is an empty process */
2382:     PetscInt numValues, maxValues = 0, v;

2384:     DMLabelGetNumValues(label,&numValues);
2385:     for (v = 0; v < numValues; v++) {
2386:       IS pointIS;

2388:       DMLabelGetStratumIS(label, v, &pointIS);
2389:       if (pointIS) {
2390:         PetscInt  min, max, numPoints;
2391:         PetscInt  start;
2392:         PetscBool contig;

2394:         ISGetLocalSize(pointIS, &numPoints);
2395:         ISGetMinMax(pointIS, &min, &max);
2396:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2397:         if (start == 0 && contig) {
2398:           ISDestroy(&pointIS);
2399:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2400:           DMLabelSetStratumIS(label, v, pointIS);
2401:         }
2402:       }
2403:       ISDestroy(&pointIS);
2404:     }
2405:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2406:     for (v = numValues; v < maxValues; v++) {
2407:       DMLabelAddStratum(label,v);
2408:     }
2409:   }

2411:   DMLabelGetState(label, &mesh->depthState);
2412:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2413:   return(0);
2414: }

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

2419:   Not Collective

2421:   Input Parameters:
2422: + dm - The DMPlex object
2423: . numPoints - The number of input points for the join
2424: - points - The input points

2426:   Output Parameters:
2427: + numCoveredPoints - The number of points in the join
2428: - coveredPoints - The points in the join

2430:   Level: intermediate

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

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

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

2440: .keywords: mesh
2441: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2442: @*/
2443: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2444: {
2445:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2446:   PetscInt      *join[2];
2447:   PetscInt       joinSize, i = 0;
2448:   PetscInt       dof, off, p, c, m;

2456:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2457:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2458:   /* Copy in support of first point */
2459:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2460:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2461:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2462:     join[i][joinSize] = mesh->supports[off+joinSize];
2463:   }
2464:   /* Check each successive support */
2465:   for (p = 1; p < numPoints; ++p) {
2466:     PetscInt newJoinSize = 0;

2468:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2469:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2470:     for (c = 0; c < dof; ++c) {
2471:       const PetscInt point = mesh->supports[off+c];

2473:       for (m = 0; m < joinSize; ++m) {
2474:         if (point == join[i][m]) {
2475:           join[1-i][newJoinSize++] = point;
2476:           break;
2477:         }
2478:       }
2479:     }
2480:     joinSize = newJoinSize;
2481:     i        = 1-i;
2482:   }
2483:   *numCoveredPoints = joinSize;
2484:   *coveredPoints    = join[i];
2485:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2486:   return(0);
2487: }

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

2492:   Not Collective

2494:   Input Parameters:
2495: + dm - The DMPlex object
2496: . numPoints - The number of input points for the join
2497: - points - The input points

2499:   Output Parameters:
2500: + numCoveredPoints - The number of points in the join
2501: - coveredPoints - The points in the join

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

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

2509:   Level: intermediate

2511: .keywords: mesh
2512: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2513: @*/
2514: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2515: {

2523:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2524:   if (numCoveredPoints) *numCoveredPoints = 0;
2525:   return(0);
2526: }

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

2531:   Not Collective

2533:   Input Parameters:
2534: + dm - The DMPlex object
2535: . numPoints - The number of input points for the join
2536: - points - The input points

2538:   Output Parameters:
2539: + numCoveredPoints - The number of points in the join
2540: - coveredPoints - The points in the join

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

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

2548:   Level: intermediate

2550: .keywords: mesh
2551: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2552: @*/
2553: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2554: {
2555:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2556:   PetscInt      *offsets, **closures;
2557:   PetscInt      *join[2];
2558:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2559:   PetscInt       p, d, c, m, ms;


2568:   DMPlexGetDepth(dm, &depth);
2569:   PetscCalloc1(numPoints, &closures);
2570:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2571:   ms      = mesh->maxSupportSize;
2572:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2573:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2574:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

2576:   for (p = 0; p < numPoints; ++p) {
2577:     PetscInt closureSize;

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

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

2585:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2586:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2587:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2588:           offsets[p*(depth+2)+d+1] = i;
2589:           break;
2590:         }
2591:       }
2592:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2593:     }
2594:     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);
2595:   }
2596:   for (d = 0; d < depth+1; ++d) {
2597:     PetscInt dof;

2599:     /* Copy in support of first point */
2600:     dof = offsets[d+1] - offsets[d];
2601:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2602:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2603:     }
2604:     /* Check each successive cone */
2605:     for (p = 1; p < numPoints && joinSize; ++p) {
2606:       PetscInt newJoinSize = 0;

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

2612:         for (m = 0; m < joinSize; ++m) {
2613:           if (point == join[i][m]) {
2614:             join[1-i][newJoinSize++] = point;
2615:             break;
2616:           }
2617:         }
2618:       }
2619:       joinSize = newJoinSize;
2620:       i        = 1-i;
2621:     }
2622:     if (joinSize) break;
2623:   }
2624:   *numCoveredPoints = joinSize;
2625:   *coveredPoints    = join[i];
2626:   for (p = 0; p < numPoints; ++p) {
2627:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2628:   }
2629:   PetscFree(closures);
2630:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2631:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2632:   return(0);
2633: }

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

2638:   Not Collective

2640:   Input Parameters:
2641: + dm - The DMPlex object
2642: . numPoints - The number of input points for the meet
2643: - points - The input points

2645:   Output Parameters:
2646: + numCoveredPoints - The number of points in the meet
2647: - coveredPoints - The points in the meet

2649:   Level: intermediate

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

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

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

2659: .keywords: mesh
2660: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2661: @*/
2662: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2663: {
2664:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2665:   PetscInt      *meet[2];
2666:   PetscInt       meetSize, i = 0;
2667:   PetscInt       dof, off, p, c, m;

2675:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2676:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2677:   /* Copy in cone of first point */
2678:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2679:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2680:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2681:     meet[i][meetSize] = mesh->cones[off+meetSize];
2682:   }
2683:   /* Check each successive cone */
2684:   for (p = 1; p < numPoints; ++p) {
2685:     PetscInt newMeetSize = 0;

2687:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2688:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2689:     for (c = 0; c < dof; ++c) {
2690:       const PetscInt point = mesh->cones[off+c];

2692:       for (m = 0; m < meetSize; ++m) {
2693:         if (point == meet[i][m]) {
2694:           meet[1-i][newMeetSize++] = point;
2695:           break;
2696:         }
2697:       }
2698:     }
2699:     meetSize = newMeetSize;
2700:     i        = 1-i;
2701:   }
2702:   *numCoveringPoints = meetSize;
2703:   *coveringPoints    = meet[i];
2704:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2705:   return(0);
2706: }

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

2711:   Not Collective

2713:   Input Parameters:
2714: + dm - The DMPlex object
2715: . numPoints - The number of input points for the meet
2716: - points - The input points

2718:   Output Parameters:
2719: + numCoveredPoints - The number of points in the meet
2720: - coveredPoints - The points in the meet

2722:   Level: intermediate

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

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

2730: .keywords: mesh
2731: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2732: @*/
2733: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2734: {

2742:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2743:   if (numCoveredPoints) *numCoveredPoints = 0;
2744:   return(0);
2745: }

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

2750:   Not Collective

2752:   Input Parameters:
2753: + dm - The DMPlex object
2754: . numPoints - The number of input points for the meet
2755: - points - The input points

2757:   Output Parameters:
2758: + numCoveredPoints - The number of points in the meet
2759: - coveredPoints - The points in the meet

2761:   Level: intermediate

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

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

2769: .keywords: mesh
2770: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2771: @*/
2772: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2773: {
2774:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2775:   PetscInt      *offsets, **closures;
2776:   PetscInt      *meet[2];
2777:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2778:   PetscInt       p, h, c, m, mc;


2787:   DMPlexGetDepth(dm, &height);
2788:   PetscMalloc1(numPoints, &closures);
2789:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2790:   mc      = mesh->maxConeSize;
2791:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2792:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
2793:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

2795:   for (p = 0; p < numPoints; ++p) {
2796:     PetscInt closureSize;

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

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

2804:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2805:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2806:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2807:           offsets[p*(height+2)+h+1] = i;
2808:           break;
2809:         }
2810:       }
2811:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2812:     }
2813:     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);
2814:   }
2815:   for (h = 0; h < height+1; ++h) {
2816:     PetscInt dof;

2818:     /* Copy in cone of first point */
2819:     dof = offsets[h+1] - offsets[h];
2820:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2821:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2822:     }
2823:     /* Check each successive cone */
2824:     for (p = 1; p < numPoints && meetSize; ++p) {
2825:       PetscInt newMeetSize = 0;

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

2831:         for (m = 0; m < meetSize; ++m) {
2832:           if (point == meet[i][m]) {
2833:             meet[1-i][newMeetSize++] = point;
2834:             break;
2835:           }
2836:         }
2837:       }
2838:       meetSize = newMeetSize;
2839:       i        = 1-i;
2840:     }
2841:     if (meetSize) break;
2842:   }
2843:   *numCoveredPoints = meetSize;
2844:   *coveredPoints    = meet[i];
2845:   for (p = 0; p < numPoints; ++p) {
2846:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2847:   }
2848:   PetscFree(closures);
2849:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2850:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2851:   return(0);
2852: }

2854: /*@C
2855:   DMPlexEqual - Determine if two DMs have the same topology

2857:   Not Collective

2859:   Input Parameters:
2860: + dmA - A DMPlex object
2861: - dmB - A DMPlex object

2863:   Output Parameters:
2864: . equal - PETSC_TRUE if the topologies are identical

2866:   Level: intermediate

2868:   Notes:
2869:   We are not solving graph isomorphism, so we do not permutation.

2871: .keywords: mesh
2872: .seealso: DMPlexGetCone()
2873: @*/
2874: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2875: {
2876:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2884:   *equal = PETSC_FALSE;
2885:   DMPlexGetDepth(dmA, &depth);
2886:   DMPlexGetDepth(dmB, &depthB);
2887:   if (depth != depthB) return(0);
2888:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2889:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2890:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2891:   for (p = pStart; p < pEnd; ++p) {
2892:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2893:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

2895:     DMPlexGetConeSize(dmA, p, &coneSize);
2896:     DMPlexGetCone(dmA, p, &cone);
2897:     DMPlexGetConeOrientation(dmA, p, &ornt);
2898:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2899:     DMPlexGetCone(dmB, p, &coneB);
2900:     DMPlexGetConeOrientation(dmB, p, &orntB);
2901:     if (coneSize != coneSizeB) return(0);
2902:     for (c = 0; c < coneSize; ++c) {
2903:       if (cone[c] != coneB[c]) return(0);
2904:       if (ornt[c] != orntB[c]) return(0);
2905:     }
2906:     DMPlexGetSupportSize(dmA, p, &supportSize);
2907:     DMPlexGetSupport(dmA, p, &support);
2908:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2909:     DMPlexGetSupport(dmB, p, &supportB);
2910:     if (supportSize != supportSizeB) return(0);
2911:     for (s = 0; s < supportSize; ++s) {
2912:       if (support[s] != supportB[s]) return(0);
2913:     }
2914:   }
2915:   *equal = PETSC_TRUE;
2916:   return(0);
2917: }

2919: /*@C
2920:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

2922:   Not Collective

2924:   Input Parameters:
2925: + dm         - The DMPlex
2926: . cellDim    - The cell dimension
2927: - numCorners - The number of vertices on a cell

2929:   Output Parameters:
2930: . numFaceVertices - The number of vertices on a face

2932:   Level: developer

2934:   Notes:
2935:   Of course this can only work for a restricted set of symmetric shapes

2937: .seealso: DMPlexGetCone()
2938: @*/
2939: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2940: {
2941:   MPI_Comm       comm;

2945:   PetscObjectGetComm((PetscObject)dm,&comm);
2947:   switch (cellDim) {
2948:   case 0:
2949:     *numFaceVertices = 0;
2950:     break;
2951:   case 1:
2952:     *numFaceVertices = 1;
2953:     break;
2954:   case 2:
2955:     switch (numCorners) {
2956:     case 3: /* triangle */
2957:       *numFaceVertices = 2; /* Edge has 2 vertices */
2958:       break;
2959:     case 4: /* quadrilateral */
2960:       *numFaceVertices = 2; /* Edge has 2 vertices */
2961:       break;
2962:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2963:       *numFaceVertices = 3; /* Edge has 3 vertices */
2964:       break;
2965:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2966:       *numFaceVertices = 3; /* Edge has 3 vertices */
2967:       break;
2968:     default:
2969:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2970:     }
2971:     break;
2972:   case 3:
2973:     switch (numCorners) {
2974:     case 4: /* tetradehdron */
2975:       *numFaceVertices = 3; /* Face has 3 vertices */
2976:       break;
2977:     case 6: /* tet cohesive cells */
2978:       *numFaceVertices = 4; /* Face has 4 vertices */
2979:       break;
2980:     case 8: /* hexahedron */
2981:       *numFaceVertices = 4; /* Face has 4 vertices */
2982:       break;
2983:     case 9: /* tet cohesive Lagrange cells */
2984:       *numFaceVertices = 6; /* Face has 6 vertices */
2985:       break;
2986:     case 10: /* quadratic tetrahedron */
2987:       *numFaceVertices = 6; /* Face has 6 vertices */
2988:       break;
2989:     case 12: /* hex cohesive Lagrange cells */
2990:       *numFaceVertices = 6; /* Face has 6 vertices */
2991:       break;
2992:     case 18: /* quadratic tet cohesive Lagrange cells */
2993:       *numFaceVertices = 6; /* Face has 6 vertices */
2994:       break;
2995:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2996:       *numFaceVertices = 9; /* Face has 9 vertices */
2997:       break;
2998:     default:
2999:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3000:     }
3001:     break;
3002:   default:
3003:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3004:   }
3005:   return(0);
3006: }

3008: /*@
3009:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3011:   Not Collective

3013:   Input Parameter:
3014: . dm    - The DMPlex object

3016:   Output Parameter:
3017: . depthLabel - The DMLabel recording point depth

3019:   Level: developer

3021: .keywords: mesh, points
3022: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3023: @*/
3024: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3025: {

3031:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3032:   *depthLabel = dm->depthLabel;
3033:   return(0);
3034: }

3036: /*@
3037:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3039:   Not Collective

3041:   Input Parameter:
3042: . dm    - The DMPlex object

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

3047:   Level: developer

3049: .keywords: mesh, points
3050: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3051: @*/
3052: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3053: {
3054:   DMLabel        label;
3055:   PetscInt       d = 0;

3061:   DMPlexGetDepthLabel(dm, &label);
3062:   if (label) {DMLabelGetNumValues(label, &d);}
3063:   *depth = d-1;
3064:   return(0);
3065: }

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

3070:   Not Collective

3072:   Input Parameters:
3073: + dm           - The DMPlex object
3074: - stratumValue - The requested depth

3076:   Output Parameters:
3077: + start - The first point at this depth
3078: - end   - One beyond the last point at this depth

3080:   Level: developer

3082: .keywords: mesh, points
3083: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3084: @*/
3085: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3086: {
3087:   DMLabel        label;
3088:   PetscInt       pStart, pEnd;

3095:   DMPlexGetChart(dm, &pStart, &pEnd);
3096:   if (pStart == pEnd) return(0);
3097:   if (stratumValue < 0) {
3098:     if (start) *start = pStart;
3099:     if (end)   *end   = pEnd;
3100:     return(0);
3101:   }
3102:   DMPlexGetDepthLabel(dm, &label);
3103:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3104:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3105:   return(0);
3106: }

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

3111:   Not Collective

3113:   Input Parameters:
3114: + dm           - The DMPlex object
3115: - stratumValue - The requested height

3117:   Output Parameters:
3118: + start - The first point at this height
3119: - end   - One beyond the last point at this height

3121:   Level: developer

3123: .keywords: mesh, points
3124: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3125: @*/
3126: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3127: {
3128:   DMLabel        label;
3129:   PetscInt       depth, pStart, pEnd;

3136:   DMPlexGetChart(dm, &pStart, &pEnd);
3137:   if (pStart == pEnd) return(0);
3138:   if (stratumValue < 0) {
3139:     if (start) *start = pStart;
3140:     if (end)   *end   = pEnd;
3141:     return(0);
3142:   }
3143:   DMPlexGetDepthLabel(dm, &label);
3144:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3145:   DMLabelGetNumValues(label, &depth);
3146:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3147:   return(0);
3148: }

3150: /* Set the number of dof on each point and separate by fields */
3151: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3152: {
3153:   PetscInt      *pMax;
3154:   PetscInt       depth, cellHeight, pStart = 0, pEnd = 0;
3155:   PetscInt       Nf, p, d, dep, f;
3156:   PetscBool     *isFE;

3160:   PetscMalloc1(numFields, &isFE);
3161:   DMGetNumFields(dm, &Nf);
3162:   for (f = 0; f < numFields; ++f) {
3163:     PetscObject  obj;
3164:     PetscClassId id;

3166:     isFE[f] = PETSC_FALSE;
3167:     if (f >= Nf) continue;
3168:     DMGetField(dm, f, &obj);
3169:     PetscObjectGetClassId(obj, &id);
3170:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
3171:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3172:   }
3173:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
3174:   if (numFields > 0) {
3175:     PetscSectionSetNumFields(*section, numFields);
3176:     if (numComp) {
3177:       for (f = 0; f < numFields; ++f) {
3178:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
3179:         if (isFE[f]) {
3180:           PetscFE           fe;
3181:           PetscDualSpace    dspace;
3182:           const PetscInt    ***perms;
3183:           const PetscScalar ***flips;
3184:           const PetscInt    *numDof;

3186:           DMGetField(dm,f,(PetscObject *) &fe);
3187:           PetscFEGetDualSpace(fe,&dspace);
3188:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3189:           PetscDualSpaceGetNumDof(dspace,&numDof);
3190:           if (perms || flips) {
3191:             DM               K;
3192:             DMLabel          depthLabel;
3193:             PetscInt         depth, h;
3194:             PetscSectionSym  sym;

3196:             PetscDualSpaceGetDM(dspace,&K);
3197:             DMPlexGetDepthLabel(dm,&depthLabel);
3198:             DMPlexGetDepth(dm,&depth);
3199:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
3200:             for (h = 0; h <= depth; h++) {
3201:               PetscDualSpace    hspace;
3202:               PetscInt          kStart, kEnd;
3203:               PetscInt          kConeSize;
3204:               const PetscInt    **perms0 = NULL;
3205:               const PetscScalar **flips0 = NULL;

3207:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3208:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3209:               if (!hspace) continue;
3210:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3211:               if (perms) perms0 = perms[0];
3212:               if (flips) flips0 = flips[0];
3213:               if (!(perms0 || flips0)) continue;
3214:               DMPlexGetConeSize(K,kStart,&kConeSize);
3215:               PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3216:             }
3217:             PetscSectionSetFieldSym(*section,f,sym);
3218:             PetscSectionSymDestroy(&sym);
3219:           }
3220:         }
3221:       }
3222:     }
3223:   }
3224:   DMPlexGetChart(dm, &pStart, &pEnd);
3225:   PetscSectionSetChart(*section, pStart, pEnd);
3226:   DMPlexGetDepth(dm, &depth);
3227:   PetscMalloc1(depth+1,&pMax);
3228:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3229:   DMPlexGetVTKCellHeight(dm, &cellHeight);
3230:   for (dep = 0; dep <= depth - cellHeight; ++dep) {
3231:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3232:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3233:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3234:     for (p = pStart; p < pEnd; ++p) {
3235:       PetscInt tot = 0;

3237:       for (f = 0; f < numFields; ++f) {
3238:         if (isFE[f] && p >= pMax[dep]) continue;
3239:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3240:         tot += numDof[f*(dim+1)+d];
3241:       }
3242:       PetscSectionSetDof(*section, p, tot);
3243:     }
3244:   }
3245:   PetscFree(pMax);
3246:   PetscFree(isFE);
3247:   return(0);
3248: }

3250: /* Set the number of dof on each point and separate by fields
3251:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3252: */
3253: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3254: {
3255:   PetscInt       numFields;
3256:   PetscInt       bc;
3257:   PetscSection   aSec;

3261:   PetscSectionGetNumFields(section, &numFields);
3262:   for (bc = 0; bc < numBC; ++bc) {
3263:     PetscInt        field = 0;
3264:     const PetscInt *comp;
3265:     const PetscInt *idx;
3266:     PetscInt        Nc = -1, n, i;

3268:     if (numFields) field = bcField[bc];
3269:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3270:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3271:     ISGetLocalSize(bcPoints[bc], &n);
3272:     ISGetIndices(bcPoints[bc], &idx);
3273:     for (i = 0; i < n; ++i) {
3274:       const PetscInt p = idx[i];
3275:       PetscInt       numConst;

3277:       if (numFields) {
3278:         PetscSectionGetFieldDof(section, p, field, &numConst);
3279:       } else {
3280:         PetscSectionGetDof(section, p, &numConst);
3281:       }
3282:       /* If Nc < 0, constrain every dof on the point */
3283:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3284:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3285:       PetscSectionAddConstraintDof(section, p, numConst);
3286:     }
3287:     ISRestoreIndices(bcPoints[bc], &idx);
3288:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3289:   }
3290:   DMPlexGetAnchors(dm, &aSec, NULL);
3291:   if (aSec) {
3292:     PetscInt aStart, aEnd, a;

3294:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3295:     for (a = aStart; a < aEnd; a++) {
3296:       PetscInt dof, f;

3298:       PetscSectionGetDof(aSec, a, &dof);
3299:       if (dof) {
3300:         /* if there are point-to-point constraints, then all dofs are constrained */
3301:         PetscSectionGetDof(section, a, &dof);
3302:         PetscSectionSetConstraintDof(section, a, dof);
3303:         for (f = 0; f < numFields; f++) {
3304:           PetscSectionGetFieldDof(section, a, f, &dof);
3305:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3306:         }
3307:       }
3308:     }
3309:   }
3310:   return(0);
3311: }

3313: /* Set the constrained field indices on each point
3314:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3315: */
3316: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3317: {
3318:   PetscSection   aSec;
3319:   PetscInt      *indices;
3320:   PetscInt       numFields, cdof, maxDof = 0, pStart, pEnd, p, bc, f, d;

3324:   PetscSectionGetNumFields(section, &numFields);
3325:   if (!numFields) return(0);
3326:   /* Initialize all field indices to -1 */
3327:   PetscSectionGetChart(section, &pStart, &pEnd);
3328:   for (p = pStart; p < pEnd; ++p) {PetscSectionGetConstraintDof(section, p, &cdof); maxDof = PetscMax(maxDof, cdof);}
3329:   PetscMalloc1(maxDof, &indices);
3330:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3331:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3332:   /* Handle BC constraints */
3333:   for (bc = 0; bc < numBC; ++bc) {
3334:     const PetscInt  field = bcField[bc];
3335:     const PetscInt *comp, *idx;
3336:     PetscInt        Nc = -1, n, i;

3338:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3339:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3340:     ISGetLocalSize(bcPoints[bc], &n);
3341:     ISGetIndices(bcPoints[bc], &idx);
3342:     for (i = 0; i < n; ++i) {
3343:       const PetscInt  p = idx[i];
3344:       const PetscInt *find;
3345:       PetscInt        fdof, fcdof, c;

3347:       PetscSectionGetFieldDof(section, p, field, &fdof);
3348:       if (!fdof) continue;
3349:       if (Nc < 0) {
3350:         for (d = 0; d < fdof; ++d) indices[d] = d;
3351:         fcdof = fdof;
3352:       } else {
3353:         PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3354:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3355:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3356:         for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
3357:         PetscSortRemoveDupsInt(&d, indices);
3358:         for (c = d; c < fcdof; ++c) indices[c] = -1;
3359:         fcdof = d;
3360:       }
3361:       PetscSectionSetFieldConstraintDof(section, p, field, fcdof);
3362:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3363:     }
3364:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3365:     ISRestoreIndices(bcPoints[bc], &idx);
3366:   }
3367:   /* Handle anchors */
3368:   DMPlexGetAnchors(dm, &aSec, NULL);
3369:   if (aSec) {
3370:     PetscInt aStart, aEnd, a;

3372:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3373:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3374:     for (a = aStart; a < aEnd; a++) {
3375:       PetscInt dof, f;

3377:       PetscSectionGetDof(aSec, a, &dof);
3378:       if (dof) {
3379:         /* if there are point-to-point constraints, then all dofs are constrained */
3380:         for (f = 0; f < numFields; f++) {
3381:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3382:         }
3383:       }
3384:     }
3385:   }
3386:   PetscFree(indices);
3387:   return(0);
3388: }

3390: /* Set the constrained indices on each point */
3391: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3392: {
3393:   PetscInt      *indices;
3394:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3398:   PetscSectionGetNumFields(section, &numFields);
3399:   PetscSectionGetMaxDof(section, &maxDof);
3400:   PetscSectionGetChart(section, &pStart, &pEnd);
3401:   PetscMalloc1(maxDof, &indices);
3402:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3403:   for (p = pStart; p < pEnd; ++p) {
3404:     PetscInt cdof, d;

3406:     PetscSectionGetConstraintDof(section, p, &cdof);
3407:     if (cdof) {
3408:       if (numFields) {
3409:         PetscInt numConst = 0, foff = 0;

3411:         for (f = 0; f < numFields; ++f) {
3412:           const PetscInt *find;
3413:           PetscInt        fcdof, fdof;

3415:           PetscSectionGetFieldDof(section, p, f, &fdof);
3416:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3417:           /* Change constraint numbering from field component to local dof number */
3418:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3419:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3420:           numConst += fcdof;
3421:           foff     += fdof;
3422:         }
3423:         if (cdof != numConst) {PetscSectionSetConstraintDof(section, p, numConst);}
3424:       } else {
3425:         for (d = 0; d < cdof; ++d) indices[d] = d;
3426:       }
3427:       PetscSectionSetConstraintIndices(section, p, indices);
3428:     }
3429:   }
3430:   PetscFree(indices);
3431:   return(0);
3432: }

3434: /*@C
3435:   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.

3437:   Not Collective

3439:   Input Parameters:
3440: + dm        - The DMPlex object
3441: . dim       - The spatial dimension of the problem
3442: . numFields - The number of fields in the problem
3443: . numComp   - An array of size numFields that holds the number of components for each field
3444: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3445: . numBC     - The number of boundary conditions
3446: . bcField   - An array of size numBC giving the field number for each boundry condition
3447: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3448: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3449: - perm      - Optional permutation of the chart, or NULL

3451:   Output Parameter:
3452: . section - The PetscSection object

3454:   Notes:
3455:     numDof[f*(dim+1)+d] gives the number of dof for field f on points of dimension d. For instance, numDof[1] is the
3456:   number of dof for field 0 on each edge.

3458:   The chart permutation is the same one set using PetscSectionSetPermutation()

3460:   Level: developer

3462:   Fortran Notes:
3463:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3465: .keywords: mesh, elements
3466: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3467: @*/
3468: PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], IS perm, PetscSection *section)
3469: {
3470:   PetscSection   aSec;

3474:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3475:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3476:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3477:   PetscSectionSetUp(*section);
3478:   DMPlexGetAnchors(dm,&aSec,NULL);
3479:   if (numBC || aSec) {
3480:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3481:     DMPlexCreateSectionBCIndices(dm, *section);
3482:   }
3483:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3484:   return(0);
3485: }

3487: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3488: {
3489:   PetscSection   section, s;
3490:   Mat            m;
3491:   PetscInt       maxHeight;

3495:   DMClone(dm, cdm);
3496:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3497:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3498:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3499:   DMSetDefaultSection(*cdm, section);
3500:   PetscSectionDestroy(&section);
3501:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3502:   MatCreate(PETSC_COMM_SELF, &m);
3503:   DMSetDefaultConstraints(*cdm, s, m);
3504:   PetscSectionDestroy(&s);
3505:   MatDestroy(&m);
3506:   return(0);
3507: }

3509: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3510: {
3511:   Vec            coordsLocal;
3512:   DM             coordsDM;

3516:   *field = NULL;
3517:   DMGetCoordinatesLocal(dm,&coordsLocal);
3518:   DMGetCoordinateDM(dm,&coordsDM);
3519:   if (coordsLocal && coordsDM) {
3520:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3521:   }
3522:   return(0);
3523: }

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

3528:   Not Collective

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

3533:   Output Parameter:
3534: . section - The PetscSection object

3536:   Level: developer

3538: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3539: @*/
3540: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3541: {
3542:   DM_Plex *mesh = (DM_Plex*) dm->data;

3546:   if (section) *section = mesh->coneSection;
3547:   return(0);
3548: }

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

3553:   Not Collective

3555:   Input Parameters:
3556: . dm        - The DMPlex object

3558:   Output Parameter:
3559: . section - The PetscSection object

3561:   Level: developer

3563: .seealso: DMPlexGetConeSection()
3564: @*/
3565: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3566: {
3567:   DM_Plex *mesh = (DM_Plex*) dm->data;

3571:   if (section) *section = mesh->supportSection;
3572:   return(0);
3573: }

3575: /*@C
3576:   DMPlexGetCones - Return cone data

3578:   Not Collective

3580:   Input Parameters:
3581: . dm        - The DMPlex object

3583:   Output Parameter:
3584: . cones - The cone for each point

3586:   Level: developer

3588: .seealso: DMPlexGetConeSection()
3589: @*/
3590: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3591: {
3592:   DM_Plex *mesh = (DM_Plex*) dm->data;

3596:   if (cones) *cones = mesh->cones;
3597:   return(0);
3598: }

3600: /*@C
3601:   DMPlexGetConeOrientations - Return cone orientation data

3603:   Not Collective

3605:   Input Parameters:
3606: . dm        - The DMPlex object

3608:   Output Parameter:
3609: . coneOrientations - The cone orientation for each point

3611:   Level: developer

3613: .seealso: DMPlexGetConeSection()
3614: @*/
3615: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3616: {
3617:   DM_Plex *mesh = (DM_Plex*) dm->data;

3621:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3622:   return(0);
3623: }

3625: /******************************** FEM Support **********************************/

3627: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3628: {
3629:   DMLabel        label;
3630:   PetscInt      *perm;
3631:   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3635:   if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3636:   DMGetDimension(dm, &dim);
3637:   DMPlexGetDepthLabel(dm, &label);
3638:   DMLabelGetValue(label, point, &depth);
3639:   if (depth == 1) {eStart = point;}
3640:   else if  (depth == dim) {
3641:     const PetscInt *cone;

3643:     DMPlexGetCone(dm, point, &cone);
3644:     eStart = cone[0];
3645:   } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering", point, depth);
3646:   if (!section) {DMGetDefaultSection(dm, &section);}
3647:   PetscSectionGetNumFields(section, &Nf);
3648:   if (dim <= 1) return(0);
3649:   for (f = 0; f < Nf; ++f) {
3650:     /* An order k SEM disc has k-1 dofs on an edge */
3651:     PetscSectionGetFieldDof(section, eStart, f, &k);
3652:     PetscSectionGetFieldComponents(section, f, &Nc);
3653:     k = k/Nc + 1;
3654:     size += PetscPowInt(k+1, dim)*Nc;
3655:   }
3656:   PetscMalloc1(size, &perm);
3657:   for (f = 0; f < Nf; ++f) {
3658:     switch (dim) {
3659:     case 2:
3660:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3661:       PetscSectionGetFieldDof(section, eStart, f, &k);
3662:       PetscSectionGetFieldComponents(section, f, &Nc);
3663:       k = k/Nc + 1;
3664:       /* The SEM order is

3666:          v_lb, {e_b}, v_rb,
3667:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3668:          v_lt, reverse {e_t}, v_rt
3669:       */
3670:       {
3671:         const PetscInt of   = 0;
3672:         const PetscInt oeb  = of   + PetscSqr(k-1);
3673:         const PetscInt oer  = oeb  + (k-1);
3674:         const PetscInt oet  = oer  + (k-1);
3675:         const PetscInt oel  = oet  + (k-1);
3676:         const PetscInt ovlb = oel  + (k-1);
3677:         const PetscInt ovrb = ovlb + 1;
3678:         const PetscInt ovrt = ovrb + 1;
3679:         const PetscInt ovlt = ovrt + 1;
3680:         PetscInt       o;

3682:         /* bottom */
3683:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3684:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3685:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3686:         /* middle */
3687:         for (i = 0; i < k-1; ++i) {
3688:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3689:           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;
3690:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3691:         }
3692:         /* top */
3693:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3694:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3695:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3696:         foffset = offset;
3697:       }
3698:       break;
3699:     case 3:
3700:       /* The original hex closure is

3702:          {c,
3703:           f_b, f_t, f_f, f_b, f_r, f_l,
3704:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3705:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3706:       */
3707:       PetscSectionGetFieldDof(section, eStart, f, &k);
3708:       PetscSectionGetFieldComponents(section, f, &Nc);
3709:       k = k/Nc + 1;
3710:       /* The SEM order is
3711:          Bottom Slice
3712:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3713:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3714:          v_blb, {e_bb}, v_brb,

3716:          Middle Slice (j)
3717:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3718:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3719:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3721:          Top Slice
3722:          v_tlf, {e_tf}, v_trf,
3723:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3724:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3725:       */
3726:       {
3727:         const PetscInt oc    = 0;
3728:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3729:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3730:         const PetscInt off   = oft   + PetscSqr(k-1);
3731:         const PetscInt ofk   = off   + PetscSqr(k-1);
3732:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3733:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3734:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3735:         const PetscInt oebb  = oebl  + (k-1);
3736:         const PetscInt oebr  = oebb  + (k-1);
3737:         const PetscInt oebf  = oebr  + (k-1);
3738:         const PetscInt oetf  = oebf  + (k-1);
3739:         const PetscInt oetr  = oetf  + (k-1);
3740:         const PetscInt oetb  = oetr  + (k-1);
3741:         const PetscInt oetl  = oetb  + (k-1);
3742:         const PetscInt oerf  = oetl  + (k-1);
3743:         const PetscInt oelf  = oerf  + (k-1);
3744:         const PetscInt oelb  = oelf  + (k-1);
3745:         const PetscInt oerb  = oelb  + (k-1);
3746:         const PetscInt ovblf = oerb  + (k-1);
3747:         const PetscInt ovblb = ovblf + 1;
3748:         const PetscInt ovbrb = ovblb + 1;
3749:         const PetscInt ovbrf = ovbrb + 1;
3750:         const PetscInt ovtlf = ovbrf + 1;
3751:         const PetscInt ovtrf = ovtlf + 1;
3752:         const PetscInt ovtrb = ovtrf + 1;
3753:         const PetscInt ovtlb = ovtrb + 1;
3754:         PetscInt       o, n;

3756:         /* Bottom Slice */
3757:         /*   bottom */
3758:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3759:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3760:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3761:         /*   middle */
3762:         for (i = 0; i < k-1; ++i) {
3763:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3764:           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;}
3765:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3766:         }
3767:         /*   top */
3768:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3769:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3770:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3772:         /* Middle Slice */
3773:         for (j = 0; j < k-1; ++j) {
3774:           /*   bottom */
3775:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3776:           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;
3777:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3778:           /*   middle */
3779:           for (i = 0; i < k-1; ++i) {
3780:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3781:             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;
3782:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3783:           }
3784:           /*   top */
3785:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3786:           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;
3787:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3788:         }

3790:         /* Top Slice */
3791:         /*   bottom */
3792:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3793:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3794:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3795:         /*   middle */
3796:         for (i = 0; i < k-1; ++i) {
3797:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3798:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3799:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3800:         }
3801:         /*   top */
3802:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3803:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3804:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3806:         foffset = offset;
3807:       }
3808:       break;
3809:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3810:     }
3811:   }
3812:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3813:   /* Check permutation */
3814:   {
3815:     PetscInt *check;

3817:     PetscMalloc1(size, &check);
3818:     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]);}
3819:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3820:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3821:     PetscFree(check);
3822:   }
3823:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3824:   return(0);
3825: }

3827: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3828: {
3829:   PetscDS        prob;
3830:   PetscInt       depth, Nf, h;
3831:   DMLabel        label;

3835:   prob    = dm->prob;
3836:   Nf      = prob->Nf;
3837:   label   = dm->depthLabel;
3838:   *dspace = NULL;
3839:   if (field < Nf) {
3840:     PetscObject disc = prob->disc[field];

3842:     if (disc->classid == PETSCFE_CLASSID) {
3843:       PetscDualSpace dsp;

3845:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3846:       DMLabelGetNumValues(label,&depth);
3847:       DMLabelGetValue(label,point,&h);
3848:       h    = depth - 1 - h;
3849:       if (h) {
3850:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3851:       } else {
3852:         *dspace = dsp;
3853:       }
3854:     }
3855:   }
3856:   return(0);
3857: }


3860: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3861: {
3862:   PetscScalar    *array, *vArray;
3863:   const PetscInt *cone, *coneO;
3864:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3865:   PetscErrorCode  ierr;

3868:   PetscSectionGetChart(section, &pStart, &pEnd);
3869:   DMPlexGetConeSize(dm, point, &numPoints);
3870:   DMPlexGetCone(dm, point, &cone);
3871:   DMPlexGetConeOrientation(dm, point, &coneO);
3872:   if (!values || !*values) {
3873:     if ((point >= pStart) && (point < pEnd)) {
3874:       PetscInt dof;

3876:       PetscSectionGetDof(section, point, &dof);
3877:       size += dof;
3878:     }
3879:     for (p = 0; p < numPoints; ++p) {
3880:       const PetscInt cp = cone[p];
3881:       PetscInt       dof;

3883:       if ((cp < pStart) || (cp >= pEnd)) continue;
3884:       PetscSectionGetDof(section, cp, &dof);
3885:       size += dof;
3886:     }
3887:     if (!values) {
3888:       if (csize) *csize = size;
3889:       return(0);
3890:     }
3891:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
3892:   } else {
3893:     array = *values;
3894:   }
3895:   size = 0;
3896:   VecGetArray(v, &vArray);
3897:   if ((point >= pStart) && (point < pEnd)) {
3898:     PetscInt     dof, off, d;
3899:     PetscScalar *varr;

3901:     PetscSectionGetDof(section, point, &dof);
3902:     PetscSectionGetOffset(section, point, &off);
3903:     varr = &vArray[off];
3904:     for (d = 0; d < dof; ++d, ++offset) {
3905:       array[offset] = varr[d];
3906:     }
3907:     size += dof;
3908:   }
3909:   for (p = 0; p < numPoints; ++p) {
3910:     const PetscInt cp = cone[p];
3911:     PetscInt       o  = coneO[p];
3912:     PetscInt       dof, off, d;
3913:     PetscScalar   *varr;

3915:     if ((cp < pStart) || (cp >= pEnd)) continue;
3916:     PetscSectionGetDof(section, cp, &dof);
3917:     PetscSectionGetOffset(section, cp, &off);
3918:     varr = &vArray[off];
3919:     if (o >= 0) {
3920:       for (d = 0; d < dof; ++d, ++offset) {
3921:         array[offset] = varr[d];
3922:       }
3923:     } else {
3924:       for (d = dof-1; d >= 0; --d, ++offset) {
3925:         array[offset] = varr[d];
3926:       }
3927:     }
3928:     size += dof;
3929:   }
3930:   VecRestoreArray(v, &vArray);
3931:   if (!*values) {
3932:     if (csize) *csize = size;
3933:     *values = array;
3934:   } else {
3935:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3936:     *csize = size;
3937:   }
3938:   return(0);
3939: }

3941: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3942: {
3943:   const PetscInt *cla;
3944:   PetscInt       np, *pts = NULL;

3948:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3949:   if (!*clPoints) {
3950:     PetscInt pStart, pEnd, p, q;

3952:     PetscSectionGetChart(section, &pStart, &pEnd);
3953:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3954:     /* Compress out points not in the section */
3955:     for (p = 0, q = 0; p < np; p++) {
3956:       PetscInt r = pts[2*p];
3957:       if ((r >= pStart) && (r < pEnd)) {
3958:         pts[q*2]   = r;
3959:         pts[q*2+1] = pts[2*p+1];
3960:         ++q;
3961:       }
3962:     }
3963:     np = q;
3964:     cla = NULL;
3965:   } else {
3966:     PetscInt dof, off;

3968:     PetscSectionGetDof(*clSec, point, &dof);
3969:     PetscSectionGetOffset(*clSec, point, &off);
3970:     ISGetIndices(*clPoints, &cla);
3971:     np   = dof/2;
3972:     pts  = (PetscInt *) &cla[off];
3973:   }
3974:   *numPoints = np;
3975:   *points    = pts;
3976:   *clp       = cla;

3978:   return(0);
3979: }

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

3986:   if (!*clPoints) {
3987:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3988:   } else {
3989:     ISRestoreIndices(*clPoints, clp);
3990:   }
3991:   *numPoints = 0;
3992:   *points    = NULL;
3993:   *clSec     = NULL;
3994:   *clPoints  = NULL;
3995:   *clp       = NULL;
3996:   return(0);
3997: }

3999: 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[])
4000: {
4001:   PetscInt          offset = 0, p;
4002:   const PetscInt    **perms = NULL;
4003:   const PetscScalar **flips = NULL;
4004:   PetscErrorCode    ierr;

4007:   *size = 0;
4008:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4009:   for (p = 0; p < numPoints; p++) {
4010:     const PetscInt    point = points[2*p];
4011:     const PetscInt    *perm = perms ? perms[p] : NULL;
4012:     const PetscScalar *flip = flips ? flips[p] : NULL;
4013:     PetscInt          dof, off, d;
4014:     const PetscScalar *varr;

4016:     PetscSectionGetDof(section, point, &dof);
4017:     PetscSectionGetOffset(section, point, &off);
4018:     varr = &vArray[off];
4019:     if (clperm) {
4020:       if (perm) {
4021:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4022:       } else {
4023:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4024:       }
4025:       if (flip) {
4026:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4027:       }
4028:     } else {
4029:       if (perm) {
4030:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4031:       } else {
4032:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4033:       }
4034:       if (flip) {
4035:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4036:       }
4037:     }
4038:     offset += dof;
4039:   }
4040:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4041:   *size = offset;
4042:   return(0);
4043: }

4045: 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[])
4046: {
4047:   PetscInt          offset = 0, f;
4048:   PetscErrorCode    ierr;

4051:   *size = 0;
4052:   for (f = 0; f < numFields; ++f) {
4053:     PetscInt          p;
4054:     const PetscInt    **perms = NULL;
4055:     const PetscScalar **flips = NULL;

4057:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4058:     for (p = 0; p < numPoints; p++) {
4059:       const PetscInt    point = points[2*p];
4060:       PetscInt          fdof, foff, b;
4061:       const PetscScalar *varr;
4062:       const PetscInt    *perm = perms ? perms[p] : NULL;
4063:       const PetscScalar *flip = flips ? flips[p] : NULL;

4065:       PetscSectionGetFieldDof(section, point, f, &fdof);
4066:       PetscSectionGetFieldOffset(section, point, f, &foff);
4067:       varr = &vArray[foff];
4068:       if (clperm) {
4069:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4070:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4071:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4072:       } else {
4073:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4074:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4075:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4076:       }
4077:       offset += fdof;
4078:     }
4079:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4080:   }
4081:   *size = offset;
4082:   return(0);
4083: }

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

4088:   Not collective

4090:   Input Parameters:
4091: + dm - The DM
4092: . section - The section describing the layout in v, or NULL to use the default section
4093: . v - The local vector
4094: . point - The point in the DM
4095: . csize - The size of the input values array, or NULL
4096: - values - An array to use for the values, or NULL to have it allocated automatically

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

4102: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4103: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4104: $ assembly function, and a user may already have allocated storage for this operation.
4105: $
4106: $ A typical use could be
4107: $
4108: $  values = NULL;
4109: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4110: $  for (cl = 0; cl < clSize; ++cl) {
4111: $    <Compute on closure>
4112: $  }
4113: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4114: $
4115: $ or
4116: $
4117: $  PetscMalloc1(clMaxSize, &values);
4118: $  for (p = pStart; p < pEnd; ++p) {
4119: $    clSize = clMaxSize;
4120: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4121: $    for (cl = 0; cl < clSize; ++cl) {
4122: $      <Compute on closure>
4123: $    }
4124: $  }
4125: $  PetscFree(values);

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

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

4133:   Level: intermediate

4135: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4136: @*/
4137: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4138: {
4139:   PetscSection       clSection;
4140:   IS                 clPoints;
4141:   PetscScalar       *array;
4142:   const PetscScalar *vArray;
4143:   PetscInt          *points = NULL;
4144:   const PetscInt    *clp, *perm;
4145:   PetscInt           depth, numFields, numPoints, size;
4146:   PetscErrorCode     ierr;

4150:   if (!section) {DMGetDefaultSection(dm, &section);}
4153:   DMPlexGetDepth(dm, &depth);
4154:   PetscSectionGetNumFields(section, &numFields);
4155:   if (depth == 1 && numFields < 2) {
4156:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4157:     return(0);
4158:   }
4159:   /* Get points */
4160:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4161:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4162:   /* Get array */
4163:   if (!values || !*values) {
4164:     PetscInt asize = 0, dof, p;

4166:     for (p = 0; p < numPoints*2; p += 2) {
4167:       PetscSectionGetDof(section, points[p], &dof);
4168:       asize += dof;
4169:     }
4170:     if (!values) {
4171:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4172:       if (csize) *csize = asize;
4173:       return(0);
4174:     }
4175:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4176:   } else {
4177:     array = *values;
4178:   }
4179:   VecGetArrayRead(v, &vArray);
4180:   /* Get values */
4181:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4182:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4183:   /* Cleanup points */
4184:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4185:   /* Cleanup array */
4186:   VecRestoreArrayRead(v, &vArray);
4187:   if (!*values) {
4188:     if (csize) *csize = size;
4189:     *values = array;
4190:   } else {
4191:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4192:     *csize = size;
4193:   }
4194:   return(0);
4195: }

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

4200:   Not collective

4202:   Input Parameters:
4203: + dm - The DM
4204: . section - The section describing the layout in v, or NULL to use the default section
4205: . v - The local vector
4206: . point - The point in the DM
4207: . csize - The number of values in the closure, or NULL
4208: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

4218:   Level: intermediate

4220: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4221: @*/
4222: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4223: {
4224:   PetscInt       size = 0;

4228:   /* Should work without recalculating size */
4229:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4230:   *values = NULL;
4231:   return(0);
4232: }

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

4237: 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[])
4238: {
4239:   PetscInt        cdof;   /* The number of constraints on this point */
4240:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4241:   PetscScalar    *a;
4242:   PetscInt        off, cind = 0, k;
4243:   PetscErrorCode  ierr;

4246:   PetscSectionGetConstraintDof(section, point, &cdof);
4247:   PetscSectionGetOffset(section, point, &off);
4248:   a    = &array[off];
4249:   if (!cdof || setBC) {
4250:     if (clperm) {
4251:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4252:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4253:     } else {
4254:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4255:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4256:     }
4257:   } else {
4258:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4259:     if (clperm) {
4260:       if (perm) {for (k = 0; k < dof; ++k) {
4261:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4262:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4263:         }
4264:       } else {
4265:         for (k = 0; k < dof; ++k) {
4266:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4267:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4268:         }
4269:       }
4270:     } else {
4271:       if (perm) {
4272:         for (k = 0; k < dof; ++k) {
4273:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4274:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4275:         }
4276:       } else {
4277:         for (k = 0; k < dof; ++k) {
4278:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4279:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4280:         }
4281:       }
4282:     }
4283:   }
4284:   return(0);
4285: }

4287: 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[])
4288: {
4289:   PetscInt        cdof;   /* The number of constraints on this point */
4290:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4291:   PetscScalar    *a;
4292:   PetscInt        off, cind = 0, k;
4293:   PetscErrorCode  ierr;

4296:   PetscSectionGetConstraintDof(section, point, &cdof);
4297:   PetscSectionGetOffset(section, point, &off);
4298:   a    = &array[off];
4299:   if (cdof) {
4300:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4301:     if (clperm) {
4302:       if (perm) {
4303:         for (k = 0; k < dof; ++k) {
4304:           if ((cind < cdof) && (k == cdofs[cind])) {
4305:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4306:             cind++;
4307:           }
4308:         }
4309:       } else {
4310:         for (k = 0; k < dof; ++k) {
4311:           if ((cind < cdof) && (k == cdofs[cind])) {
4312:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4313:             cind++;
4314:           }
4315:         }
4316:       }
4317:     } else {
4318:       if (perm) {
4319:         for (k = 0; k < dof; ++k) {
4320:           if ((cind < cdof) && (k == cdofs[cind])) {
4321:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4322:             cind++;
4323:           }
4324:         }
4325:       } else {
4326:         for (k = 0; k < dof; ++k) {
4327:           if ((cind < cdof) && (k == cdofs[cind])) {
4328:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4329:             cind++;
4330:           }
4331:         }
4332:       }
4333:     }
4334:   }
4335:   return(0);
4336: }

4338: 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[])
4339: {
4340:   PetscScalar    *a;
4341:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4342:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4343:   PetscInt        cind = 0, b;
4344:   PetscErrorCode  ierr;

4347:   PetscSectionGetFieldDof(section, point, f, &fdof);
4348:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4349:   PetscSectionGetFieldOffset(section, point, f, &foff);
4350:   a    = &array[foff];
4351:   if (!fcdof || setBC) {
4352:     if (clperm) {
4353:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4354:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4355:     } else {
4356:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4357:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4358:     }
4359:   } else {
4360:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4361:     if (clperm) {
4362:       if (perm) {
4363:         for (b = 0; b < fdof; b++) {
4364:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4365:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4366:         }
4367:       } else {
4368:         for (b = 0; b < fdof; b++) {
4369:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4370:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4371:         }
4372:       }
4373:     } else {
4374:       if (perm) {
4375:         for (b = 0; b < fdof; b++) {
4376:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4377:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4378:         }
4379:       } else {
4380:         for (b = 0; b < fdof; b++) {
4381:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4382:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4383:         }
4384:       }
4385:     }
4386:   }
4387:   *offset += fdof;
4388:   return(0);
4389: }

4391: 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[])
4392: {
4393:   PetscScalar    *a;
4394:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4395:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4396:   PetscInt        cind = 0, ncind = 0, b;
4397:   PetscBool       ncSet, fcSet;
4398:   PetscErrorCode  ierr;

4401:   PetscSectionGetFieldDof(section, point, f, &fdof);
4402:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4403:   PetscSectionGetFieldOffset(section, point, f, &foff);
4404:   a    = &array[foff];
4405:   if (fcdof) {
4406:     /* We just override fcdof and fcdofs with Ncc and comps */
4407:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4408:     if (clperm) {
4409:       if (perm) {
4410:         if (comps) {
4411:           for (b = 0; b < fdof; b++) {
4412:             ncSet = fcSet = PETSC_FALSE;
4413:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4414:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4415:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4416:           }
4417:         } else {
4418:           for (b = 0; b < fdof; b++) {
4419:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4420:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4421:               ++cind;
4422:             }
4423:           }
4424:         }
4425:       } else {
4426:         if (comps) {
4427:           for (b = 0; b < fdof; b++) {
4428:             ncSet = fcSet = PETSC_FALSE;
4429:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4430:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4431:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4432:           }
4433:         } else {
4434:           for (b = 0; b < fdof; b++) {
4435:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4436:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4437:               ++cind;
4438:             }
4439:           }
4440:         }
4441:       }
4442:     } else {
4443:       if (perm) {
4444:         if (comps) {
4445:           for (b = 0; b < fdof; b++) {
4446:             ncSet = fcSet = PETSC_FALSE;
4447:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4448:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4449:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4450:           }
4451:         } else {
4452:           for (b = 0; b < fdof; b++) {
4453:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4454:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4455:               ++cind;
4456:             }
4457:           }
4458:         }
4459:       } else {
4460:         if (comps) {
4461:           for (b = 0; b < fdof; b++) {
4462:             ncSet = fcSet = PETSC_FALSE;
4463:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4464:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4465:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4466:           }
4467:         } else {
4468:           for (b = 0; b < fdof; b++) {
4469:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4470:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4471:               ++cind;
4472:             }
4473:           }
4474:         }
4475:       }
4476:     }
4477:   }
4478:   *offset += fdof;
4479:   return(0);
4480: }

4482: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4483: {
4484:   PetscScalar    *array;
4485:   const PetscInt *cone, *coneO;
4486:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4487:   PetscErrorCode  ierr;

4490:   PetscSectionGetChart(section, &pStart, &pEnd);
4491:   DMPlexGetConeSize(dm, point, &numPoints);
4492:   DMPlexGetCone(dm, point, &cone);
4493:   DMPlexGetConeOrientation(dm, point, &coneO);
4494:   VecGetArray(v, &array);
4495:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4496:     const PetscInt cp = !p ? point : cone[p-1];
4497:     const PetscInt o  = !p ? 0     : coneO[p-1];

4499:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4500:     PetscSectionGetDof(section, cp, &dof);
4501:     /* ADD_VALUES */
4502:     {
4503:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4504:       PetscScalar    *a;
4505:       PetscInt        cdof, coff, cind = 0, k;

4507:       PetscSectionGetConstraintDof(section, cp, &cdof);
4508:       PetscSectionGetOffset(section, cp, &coff);
4509:       a    = &array[coff];
4510:       if (!cdof) {
4511:         if (o >= 0) {
4512:           for (k = 0; k < dof; ++k) {
4513:             a[k] += values[off+k];
4514:           }
4515:         } else {
4516:           for (k = 0; k < dof; ++k) {
4517:             a[k] += values[off+dof-k-1];
4518:           }
4519:         }
4520:       } else {
4521:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4522:         if (o >= 0) {
4523:           for (k = 0; k < dof; ++k) {
4524:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4525:             a[k] += values[off+k];
4526:           }
4527:         } else {
4528:           for (k = 0; k < dof; ++k) {
4529:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4530:             a[k] += values[off+dof-k-1];
4531:           }
4532:         }
4533:       }
4534:     }
4535:   }
4536:   VecRestoreArray(v, &array);
4537:   return(0);
4538: }

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

4543:   Not collective

4545:   Input Parameters:
4546: + dm - The DM
4547: . section - The section describing the layout in v, or NULL to use the default section
4548: . v - The local vector
4549: . point - The point in the DM
4550: . values - The array of values
4551: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4552:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4557:   Level: intermediate

4559: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4560: @*/
4561: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4562: {
4563:   PetscSection    clSection;
4564:   IS              clPoints;
4565:   PetscScalar    *array;
4566:   PetscInt       *points = NULL;
4567:   const PetscInt *clp, *clperm;
4568:   PetscInt        depth, numFields, numPoints, p;
4569:   PetscErrorCode  ierr;

4573:   if (!section) {DMGetDefaultSection(dm, &section);}
4576:   DMPlexGetDepth(dm, &depth);
4577:   PetscSectionGetNumFields(section, &numFields);
4578:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4579:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4580:     return(0);
4581:   }
4582:   /* Get points */
4583:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4584:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4585:   /* Get array */
4586:   VecGetArray(v, &array);
4587:   /* Get values */
4588:   if (numFields > 0) {
4589:     PetscInt offset = 0, f;
4590:     for (f = 0; f < numFields; ++f) {
4591:       const PetscInt    **perms = NULL;
4592:       const PetscScalar **flips = NULL;

4594:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4595:       switch (mode) {
4596:       case INSERT_VALUES:
4597:         for (p = 0; p < numPoints; p++) {
4598:           const PetscInt    point = points[2*p];
4599:           const PetscInt    *perm = perms ? perms[p] : NULL;
4600:           const PetscScalar *flip = flips ? flips[p] : NULL;
4601:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4602:         } break;
4603:       case INSERT_ALL_VALUES:
4604:         for (p = 0; p < numPoints; p++) {
4605:           const PetscInt    point = points[2*p];
4606:           const PetscInt    *perm = perms ? perms[p] : NULL;
4607:           const PetscScalar *flip = flips ? flips[p] : NULL;
4608:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4609:         } break;
4610:       case INSERT_BC_VALUES:
4611:         for (p = 0; p < numPoints; p++) {
4612:           const PetscInt    point = points[2*p];
4613:           const PetscInt    *perm = perms ? perms[p] : NULL;
4614:           const PetscScalar *flip = flips ? flips[p] : NULL;
4615:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4616:         } break;
4617:       case ADD_VALUES:
4618:         for (p = 0; p < numPoints; p++) {
4619:           const PetscInt    point = points[2*p];
4620:           const PetscInt    *perm = perms ? perms[p] : NULL;
4621:           const PetscScalar *flip = flips ? flips[p] : NULL;
4622:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4623:         } break;
4624:       case ADD_ALL_VALUES:
4625:         for (p = 0; p < numPoints; p++) {
4626:           const PetscInt    point = points[2*p];
4627:           const PetscInt    *perm = perms ? perms[p] : NULL;
4628:           const PetscScalar *flip = flips ? flips[p] : NULL;
4629:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4630:         } break;
4631:       case ADD_BC_VALUES:
4632:         for (p = 0; p < numPoints; p++) {
4633:           const PetscInt    point = points[2*p];
4634:           const PetscInt    *perm = perms ? perms[p] : NULL;
4635:           const PetscScalar *flip = flips ? flips[p] : NULL;
4636:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4637:         } break;
4638:       default:
4639:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4640:       }
4641:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4642:     }
4643:   } else {
4644:     PetscInt dof, off;
4645:     const PetscInt    **perms = NULL;
4646:     const PetscScalar **flips = NULL;

4648:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4649:     switch (mode) {
4650:     case INSERT_VALUES:
4651:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4652:         const PetscInt    point = points[2*p];
4653:         const PetscInt    *perm = perms ? perms[p] : NULL;
4654:         const PetscScalar *flip = flips ? flips[p] : NULL;
4655:         PetscSectionGetDof(section, point, &dof);
4656:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4657:       } break;
4658:     case INSERT_ALL_VALUES:
4659:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4660:         const PetscInt    point = points[2*p];
4661:         const PetscInt    *perm = perms ? perms[p] : NULL;
4662:         const PetscScalar *flip = flips ? flips[p] : NULL;
4663:         PetscSectionGetDof(section, point, &dof);
4664:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4665:       } break;
4666:     case INSERT_BC_VALUES:
4667:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4668:         const PetscInt    point = points[2*p];
4669:         const PetscInt    *perm = perms ? perms[p] : NULL;
4670:         const PetscScalar *flip = flips ? flips[p] : NULL;
4671:         PetscSectionGetDof(section, point, &dof);
4672:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4673:       } break;
4674:     case ADD_VALUES:
4675:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4676:         const PetscInt    point = points[2*p];
4677:         const PetscInt    *perm = perms ? perms[p] : NULL;
4678:         const PetscScalar *flip = flips ? flips[p] : NULL;
4679:         PetscSectionGetDof(section, point, &dof);
4680:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4681:       } break;
4682:     case ADD_ALL_VALUES:
4683:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4684:         const PetscInt    point = points[2*p];
4685:         const PetscInt    *perm = perms ? perms[p] : NULL;
4686:         const PetscScalar *flip = flips ? flips[p] : NULL;
4687:         PetscSectionGetDof(section, point, &dof);
4688:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4689:       } break;
4690:     case ADD_BC_VALUES:
4691:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4692:         const PetscInt    point = points[2*p];
4693:         const PetscInt    *perm = perms ? perms[p] : NULL;
4694:         const PetscScalar *flip = flips ? flips[p] : NULL;
4695:         PetscSectionGetDof(section, point, &dof);
4696:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4697:       } break;
4698:     default:
4699:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4700:     }
4701:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4702:   }
4703:   /* Cleanup points */
4704:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4705:   /* Cleanup array */
4706:   VecRestoreArray(v, &array);
4707:   return(0);
4708: }

4710: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4711: {
4712:   PetscSection      clSection;
4713:   IS                clPoints;
4714:   PetscScalar       *array;
4715:   PetscInt          *points = NULL;
4716:   const PetscInt    *clp, *clperm;
4717:   PetscInt          numFields, numPoints, p;
4718:   PetscInt          offset = 0, f;
4719:   PetscErrorCode    ierr;

4723:   if (!section) {DMGetDefaultSection(dm, &section);}
4726:   PetscSectionGetNumFields(section, &numFields);
4727:   /* Get points */
4728:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4729:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4730:   /* Get array */
4731:   VecGetArray(v, &array);
4732:   /* Get values */
4733:   for (f = 0; f < numFields; ++f) {
4734:     const PetscInt    **perms = NULL;
4735:     const PetscScalar **flips = NULL;

4737:     if (!fieldActive[f]) {
4738:       for (p = 0; p < numPoints*2; p += 2) {
4739:         PetscInt fdof;
4740:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4741:         offset += fdof;
4742:       }
4743:       continue;
4744:     }
4745:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4746:     switch (mode) {
4747:     case INSERT_VALUES:
4748:       for (p = 0; p < numPoints; p++) {
4749:         const PetscInt    point = points[2*p];
4750:         const PetscInt    *perm = perms ? perms[p] : NULL;
4751:         const PetscScalar *flip = flips ? flips[p] : NULL;
4752:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4753:       } break;
4754:     case INSERT_ALL_VALUES:
4755:       for (p = 0; p < numPoints; p++) {
4756:         const PetscInt    point = points[2*p];
4757:         const PetscInt    *perm = perms ? perms[p] : NULL;
4758:         const PetscScalar *flip = flips ? flips[p] : NULL;
4759:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4760:         } break;
4761:     case INSERT_BC_VALUES:
4762:       for (p = 0; p < numPoints; p++) {
4763:         const PetscInt    point = points[2*p];
4764:         const PetscInt    *perm = perms ? perms[p] : NULL;
4765:         const PetscScalar *flip = flips ? flips[p] : NULL;
4766:         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4767:       } break;
4768:     case ADD_VALUES:
4769:       for (p = 0; p < numPoints; p++) {
4770:         const PetscInt    point = points[2*p];
4771:         const PetscInt    *perm = perms ? perms[p] : NULL;
4772:         const PetscScalar *flip = flips ? flips[p] : NULL;
4773:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4774:       } break;
4775:     case ADD_ALL_VALUES:
4776:       for (p = 0; p < numPoints; p++) {
4777:         const PetscInt    point = points[2*p];
4778:         const PetscInt    *perm = perms ? perms[p] : NULL;
4779:         const PetscScalar *flip = flips ? flips[p] : NULL;
4780:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4781:       } break;
4782:     default:
4783:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4784:     }
4785:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4786:   }
4787:   /* Cleanup points */
4788:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4789:   /* Cleanup array */
4790:   VecRestoreArray(v, &array);
4791:   return(0);
4792: }

4794: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4795: {
4796:   PetscMPIInt    rank;
4797:   PetscInt       i, j;

4801:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4802:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4803:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4804:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4805:   numCIndices = numCIndices ? numCIndices : numRIndices;
4806:   for (i = 0; i < numRIndices; i++) {
4807:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4808:     for (j = 0; j < numCIndices; j++) {
4809: #if defined(PETSC_USE_COMPLEX)
4810:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4811: #else
4812:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4813: #endif
4814:     }
4815:     PetscViewerASCIIPrintf(viewer, "\n");
4816:   }
4817:   return(0);
4818: }

4820: /* . off - The global offset of this point */
4821: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4822: {
4823:   PetscInt        dof;    /* The number of unknowns on this point */
4824:   PetscInt        cdof;   /* The number of constraints on this point */
4825:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4826:   PetscInt        cind = 0, k;
4827:   PetscErrorCode  ierr;

4830:   PetscSectionGetDof(section, point, &dof);
4831:   PetscSectionGetConstraintDof(section, point, &cdof);
4832:   if (!cdof || setBC) {
4833:     if (perm) {
4834:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4835:     } else {
4836:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4837:     }
4838:   } else {
4839:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4840:     if (perm) {
4841:       for (k = 0; k < dof; ++k) {
4842:         if ((cind < cdof) && (k == cdofs[cind])) {
4843:           /* Insert check for returning constrained indices */
4844:           indices[*loff+perm[k]] = -(off+k+1);
4845:           ++cind;
4846:         } else {
4847:           indices[*loff+perm[k]] = off+k-cind;
4848:         }
4849:       }
4850:     } else {
4851:       for (k = 0; k < dof; ++k) {
4852:         if ((cind < cdof) && (k == cdofs[cind])) {
4853:           /* Insert check for returning constrained indices */
4854:           indices[*loff+k] = -(off+k+1);
4855:           ++cind;
4856:         } else {
4857:           indices[*loff+k] = off+k-cind;
4858:         }
4859:       }
4860:     }
4861:   }
4862:   *loff += dof;
4863:   return(0);
4864: }

4866: /* . off - The global offset of this point */
4867: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4868: {
4869:   PetscInt       numFields, foff, f;

4873:   PetscSectionGetNumFields(section, &numFields);
4874:   for (f = 0, foff = 0; f < numFields; ++f) {
4875:     PetscInt        fdof, cfdof;
4876:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4877:     PetscInt        cind = 0, b;
4878:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4880:     PetscSectionGetFieldDof(section, point, f, &fdof);
4881:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4882:     if (!cfdof || setBC) {
4883:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4884:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4885:     } else {
4886:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4887:       if (perm) {
4888:         for (b = 0; b < fdof; b++) {
4889:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4890:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4891:             ++cind;
4892:           } else {
4893:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4894:           }
4895:         }
4896:       } else {
4897:         for (b = 0; b < fdof; b++) {
4898:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4899:             indices[foffs[f]+b] = -(off+foff+b+1);
4900:             ++cind;
4901:           } else {
4902:             indices[foffs[f]+b] = off+foff+b-cind;
4903:           }
4904:         }
4905:       }
4906:     }
4907:     foff     += (setBC ? fdof : (fdof - cfdof));
4908:     foffs[f] += fdof;
4909:   }
4910:   return(0);
4911: }

4913: 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)
4914: {
4915:   Mat             cMat;
4916:   PetscSection    aSec, cSec;
4917:   IS              aIS;
4918:   PetscInt        aStart = -1, aEnd = -1;
4919:   const PetscInt  *anchors;
4920:   PetscInt        numFields, f, p, q, newP = 0;
4921:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4922:   PetscInt        *newPoints, *indices, *newIndices;
4923:   PetscInt        maxAnchor, maxDof;
4924:   PetscInt        newOffsets[32];
4925:   PetscInt        *pointMatOffsets[32];
4926:   PetscInt        *newPointOffsets[32];
4927:   PetscScalar     *pointMat[32];
4928:   PetscScalar     *newValues=NULL,*tmpValues;
4929:   PetscBool       anyConstrained = PETSC_FALSE;
4930:   PetscErrorCode  ierr;

4935:   PetscSectionGetNumFields(section, &numFields);

4937:   DMPlexGetAnchors(dm,&aSec,&aIS);
4938:   /* if there are point-to-point constraints */
4939:   if (aSec) {
4940:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4941:     ISGetIndices(aIS,&anchors);
4942:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4943:     /* figure out how many points are going to be in the new element matrix
4944:      * (we allow double counting, because it's all just going to be summed
4945:      * into the global matrix anyway) */
4946:     for (p = 0; p < 2*numPoints; p+=2) {
4947:       PetscInt b    = points[p];
4948:       PetscInt bDof = 0, bSecDof;

4950:       PetscSectionGetDof(section,b,&bSecDof);
4951:       if (!bSecDof) {
4952:         continue;
4953:       }
4954:       if (b >= aStart && b < aEnd) {
4955:         PetscSectionGetDof(aSec,b,&bDof);
4956:       }
4957:       if (bDof) {
4958:         /* this point is constrained */
4959:         /* it is going to be replaced by its anchors */
4960:         PetscInt bOff, q;

4962:         anyConstrained = PETSC_TRUE;
4963:         newNumPoints  += bDof;
4964:         PetscSectionGetOffset(aSec,b,&bOff);
4965:         for (q = 0; q < bDof; q++) {
4966:           PetscInt a = anchors[bOff + q];
4967:           PetscInt aDof;

4969:           PetscSectionGetDof(section,a,&aDof);
4970:           newNumIndices += aDof;
4971:           for (f = 0; f < numFields; ++f) {
4972:             PetscInt fDof;

4974:             PetscSectionGetFieldDof(section, a, f, &fDof);
4975:             newOffsets[f+1] += fDof;
4976:           }
4977:         }
4978:       }
4979:       else {
4980:         /* this point is not constrained */
4981:         newNumPoints++;
4982:         newNumIndices += bSecDof;
4983:         for (f = 0; f < numFields; ++f) {
4984:           PetscInt fDof;

4986:           PetscSectionGetFieldDof(section, b, f, &fDof);
4987:           newOffsets[f+1] += fDof;
4988:         }
4989:       }
4990:     }
4991:   }
4992:   if (!anyConstrained) {
4993:     if (outNumPoints)  *outNumPoints  = 0;
4994:     if (outNumIndices) *outNumIndices = 0;
4995:     if (outPoints)     *outPoints     = NULL;
4996:     if (outValues)     *outValues     = NULL;
4997:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4998:     return(0);
4999:   }

5001:   if (outNumPoints)  *outNumPoints  = newNumPoints;
5002:   if (outNumIndices) *outNumIndices = newNumIndices;

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

5006:   if (!outPoints && !outValues) {
5007:     if (offsets) {
5008:       for (f = 0; f <= numFields; f++) {
5009:         offsets[f] = newOffsets[f];
5010:       }
5011:     }
5012:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5013:     return(0);
5014:   }

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

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

5020:   /* workspaces */
5021:   if (numFields) {
5022:     for (f = 0; f < numFields; f++) {
5023:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5024:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5025:     }
5026:   }
5027:   else {
5028:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5029:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5030:   }

5032:   /* get workspaces for the point-to-point matrices */
5033:   if (numFields) {
5034:     PetscInt totalOffset, totalMatOffset;

5036:     for (p = 0; p < numPoints; p++) {
5037:       PetscInt b    = points[2*p];
5038:       PetscInt bDof = 0, bSecDof;

5040:       PetscSectionGetDof(section,b,&bSecDof);
5041:       if (!bSecDof) {
5042:         for (f = 0; f < numFields; f++) {
5043:           newPointOffsets[f][p + 1] = 0;
5044:           pointMatOffsets[f][p + 1] = 0;
5045:         }
5046:         continue;
5047:       }
5048:       if (b >= aStart && b < aEnd) {
5049:         PetscSectionGetDof(aSec, b, &bDof);
5050:       }
5051:       if (bDof) {
5052:         for (f = 0; f < numFields; f++) {
5053:           PetscInt fDof, q, bOff, allFDof = 0;

5055:           PetscSectionGetFieldDof(section, b, f, &fDof);
5056:           PetscSectionGetOffset(aSec, b, &bOff);
5057:           for (q = 0; q < bDof; q++) {
5058:             PetscInt a = anchors[bOff + q];
5059:             PetscInt aFDof;

5061:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5062:             allFDof += aFDof;
5063:           }
5064:           newPointOffsets[f][p+1] = allFDof;
5065:           pointMatOffsets[f][p+1] = fDof * allFDof;
5066:         }
5067:       }
5068:       else {
5069:         for (f = 0; f < numFields; f++) {
5070:           PetscInt fDof;

5072:           PetscSectionGetFieldDof(section, b, f, &fDof);
5073:           newPointOffsets[f][p+1] = fDof;
5074:           pointMatOffsets[f][p+1] = 0;
5075:         }
5076:       }
5077:     }
5078:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5079:       newPointOffsets[f][0] = totalOffset;
5080:       pointMatOffsets[f][0] = totalMatOffset;
5081:       for (p = 0; p < numPoints; p++) {
5082:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5083:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5084:       }
5085:       totalOffset    = newPointOffsets[f][numPoints];
5086:       totalMatOffset = pointMatOffsets[f][numPoints];
5087:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5088:     }
5089:   }
5090:   else {
5091:     for (p = 0; p < numPoints; p++) {
5092:       PetscInt b    = points[2*p];
5093:       PetscInt bDof = 0, bSecDof;

5095:       PetscSectionGetDof(section,b,&bSecDof);
5096:       if (!bSecDof) {
5097:         newPointOffsets[0][p + 1] = 0;
5098:         pointMatOffsets[0][p + 1] = 0;
5099:         continue;
5100:       }
5101:       if (b >= aStart && b < aEnd) {
5102:         PetscSectionGetDof(aSec, b, &bDof);
5103:       }
5104:       if (bDof) {
5105:         PetscInt bOff, q, allDof = 0;

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

5111:           PetscSectionGetDof(section, a, &aDof);
5112:           allDof += aDof;
5113:         }
5114:         newPointOffsets[0][p+1] = allDof;
5115:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5116:       }
5117:       else {
5118:         newPointOffsets[0][p+1] = bSecDof;
5119:         pointMatOffsets[0][p+1] = 0;
5120:       }
5121:     }
5122:     newPointOffsets[0][0] = 0;
5123:     pointMatOffsets[0][0] = 0;
5124:     for (p = 0; p < numPoints; p++) {
5125:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5126:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5127:     }
5128:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5129:   }

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

5134:   /* get the point-to-point matrices; construct newPoints */
5135:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5136:   PetscSectionGetMaxDof(section, &maxDof);
5137:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5138:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5139:   if (numFields) {
5140:     for (p = 0, newP = 0; p < numPoints; p++) {
5141:       PetscInt b    = points[2*p];
5142:       PetscInt o    = points[2*p+1];
5143:       PetscInt bDof = 0, bSecDof;

5145:       PetscSectionGetDof(section, b, &bSecDof);
5146:       if (!bSecDof) {
5147:         continue;
5148:       }
5149:       if (b >= aStart && b < aEnd) {
5150:         PetscSectionGetDof(aSec, b, &bDof);
5151:       }
5152:       if (bDof) {
5153:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5155:         fStart[0] = 0;
5156:         fEnd[0]   = 0;
5157:         for (f = 0; f < numFields; f++) {
5158:           PetscInt fDof;

5160:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5161:           fStart[f+1] = fStart[f] + fDof;
5162:           fEnd[f+1]   = fStart[f+1];
5163:         }
5164:         PetscSectionGetOffset(cSec, b, &bOff);
5165:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

5167:         fAnchorStart[0] = 0;
5168:         fAnchorEnd[0]   = 0;
5169:         for (f = 0; f < numFields; f++) {
5170:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5172:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5173:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5174:         }
5175:         PetscSectionGetOffset(aSec, b, &bOff);
5176:         for (q = 0; q < bDof; q++) {
5177:           PetscInt a = anchors[bOff + q], aOff;

5179:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5180:           newPoints[2*(newP + q)]     = a;
5181:           newPoints[2*(newP + q) + 1] = 0;
5182:           PetscSectionGetOffset(section, a, &aOff);
5183:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5184:         }
5185:         newP += bDof;

5187:         if (outValues) {
5188:           /* get the point-to-point submatrix */
5189:           for (f = 0; f < numFields; f++) {
5190:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5191:           }
5192:         }
5193:       }
5194:       else {
5195:         newPoints[2 * newP]     = b;
5196:         newPoints[2 * newP + 1] = o;
5197:         newP++;
5198:       }
5199:     }
5200:   } else {
5201:     for (p = 0; p < numPoints; p++) {
5202:       PetscInt b    = points[2*p];
5203:       PetscInt o    = points[2*p+1];
5204:       PetscInt bDof = 0, bSecDof;

5206:       PetscSectionGetDof(section, b, &bSecDof);
5207:       if (!bSecDof) {
5208:         continue;
5209:       }
5210:       if (b >= aStart && b < aEnd) {
5211:         PetscSectionGetDof(aSec, b, &bDof);
5212:       }
5213:       if (bDof) {
5214:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5225:           newPoints[2*(newP + q)]     = a;
5226:           newPoints[2*(newP + q) + 1] = 0;
5227:           PetscSectionGetOffset(section, a, &aOff);
5228:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5229:         }
5230:         newP += bDof;

5232:         /* get the point-to-point submatrix */
5233:         if (outValues) {
5234:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5235:         }
5236:       }
5237:       else {
5238:         newPoints[2 * newP]     = b;
5239:         newPoints[2 * newP + 1] = o;
5240:         newP++;
5241:       }
5242:     }
5243:   }

5245:   if (outValues) {
5246:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5247:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5248:     /* multiply constraints on the right */
5249:     if (numFields) {
5250:       for (f = 0; f < numFields; f++) {
5251:         PetscInt oldOff = offsets[f];

5253:         for (p = 0; p < numPoints; p++) {
5254:           PetscInt cStart = newPointOffsets[f][p];
5255:           PetscInt b      = points[2 * p];
5256:           PetscInt c, r, k;
5257:           PetscInt dof;

5259:           PetscSectionGetFieldDof(section,b,f,&dof);
5260:           if (!dof) {
5261:             continue;
5262:           }
5263:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5264:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5265:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5267:             for (r = 0; r < numIndices; r++) {
5268:               for (c = 0; c < nCols; c++) {
5269:                 for (k = 0; k < dof; k++) {
5270:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5271:                 }
5272:               }
5273:             }
5274:           }
5275:           else {
5276:             /* copy this column as is */
5277:             for (r = 0; r < numIndices; r++) {
5278:               for (c = 0; c < dof; c++) {
5279:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5280:               }
5281:             }
5282:           }
5283:           oldOff += dof;
5284:         }
5285:       }
5286:     }
5287:     else {
5288:       PetscInt oldOff = 0;
5289:       for (p = 0; p < numPoints; p++) {
5290:         PetscInt cStart = newPointOffsets[0][p];
5291:         PetscInt b      = points[2 * p];
5292:         PetscInt c, r, k;
5293:         PetscInt dof;

5295:         PetscSectionGetDof(section,b,&dof);
5296:         if (!dof) {
5297:           continue;
5298:         }
5299:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5300:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5301:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5303:           for (r = 0; r < numIndices; r++) {
5304:             for (c = 0; c < nCols; c++) {
5305:               for (k = 0; k < dof; k++) {
5306:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5307:               }
5308:             }
5309:           }
5310:         }
5311:         else {
5312:           /* copy this column as is */
5313:           for (r = 0; r < numIndices; r++) {
5314:             for (c = 0; c < dof; c++) {
5315:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5316:             }
5317:           }
5318:         }
5319:         oldOff += dof;
5320:       }
5321:     }

5323:     if (multiplyLeft) {
5324:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5325:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5326:       /* multiply constraints transpose on the left */
5327:       if (numFields) {
5328:         for (f = 0; f < numFields; f++) {
5329:           PetscInt oldOff = offsets[f];

5331:           for (p = 0; p < numPoints; p++) {
5332:             PetscInt rStart = newPointOffsets[f][p];
5333:             PetscInt b      = points[2 * p];
5334:             PetscInt c, r, k;
5335:             PetscInt dof;

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

5342:               for (r = 0; r < nRows; r++) {
5343:                 for (c = 0; c < newNumIndices; c++) {
5344:                   for (k = 0; k < dof; k++) {
5345:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5346:                   }
5347:                 }
5348:               }
5349:             }
5350:             else {
5351:               /* copy this row as is */
5352:               for (r = 0; r < dof; r++) {
5353:                 for (c = 0; c < newNumIndices; c++) {
5354:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5355:                 }
5356:               }
5357:             }
5358:             oldOff += dof;
5359:           }
5360:         }
5361:       }
5362:       else {
5363:         PetscInt oldOff = 0;

5365:         for (p = 0; p < numPoints; p++) {
5366:           PetscInt rStart = newPointOffsets[0][p];
5367:           PetscInt b      = points[2 * p];
5368:           PetscInt c, r, k;
5369:           PetscInt dof;

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

5376:             for (r = 0; r < nRows; r++) {
5377:               for (c = 0; c < newNumIndices; c++) {
5378:                 for (k = 0; k < dof; k++) {
5379:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5380:                 }
5381:               }
5382:             }
5383:           }
5384:           else {
5385:             /* copy this row as is */
5386:             for (r = 0; r < dof; r++) {
5387:               for (c = 0; c < newNumIndices; c++) {
5388:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5389:               }
5390:             }
5391:           }
5392:           oldOff += dof;
5393:         }
5394:       }

5396:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5397:     }
5398:     else {
5399:       newValues = tmpValues;
5400:     }
5401:   }

5403:   /* clean up */
5404:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5405:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5407:   if (numFields) {
5408:     for (f = 0; f < numFields; f++) {
5409:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5410:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5411:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5412:     }
5413:   }
5414:   else {
5415:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5416:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5417:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5418:   }
5419:   ISRestoreIndices(aIS,&anchors);

5421:   /* output */
5422:   if (outPoints) {
5423:     *outPoints = newPoints;
5424:   }
5425:   else {
5426:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5427:   }
5428:   if (outValues) {
5429:     *outValues = newValues;
5430:   }
5431:   for (f = 0; f <= numFields; f++) {
5432:     offsets[f] = newOffsets[f];
5433:   }
5434:   return(0);
5435: }

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

5440:   Not collective

5442:   Input Parameters:
5443: + dm - The DM
5444: . section - The section describing the layout in v, or NULL to use the default section
5445: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5446: - point - The mesh point

5448:   Output parameters:
5449: + numIndices - The number of indices
5450: . indices - The indices
5451: - outOffsets - Field offset if not NULL

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

5455:   Level: advanced

5457: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5458: @*/
5459: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5460: {
5461:   PetscSection    clSection;
5462:   IS              clPoints;
5463:   const PetscInt *clp;
5464:   const PetscInt  **perms[32] = {NULL};
5465:   PetscInt       *points = NULL, *pointsNew;
5466:   PetscInt        numPoints, numPointsNew;
5467:   PetscInt        offsets[32];
5468:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5469:   PetscErrorCode  ierr;

5477:   PetscSectionGetNumFields(section, &Nf);
5478:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5479:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5480:   /* Get points in closure */
5481:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5482:   /* Get number of indices and indices per field */
5483:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5484:     PetscInt dof, fdof;

5486:     PetscSectionGetDof(section, points[p], &dof);
5487:     for (f = 0; f < Nf; ++f) {
5488:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5489:       offsets[f+1] += fdof;
5490:     }
5491:     Nind += dof;
5492:   }
5493:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5494:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5495:   if (!Nf) offsets[1] = Nind;
5496:   /* Get dual space symmetries */
5497:   for (f = 0; f < PetscMax(1,Nf); f++) {
5498:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5499:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5500:   }
5501:   /* Correct for hanging node constraints */
5502:   {
5503:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5504:     if (numPointsNew) {
5505:       for (f = 0; f < PetscMax(1,Nf); f++) {
5506:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5507:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5508:       }
5509:       for (f = 0; f < PetscMax(1,Nf); f++) {
5510:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5511:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5512:       }
5513:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5514:       numPoints = numPointsNew;
5515:       Nind      = NindNew;
5516:       points    = pointsNew;
5517:     }
5518:   }
5519:   /* Calculate indices */
5520:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5521:   if (Nf) {
5522:     if (outOffsets) {
5523:       PetscInt f;

5525:       for (f = 0; f <= Nf; f++) {
5526:         outOffsets[f] = offsets[f];
5527:       }
5528:     }
5529:     for (p = 0; p < numPoints; p++) {
5530:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5531:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5532:     }
5533:   } else {
5534:     for (p = 0, off = 0; p < numPoints; p++) {
5535:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5537:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5538:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5539:     }
5540:   }
5541:   /* Cleanup points */
5542:   for (f = 0; f < PetscMax(1,Nf); f++) {
5543:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5544:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5545:   }
5546:   if (numPointsNew) {
5547:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5548:   } else {
5549:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5550:   }
5551:   if (numIndices) *numIndices = Nind;
5552:   return(0);
5553: }

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

5558:   Not collective

5560:   Input Parameters:
5561: + dm - The DM
5562: . section - The section describing the layout in v, or NULL to use the default section
5563: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5564: . point - The mesh point
5565: . numIndices - The number of indices
5566: . indices - The indices
5567: - outOffsets - Field offset if not NULL

5569:   Level: advanced

5571: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5572: @*/
5573: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5574: {

5580:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5581:   return(0);
5582: }

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

5587:   Not collective

5589:   Input Parameters:
5590: + dm - The DM
5591: . section - The section describing the layout in v, or NULL to use the default section
5592: . globalSection - The section describing the layout in v, or NULL to use the default global section
5593: . A - The matrix
5594: . point - The point in the DM
5595: . values - The array of values
5596: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5601:   Level: intermediate

5603: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5604: @*/
5605: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5606: {
5607:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5608:   PetscSection        clSection;
5609:   IS                  clPoints;
5610:   PetscInt           *points = NULL, *newPoints;
5611:   const PetscInt     *clp;
5612:   PetscInt           *indices;
5613:   PetscInt            offsets[32];
5614:   const PetscInt    **perms[32] = {NULL};
5615:   const PetscScalar **flips[32] = {NULL};
5616:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5617:   PetscScalar        *valCopy = NULL;
5618:   PetscScalar        *newValues;
5619:   PetscErrorCode      ierr;

5623:   if (!section) {DMGetDefaultSection(dm, &section);}
5625:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5628:   PetscSectionGetNumFields(section, &numFields);
5629:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5630:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5631:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5632:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5633:     PetscInt fdof;

5635:     PetscSectionGetDof(section, points[p], &dof);
5636:     for (f = 0; f < numFields; ++f) {
5637:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5638:       offsets[f+1] += fdof;
5639:     }
5640:     numIndices += dof;
5641:   }
5642:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5656:         if (!numFields) {
5657:           PetscSectionGetDof(section,point,&fdof);
5658:         } else {
5659:           PetscSectionGetFieldDof(section,point,f,&fdof);
5660:         }
5661:         if (flip) {
5662:           PetscInt i, j, k;

5664:           if (!valCopy) {
5665:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5666:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5667:             values = valCopy;
5668:           }
5669:           for (i = 0; i < fdof; i++) {
5670:             PetscScalar fval = flip[i];

5672:             for (k = 0; k < numIndices; k++) {
5673:               valCopy[numIndices * (foffset + i) + k] *= fval;
5674:               valCopy[numIndices * k + (foffset + i)] *= fval;
5675:             }
5676:           }
5677:         }
5678:         foffset += fdof;
5679:       }
5680:     }
5681:   }
5682:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5683:   if (newNumPoints) {
5684:     if (valCopy) {
5685:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5686:     }
5687:     for (f = 0; f < PetscMax(1,numFields); f++) {
5688:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5689:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5690:     }
5691:     for (f = 0; f < PetscMax(1,numFields); f++) {
5692:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5693:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5694:     }
5695:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5696:     numPoints  = newNumPoints;
5697:     numIndices = newNumIndices;
5698:     points     = newPoints;
5699:     values     = newValues;
5700:   }
5701:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5702:   if (numFields) {
5703:     for (p = 0; p < numPoints; p++) {
5704:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5705:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5706:     }
5707:   } else {
5708:     for (p = 0, off = 0; p < numPoints; p++) {
5709:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5710:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5711:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5712:     }
5713:   }
5714:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5715:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5716:   if (mesh->printFEM > 1) {
5717:     PetscInt i;
5718:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5719:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5720:     PetscPrintf(PETSC_COMM_SELF, "\n");
5721:   }
5722:   if (ierr) {
5723:     PetscMPIInt    rank;
5724:     PetscErrorCode ierr2;

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

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

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

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

5829:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5830:     if (!dof) continue;
5831:     for (f = 0; f < numFields; ++f) {
5832:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5833:       foffsets[f+1] += fdof;
5834:     }
5835:     numFIndices += dof;
5836:   }
5837:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

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

5867:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5868:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5869:     for (p = 0, off = 0; p < numFPoints; p++) {
5870:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5872:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5873:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5874:     }
5875:     for (p = 0, off = 0; p < numCPoints; p++) {
5876:       const PetscInt *perm = permsC ? permsC[p] : NULL;

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

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

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

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

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

5981:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5982:     if (!dof) continue;
5983:     for (f = 0; f < numFields; ++f) {
5984:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5985:       foffsets[f+1] += fdof;
5986:     }
5987:     numFIndices += dof;
5988:   }
5989:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

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

6017:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6018:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6019:     for (p = 0, off = 0; p < numFPoints; p++) {
6020:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6022:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6023:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6024:     }
6025:     for (p = 0, off = 0; p < numCPoints; p++) {
6026:       const PetscInt *perm = permsC ? permsC[p] : NULL;

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

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

6042:   Input Parameter:
6043: . dm - The DMPlex object

6045:   Output Parameters:
6046: + cMax - The first hybrid cell
6047: . fMax - The first hybrid face
6048: . eMax - The first hybrid edge
6049: - vMax - The first hybrid vertex

6051:   Level: developer

6053: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6054: @*/
6055: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6056: {
6057:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6058:   PetscInt       dim;

6063:   DMGetDimension(dm, &dim);
6064:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6065:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
6066:   if (eMax) *eMax = mesh->hybridPointMax[1];
6067:   if (vMax) *vMax = mesh->hybridPointMax[0];
6068:   return(0);
6069: }

6071: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6072: {
6073:   IS             is, his;
6074:   PetscInt       first, stride;
6075:   PetscBool      isStride;

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

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

6095:   Input Parameters:
6096: . dm   - The DMPlex object
6097: . cMax - The first hybrid cell
6098: . fMax - The first hybrid face
6099: . eMax - The first hybrid edge
6100: - vMax - The first hybrid vertex

6102:   Level: developer

6104: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6105: @*/
6106: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6107: {
6108:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6109:   PetscInt       dim;
6110:   DMLabel        depthLabel;
6111:   DMLabel        dimLabel;

6116:   DMGetDimension(dm, &dim);
6117:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
6118:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
6119:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
6120:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
6121:   DMGetLabel(dm, "dim", &dimLabel);
6122:   if (!dimLabel) {
6123:     DMCreateLabel(dm, "dim");
6124:     DMGetLabel(dm, "dim", &dimLabel);
6125:   }
6126:   DMPlexGetDepthLabel(dm, &depthLabel);
6127:   if (cMax >= 0) {DMPlexCreateDimStratum(dm, depthLabel, dimLabel, dim, cMax);}
6128:   if (fMax >= 0) {DMPlexCreateDimStratum(dm, depthLabel, dimLabel, dim - 1, fMax);}
6129:   if (eMax >= 0) {DMPlexCreateDimStratum(dm, depthLabel, dimLabel, 1, eMax);}
6130:   if (vMax >= 0) {DMPlexCreateDimStratum(dm, depthLabel, dimLabel, 0, vMax);}
6131:   return(0);
6132: }

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

6137:   Input Parameter:
6138: . dm   - The DMPlex object

6140:   Output Parameter:
6141: . cellHeight - The height of a cell

6143:   Level: developer

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

6154:   *cellHeight = mesh->vtkCellHeight;
6155:   return(0);
6156: }

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

6161:   Input Parameters:
6162: + dm   - The DMPlex object
6163: - cellHeight - The height of a cell

6165:   Level: developer

6167: .seealso DMPlexGetVTKCellHeight()
6168: @*/
6169: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6170: {
6171:   DM_Plex *mesh = (DM_Plex*) dm->data;

6175:   mesh->vtkCellHeight = cellHeight;
6176:   return(0);
6177: }

6179: /* We can easily have a form that takes an IS instead */
6180: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6181: {
6182:   PetscSection   section, globalSection;
6183:   PetscInt      *numbers, p;

6187:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6188:   PetscSectionSetChart(section, pStart, pEnd);
6189:   for (p = pStart; p < pEnd; ++p) {
6190:     PetscSectionSetDof(section, p, 1);
6191:   }
6192:   PetscSectionSetUp(section);
6193:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6194:   PetscMalloc1(pEnd - pStart, &numbers);
6195:   for (p = pStart; p < pEnd; ++p) {
6196:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6197:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6198:     else                       numbers[p-pStart] += shift;
6199:   }
6200:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6201:   if (globalSize) {
6202:     PetscLayout layout;
6203:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6204:     PetscLayoutGetSize(layout, globalSize);
6205:     PetscLayoutDestroy(&layout);
6206:   }
6207:   PetscSectionDestroy(&section);
6208:   PetscSectionDestroy(&globalSection);
6209:   return(0);
6210: }

6212: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6213: {
6214:   PetscInt       cellHeight, cStart, cEnd, cMax;

6218:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6219:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6220:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6221:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6222:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6223:   return(0);
6224: }

6226: /*@C
6227:   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process

6229:   Input Parameter:
6230: . dm   - The DMPlex object

6232:   Output Parameter:
6233: . globalCellNumbers - Global cell numbers for all cells on this process

6235:   Level: developer

6237: .seealso DMPlexGetVertexNumbering()
6238: @*/
6239: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6240: {
6241:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6246:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6247:   *globalCellNumbers = mesh->globalCellNumbers;
6248:   return(0);
6249: }

6251: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6252: {
6253:   PetscInt       vStart, vEnd, vMax;

6258:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6259:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6260:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6261:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6262:   return(0);
6263: }

6265: /*@C
6266:   DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process

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

6271:   Output Parameter:
6272: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6274:   Level: developer

6276: .seealso DMPlexGetCellNumbering()
6277: @*/
6278: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6279: {
6280:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6285:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6286:   *globalVertexNumbers = mesh->globalVertexNumbers;
6287:   return(0);
6288: }

6290: /*@C
6291:   DMPlexCreatePointNumbering - Create a global numbering for all points on this process

6293:   Input Parameter:
6294: . dm   - The DMPlex object

6296:   Output Parameter:
6297: . globalPointNumbers - Global numbers for all points on this process

6299:   Level: developer

6301: .seealso DMPlexGetCellNumbering()
6302: @*/
6303: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6304: {
6305:   IS             nums[4];
6306:   PetscInt       depths[4];
6307:   PetscInt       depth, d, shift = 0;

6312:   DMPlexGetDepth(dm, &depth);
6313:   /* For unstratified meshes use dim instead of depth */
6314:   if (depth < 0) {DMGetDimension(dm, &depth);}
6315:   depths[0] = depth; depths[1] = 0;
6316:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6317:   for (d = 0; d <= depth; ++d) {
6318:     PetscInt pStart, pEnd, gsize;

6320:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6321:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6322:     shift += gsize;
6323:   }
6324:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6325:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6326:   return(0);
6327: }


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

6333:   Input Parameter:
6334: . dm - The DMPlex object

6336:   Output Parameter:
6337: . ranks - The rank field

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

6342:   Level: intermediate

6344: .seealso: DMView()
6345: @*/
6346: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6347: {
6348:   DM             rdm;
6349:   PetscDS        prob;
6350:   PetscFE        fe;
6351:   PetscScalar   *r;
6352:   PetscMPIInt    rank;
6353:   PetscInt       dim, cStart, cEnd, c;

6357:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6358:   DMClone(dm, &rdm);
6359:   DMGetDimension(rdm, &dim);
6360:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, NULL, -1, &fe);
6361:   PetscObjectSetName((PetscObject) fe, "rank");
6362:   DMGetDS(rdm, &prob);
6363:   PetscDSSetDiscretization(prob, 0, (PetscObject) fe);
6364:   PetscFEDestroy(&fe);
6365:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6366:   DMCreateGlobalVector(rdm, ranks);
6367:   PetscObjectSetName((PetscObject) *ranks, "partition");
6368:   VecGetArray(*ranks, &r);
6369:   for (c = cStart; c < cEnd; ++c) {
6370:     PetscScalar *lr;

6372:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6373:     *lr = rank;
6374:   }
6375:   VecRestoreArray(*ranks, &r);
6376:   DMDestroy(&rdm);
6377:   return(0);
6378: }

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

6383:   Input Parameter:
6384: . dm - The DMPlex object

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

6388:   Level: developer

6390: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6391: @*/
6392: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6393: {
6394:   PetscSection    coneSection, supportSection;
6395:   const PetscInt *cone, *support;
6396:   PetscInt        coneSize, c, supportSize, s;
6397:   PetscInt        pStart, pEnd, p, csize, ssize;
6398:   PetscErrorCode  ierr;

6402:   DMPlexGetConeSection(dm, &coneSection);
6403:   DMPlexGetSupportSection(dm, &supportSection);
6404:   /* Check that point p is found in the support of its cone points, and vice versa */
6405:   DMPlexGetChart(dm, &pStart, &pEnd);
6406:   for (p = pStart; p < pEnd; ++p) {
6407:     DMPlexGetConeSize(dm, p, &coneSize);
6408:     DMPlexGetCone(dm, p, &cone);
6409:     for (c = 0; c < coneSize; ++c) {
6410:       PetscBool dup = PETSC_FALSE;
6411:       PetscInt  d;
6412:       for (d = c-1; d >= 0; --d) {
6413:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6414:       }
6415:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6416:       DMPlexGetSupport(dm, cone[c], &support);
6417:       for (s = 0; s < supportSize; ++s) {
6418:         if (support[s] == p) break;
6419:       }
6420:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6421:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6422:         for (s = 0; s < coneSize; ++s) {
6423:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6424:         }
6425:         PetscPrintf(PETSC_COMM_SELF, "\n");
6426:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6427:         for (s = 0; s < supportSize; ++s) {
6428:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6429:         }
6430:         PetscPrintf(PETSC_COMM_SELF, "\n");
6431:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6432:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6433:       }
6434:     }
6435:     DMPlexGetSupportSize(dm, p, &supportSize);
6436:     DMPlexGetSupport(dm, p, &support);
6437:     for (s = 0; s < supportSize; ++s) {
6438:       DMPlexGetConeSize(dm, support[s], &coneSize);
6439:       DMPlexGetCone(dm, support[s], &cone);
6440:       for (c = 0; c < coneSize; ++c) {
6441:         if (cone[c] == p) break;
6442:       }
6443:       if (c >= coneSize) {
6444:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6445:         for (c = 0; c < supportSize; ++c) {
6446:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6447:         }
6448:         PetscPrintf(PETSC_COMM_SELF, "\n");
6449:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6450:         for (c = 0; c < coneSize; ++c) {
6451:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6452:         }
6453:         PetscPrintf(PETSC_COMM_SELF, "\n");
6454:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6455:       }
6456:     }
6457:   }
6458:   PetscSectionGetStorageSize(coneSection, &csize);
6459:   PetscSectionGetStorageSize(supportSection, &ssize);
6460:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6461:   return(0);
6462: }

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

6467:   Input Parameters:
6468: + dm - The DMPlex object
6469: . isSimplex - Are the cells simplices or tensor products
6470: - cellHeight - Normally 0

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

6474:   Level: developer

6476: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6477: @*/
6478: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6479: {
6480:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6485:   DMGetDimension(dm, &dim);
6486:   switch (dim) {
6487:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6488:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6489:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6490:   default:
6491:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6492:   }
6493:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6494:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6495:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6496:   cMax = cMax >= 0 ? cMax : cEnd;
6497:   for (c = cStart; c < cMax; ++c) {
6498:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6500:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6501:     for (cl = 0; cl < closureSize*2; cl += 2) {
6502:       const PetscInt p = closure[cl];
6503:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6504:     }
6505:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6506:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6507:   }
6508:   for (c = cMax; c < cEnd; ++c) {
6509:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6511:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6512:     for (cl = 0; cl < closureSize*2; cl += 2) {
6513:       const PetscInt p = closure[cl];
6514:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6515:     }
6516:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6517:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6518:   }
6519:   return(0);
6520: }

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

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

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

6532:   Level: developer

6534: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6535: @*/
6536: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6537: {
6538:   PetscInt       pMax[4];
6539:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6544:   DMGetDimension(dm, &dim);
6545:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6546:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6547:   for (h = cellHeight; h < dim; ++h) {
6548:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6549:     for (c = cStart; c < cEnd; ++c) {
6550:       const PetscInt *cone, *ornt, *faces;
6551:       PetscInt        numFaces, faceSize, coneSize,f;
6552:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6554:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6555:       DMPlexGetConeSize(dm, c, &coneSize);
6556:       DMPlexGetCone(dm, c, &cone);
6557:       DMPlexGetConeOrientation(dm, c, &ornt);
6558:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6559:       for (cl = 0; cl < closureSize*2; cl += 2) {
6560:         const PetscInt p = closure[cl];
6561:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6562:       }
6563:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6564:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6565:       for (f = 0; f < numFaces; ++f) {
6566:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6568:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6569:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6570:           const PetscInt p = fclosure[cl];
6571:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6572:         }
6573:         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);
6574:         for (v = 0; v < fnumCorners; ++v) {
6575:           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]);
6576:         }
6577:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6578:       }
6579:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6580:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6581:     }
6582:   }
6583:   return(0);
6584: }

6586: /* Pointwise interpolation
6587:      Just code FEM for now
6588:      u^f = I u^c
6589:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6590:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6591:      I_{ij} = psi^f_i phi^c_j
6592: */
6593: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6594: {
6595:   PetscSection   gsc, gsf;
6596:   PetscInt       m, n;
6597:   void          *ctx;
6598:   DM             cdm;
6599:   PetscBool      regular, ismatis;

6603:   DMGetDefaultGlobalSection(dmFine, &gsf);
6604:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6605:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6606:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6608:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
6609:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6610:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6611:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
6612:   DMGetApplicationContext(dmFine, &ctx);

6614:   DMGetCoarseDM(dmFine, &cdm);
6615:   DMPlexGetRegularRefinement(dmFine, &regular);
6616:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6617:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6618:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6619:   /* Use naive scaling */
6620:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6621:   return(0);
6622: }

6624: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6625: {
6627:   VecScatter     ctx;

6630:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6631:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6632:   VecScatterDestroy(&ctx);
6633:   return(0);
6634: }

6636: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6637: {
6638:   PetscSection   gsc, gsf;
6639:   PetscInt       m, n;
6640:   void          *ctx;
6641:   DM             cdm;
6642:   PetscBool      regular;

6646:   DMGetDefaultGlobalSection(dmFine, &gsf);
6647:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6648:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6649:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6651:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6652:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6653:   MatSetType(*mass, dmCoarse->mattype);
6654:   DMGetApplicationContext(dmFine, &ctx);

6656:   DMGetCoarseDM(dmFine, &cdm);
6657:   DMPlexGetRegularRefinement(dmFine, &regular);
6658:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6659:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6660:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6661:   return(0);
6662: }

6664: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6665: {
6666:   PetscSection   section;
6667:   IS            *bcPoints, *bcComps;
6668:   PetscBool     *isFE;
6669:   PetscInt      *bcFields, *numComp, *numDof;
6670:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6671:   PetscInt       cStart, cEnd, cEndInterior;

6675:   DMGetNumFields(dm, &numFields);
6676:   /* FE and FV boundary conditions are handled slightly differently */
6677:   PetscMalloc1(numFields, &isFE);
6678:   for (f = 0; f < numFields; ++f) {
6679:     PetscObject  obj;
6680:     PetscClassId id;

6682:     DMGetField(dm, f, &obj);
6683:     PetscObjectGetClassId(obj, &id);
6684:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6685:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6686:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6687:   }
6688:   /* Allocate boundary point storage for FEM boundaries */
6689:   DMPlexGetDepth(dm, &depth);
6690:   DMGetDimension(dm, &dim);
6691:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6692:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6693:   PetscDSGetNumBoundary(dm->prob, &numBd);
6694:   if (!numFields && numBd) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "number of fields is zero and number of boundary conditions is nonzero (this should never happen)");
6695:   for (bd = 0; bd < numBd; ++bd) {
6696:     PetscInt                field;
6697:     DMBoundaryConditionType type;
6698:     const char             *labelName;
6699:     DMLabel                 label;

6701:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6702:     DMGetLabel(dm,labelName,&label);
6703:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6704:   }
6705:   /* Add ghost cell boundaries for FVM */
6706:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6707:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6708:   /* Constrain ghost cells for FV */
6709:   for (f = 0; f < numFields; ++f) {
6710:     PetscInt *newidx, c;

6712:     if (isFE[f] || cEndInterior < 0) continue;
6713:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6714:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6715:     bcFields[bc] = f;
6716:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6717:   }
6718:   /* Handle FEM Dirichlet boundaries */
6719:   for (bd = 0; bd < numBd; ++bd) {
6720:     const char             *bdLabel;
6721:     DMLabel                 label;
6722:     const PetscInt         *comps;
6723:     const PetscInt         *values;
6724:     PetscInt                bd2, field, numComps, numValues;
6725:     DMBoundaryConditionType type;
6726:     PetscBool               duplicate = PETSC_FALSE;

6728:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6729:     DMGetLabel(dm, bdLabel, &label);
6730:     if (!isFE[field] || !label) continue;
6731:     /* Only want to modify label once */
6732:     for (bd2 = 0; bd2 < bd; ++bd2) {
6733:       const char *bdname;
6734:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6735:       PetscStrcmp(bdname, bdLabel, &duplicate);
6736:       if (duplicate) break;
6737:     }
6738:     if (!duplicate && (isFE[field])) {
6739:       /* don't complete cells, which are just present to give orientation to the boundary */
6740:       DMPlexLabelComplete(dm, label);
6741:     }
6742:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6743:     if (type & DM_BC_ESSENTIAL) {
6744:       PetscInt       *newidx;
6745:       PetscInt        n, newn = 0, p, v;

6747:       bcFields[bc] = field;
6748:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6749:       for (v = 0; v < numValues; ++v) {
6750:         IS              tmp;
6751:         const PetscInt *idx;

6753:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6754:         if (!tmp) continue;
6755:         ISGetLocalSize(tmp, &n);
6756:         ISGetIndices(tmp, &idx);
6757:         if (isFE[field]) {
6758:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6759:         } else {
6760:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6761:         }
6762:         ISRestoreIndices(tmp, &idx);
6763:         ISDestroy(&tmp);
6764:       }
6765:       PetscMalloc1(newn,&newidx);
6766:       newn = 0;
6767:       for (v = 0; v < numValues; ++v) {
6768:         IS              tmp;
6769:         const PetscInt *idx;

6771:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6772:         if (!tmp) continue;
6773:         ISGetLocalSize(tmp, &n);
6774:         ISGetIndices(tmp, &idx);
6775:         if (isFE[field]) {
6776:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6777:         } else {
6778:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6779:         }
6780:         ISRestoreIndices(tmp, &idx);
6781:         ISDestroy(&tmp);
6782:       }
6783:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6784:     }
6785:   }
6786:   /* Handle discretization */
6787:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6788:   for (f = 0; f < numFields; ++f) {
6789:     PetscObject obj;

6791:     DMGetField(dm, f, &obj);
6792:     if (isFE[f]) {
6793:       PetscFE         fe = (PetscFE) obj;
6794:       const PetscInt *numFieldDof;
6795:       PetscInt        d;

6797:       PetscFEGetNumComponents(fe, &numComp[f]);
6798:       PetscFEGetNumDof(fe, &numFieldDof);
6799:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6800:     } else {
6801:       PetscFV fv = (PetscFV) obj;

6803:       PetscFVGetNumComponents(fv, &numComp[f]);
6804:       numDof[f*(dim+1)+dim] = numComp[f];
6805:     }
6806:   }
6807:   for (f = 0; f < numFields; ++f) {
6808:     PetscInt d;
6809:     for (d = 1; d < dim; ++d) {
6810:       if ((numDof[f*(dim+1)+d] > 0) && (depth < dim)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces.");
6811:     }
6812:   }
6813:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6814:   for (f = 0; f < numFields; ++f) {
6815:     PetscFE     fe;
6816:     const char *name;

6818:     DMGetField(dm, f, (PetscObject *) &fe);
6819:     PetscObjectGetName((PetscObject) fe, &name);
6820:     PetscSectionSetFieldName(section, f, name);
6821:   }
6822:   DMSetDefaultSection(dm, section);
6823:   PetscSectionDestroy(&section);
6824:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6825:   PetscFree3(bcFields,bcPoints,bcComps);
6826:   PetscFree2(numComp,numDof);
6827:   PetscFree(isFE);
6828:   return(0);
6829: }

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

6834:   Input Parameter:
6835: . dm - The DMPlex object

6837:   Output Parameter:
6838: . regular - The flag

6840:   Level: intermediate

6842: .seealso: DMPlexSetRegularRefinement()
6843: @*/
6844: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6845: {
6849:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6850:   return(0);
6851: }

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

6856:   Input Parameters:
6857: + dm - The DMPlex object
6858: - regular - The flag

6860:   Level: intermediate

6862: .seealso: DMPlexGetRegularRefinement()
6863: @*/
6864: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6865: {
6868:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6869:   return(0);
6870: }

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

6877:   not collective

6879:   Input Parameters:
6880: . dm - The DMPlex object

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


6887:   Level: intermediate

6889: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6890: @*/
6891: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6892: {
6893:   DM_Plex *plex = (DM_Plex *)dm->data;

6898:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6899:   if (anchorSection) *anchorSection = plex->anchorSection;
6900:   if (anchorIS) *anchorIS = plex->anchorIS;
6901:   return(0);
6902: }

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

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

6912:   collective on dm

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

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

6921:   Level: intermediate

6923: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6924: @*/
6925: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6926: {
6927:   DM_Plex        *plex = (DM_Plex *)dm->data;
6928:   PetscMPIInt    result;

6933:   if (anchorSection) {
6935:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6936:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6937:   }
6938:   if (anchorIS) {
6940:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6941:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6942:   }

6944:   PetscObjectReference((PetscObject)anchorSection);
6945:   PetscSectionDestroy(&plex->anchorSection);
6946:   plex->anchorSection = anchorSection;

6948:   PetscObjectReference((PetscObject)anchorIS);
6949:   ISDestroy(&plex->anchorIS);
6950:   plex->anchorIS = anchorIS;

6952: #if defined(PETSC_USE_DEBUG)
6953:   if (anchorIS && anchorSection) {
6954:     PetscInt size, a, pStart, pEnd;
6955:     const PetscInt *anchors;

6957:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6958:     ISGetLocalSize(anchorIS,&size);
6959:     ISGetIndices(anchorIS,&anchors);
6960:     for (a = 0; a < size; a++) {
6961:       PetscInt p;

6963:       p = anchors[a];
6964:       if (p >= pStart && p < pEnd) {
6965:         PetscInt dof;

6967:         PetscSectionGetDof(anchorSection,p,&dof);
6968:         if (dof) {
6969:           PetscErrorCode ierr2;

6971:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6972:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6973:         }
6974:       }
6975:     }
6976:     ISRestoreIndices(anchorIS,&anchors);
6977:   }
6978: #endif
6979:   /* reset the generic constraints */
6980:   DMSetDefaultConstraints(dm,NULL,NULL);
6981:   return(0);
6982: }

6984: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6985: {
6986:   PetscSection anchorSection;
6987:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6992:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6993:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6994:   PetscSectionGetNumFields(section,&numFields);
6995:   if (numFields) {
6996:     PetscInt f;
6997:     PetscSectionSetNumFields(*cSec,numFields);

6999:     for (f = 0; f < numFields; f++) {
7000:       PetscInt numComp;

7002:       PetscSectionGetFieldComponents(section,f,&numComp);
7003:       PetscSectionSetFieldComponents(*cSec,f,numComp);
7004:     }
7005:   }
7006:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7007:   PetscSectionGetChart(section,&sStart,&sEnd);
7008:   pStart = PetscMax(pStart,sStart);
7009:   pEnd   = PetscMin(pEnd,sEnd);
7010:   pEnd   = PetscMax(pStart,pEnd);
7011:   PetscSectionSetChart(*cSec,pStart,pEnd);
7012:   for (p = pStart; p < pEnd; p++) {
7013:     PetscSectionGetDof(anchorSection,p,&dof);
7014:     if (dof) {
7015:       PetscSectionGetDof(section,p,&dof);
7016:       PetscSectionSetDof(*cSec,p,dof);
7017:       for (f = 0; f < numFields; f++) {
7018:         PetscSectionGetFieldDof(section,p,f,&dof);
7019:         PetscSectionSetFieldDof(*cSec,p,f,dof);
7020:       }
7021:     }
7022:   }
7023:   PetscSectionSetUp(*cSec);
7024:   return(0);
7025: }

7027: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7028: {
7029:   PetscSection aSec;
7030:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7031:   const PetscInt *anchors;
7032:   PetscInt numFields, f;
7033:   IS aIS;

7038:   PetscSectionGetStorageSize(cSec, &m);
7039:   PetscSectionGetStorageSize(section, &n);
7040:   MatCreate(PETSC_COMM_SELF,cMat);
7041:   MatSetSizes(*cMat,m,n,m,n);
7042:   MatSetType(*cMat,MATSEQAIJ);
7043:   DMPlexGetAnchors(dm,&aSec,&aIS);
7044:   ISGetIndices(aIS,&anchors);
7045:   /* cSec will be a subset of aSec and section */
7046:   PetscSectionGetChart(cSec,&pStart,&pEnd);
7047:   PetscMalloc1(m+1,&i);
7048:   i[0] = 0;
7049:   PetscSectionGetNumFields(section,&numFields);
7050:   for (p = pStart; p < pEnd; p++) {
7051:     PetscInt rDof, rOff, r;

7053:     PetscSectionGetDof(aSec,p,&rDof);
7054:     if (!rDof) continue;
7055:     PetscSectionGetOffset(aSec,p,&rOff);
7056:     if (numFields) {
7057:       for (f = 0; f < numFields; f++) {
7058:         annz = 0;
7059:         for (r = 0; r < rDof; r++) {
7060:           a = anchors[rOff + r];
7061:           PetscSectionGetFieldDof(section,a,f,&aDof);
7062:           annz += aDof;
7063:         }
7064:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7065:         PetscSectionGetFieldOffset(cSec,p,f,&off);
7066:         for (q = 0; q < dof; q++) {
7067:           i[off + q + 1] = i[off + q] + annz;
7068:         }
7069:       }
7070:     }
7071:     else {
7072:       annz = 0;
7073:       for (q = 0; q < dof; q++) {
7074:         a = anchors[off + q];
7075:         PetscSectionGetDof(section,a,&aDof);
7076:         annz += aDof;
7077:       }
7078:       PetscSectionGetDof(cSec,p,&dof);
7079:       PetscSectionGetOffset(cSec,p,&off);
7080:       for (q = 0; q < dof; q++) {
7081:         i[off + q + 1] = i[off + q] + annz;
7082:       }
7083:     }
7084:   }
7085:   nnz = i[m];
7086:   PetscMalloc1(nnz,&j);
7087:   offset = 0;
7088:   for (p = pStart; p < pEnd; p++) {
7089:     if (numFields) {
7090:       for (f = 0; f < numFields; f++) {
7091:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7092:         for (q = 0; q < dof; q++) {
7093:           PetscInt rDof, rOff, r;
7094:           PetscSectionGetDof(aSec,p,&rDof);
7095:           PetscSectionGetOffset(aSec,p,&rOff);
7096:           for (r = 0; r < rDof; r++) {
7097:             PetscInt s;

7099:             a = anchors[rOff + r];
7100:             PetscSectionGetFieldDof(section,a,f,&aDof);
7101:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7102:             for (s = 0; s < aDof; s++) {
7103:               j[offset++] = aOff + s;
7104:             }
7105:           }
7106:         }
7107:       }
7108:     }
7109:     else {
7110:       PetscSectionGetDof(cSec,p,&dof);
7111:       for (q = 0; q < dof; q++) {
7112:         PetscInt rDof, rOff, r;
7113:         PetscSectionGetDof(aSec,p,&rDof);
7114:         PetscSectionGetOffset(aSec,p,&rOff);
7115:         for (r = 0; r < rDof; r++) {
7116:           PetscInt s;

7118:           a = anchors[rOff + r];
7119:           PetscSectionGetDof(section,a,&aDof);
7120:           PetscSectionGetOffset(section,a,&aOff);
7121:           for (s = 0; s < aDof; s++) {
7122:             j[offset++] = aOff + s;
7123:           }
7124:         }
7125:       }
7126:     }
7127:   }
7128:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7129:   PetscFree(i);
7130:   PetscFree(j);
7131:   ISRestoreIndices(aIS,&anchors);
7132:   return(0);
7133: }

7135: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7136: {
7137:   DM_Plex        *plex = (DM_Plex *)dm->data;
7138:   PetscSection   anchorSection, section, cSec;
7139:   Mat            cMat;

7144:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7145:   if (anchorSection) {
7146:     PetscDS  ds;
7147:     PetscInt nf;

7149:     DMGetDefaultSection(dm,&section);
7150:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7151:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7152:     DMGetDS(dm,&ds);
7153:     PetscDSGetNumFields(ds,&nf);
7154:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7155:     DMSetDefaultConstraints(dm,cSec,cMat);
7156:     PetscSectionDestroy(&cSec);
7157:     MatDestroy(&cMat);
7158:   }
7159:   return(0);
7160: }