Actual source code: plex.c
petsc-3.10.5 2019-03-28
Report Typos and Errors

      1:  #include <petsc/private/dmpleximpl.h>
      2:  #include <petsc/private/isimpl.h>
      3:  #include <petsc/private/vecimpl.h>
      4:  #include <petsc/private/glvisvecimpl.h>
      5:  #include <petscsf.h>
      6:  #include <petscds.h>
      7:  #include <petscdraw.h>
      8:  #include <petscdmfield.h>

     10: /* Logging support */
     11: PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;

     13: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

     15: /*@
     16:   DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells.
     17:   3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D.

     19:   Collective

     21:   Input Parameters:
     22: . dm - The DMPlex object

     24:   Output Parameters:
     25: . dmRefined - The refined DMPlex object

     27:   Note: Returns NULL if the mesh is already a tensor product mesh.

     29:   Level: intermediate

     31: .seealso: DMPlexCreate(), DMPlexSetRefinementUniform()
     32: @*/
     33: PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined)
     34: {
     35:   PetscInt         dim, cMax, fMax, cStart, cEnd, coneSize;
     36:   CellRefiner      cellRefiner;
     37:   PetscBool        lop, allnoop, localized;
     38:   PetscErrorCode   ierr;

     43:   DMGetDimension(dm, &dim);
     44:   DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
     45:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
     46:   if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
     47:   else {
     48:     DMPlexGetConeSize(dm,cStart,&coneSize);
     49:     switch (dim) {
     50:     case 1:
     51:       cellRefiner = REFINER_NOOP;
     52:     break;
     53:     case 2:
     54:       switch (coneSize) {
     55:       case 3:
     56:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
     57:         else cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
     58:       break;
     59:       case 4:
     60:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
     61:         else cellRefiner = REFINER_NOOP;
     62:       break;
     63:       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
     64:       }
     65:     break;
     66:     case 3:
     67:       switch (coneSize) {
     68:       case 4:
     69:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
     70:         else cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
     71:       break;
     72:       case 5:
     73:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
     74:         else cellRefiner = REFINER_NOOP;
     75:       break;
     76:       case 6:
     77:         if (cMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Simplex2Tensor in 3D with Hybrid mesh not yet done");
     78:         cellRefiner = REFINER_NOOP;
     79:       break;
     80:       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
     81:       }
     82:     break;
     83:     default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
     84:     }
     85:   }
     86:   /* return if we don't need to refine */
     87:   lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
     88:   MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
     89:   if (allnoop) {
     90:     *dmRefined = NULL;
     91:     return(0);
     92:   }
     93:   DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
     94:   DMCopyBoundary(dm, *dmRefined);
     95:   DMGetCoordinatesLocalized(dm, &localized);
     96:   if (localized) {
     97:     DMLocalizeCoordinates(*dmRefined);
     98:   }
     99:   return(0);
    100: }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    410:   VecGetDM(originalv, &dm);
    411:   PetscObjectGetComm((PetscObject) originalv, &comm);
    412:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
    413:   PetscViewerGetFormat(viewer, &format);
    414:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
    415:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
    416:   if (format == PETSC_VIEWER_NATIVE) {
    417:     const char *vecname;
    418:     PetscInt    n, nroots;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    967:         DMLabelGetStratumSize(label, values[v], &size);
    968:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
    969:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
    970:       }
    971:       PetscViewerASCIIPrintf(viewer, ")\n");
    972:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
    973:       ISRestoreIndices(valueIS, &values);
    974:       ISDestroy(&valueIS);
    975:     }
    976:     DMGetCoarseDM(dm, &cdm);
    977:     if (cdm) {
    978:       PetscViewerASCIIPushTab(viewer);
    979:       DMPlexView_Ascii(cdm, viewer);
    980:       PetscViewerASCIIPopTab(viewer);
    981:     }
    982:   }
    983:   return(0);
    984: }

    986: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
    987: {
    988:   PetscDraw          draw;
    989:   DM                 cdm;
    990:   PetscSection       coordSection;
    991:   Vec                coordinates;
    992:   const PetscScalar *coords;
    993:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
    994:   PetscBool          isnull;
    995:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
    996:   PetscMPIInt        rank;
    997:   PetscErrorCode     ierr;

    1000:   DMGetCoordinateDim(dm, &dim);
    1001:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
    1002:   DMGetCoordinateDM(dm, &cdm);
    1003:   DMGetSection(cdm, &coordSection);
    1004:   DMGetCoordinatesLocal(dm, &coordinates);
    1005:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    1006:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

    1008:   PetscViewerDrawGetDraw(viewer, 0, &draw);
    1009:   PetscDrawIsNull(draw, &isnull);
    1010:   if (isnull) return(0);
    1011:   PetscDrawSetTitle(draw, "Mesh");

    1013:   VecGetLocalSize(coordinates, &N);
    1014:   VecGetArrayRead(coordinates, &coords);
    1015:   for (c = 0; c < N; c += dim) {
    1016:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
    1017:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
    1018:   }
    1019:   VecRestoreArrayRead(coordinates, &coords);
    1020:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
    1021:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
    1022:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
    1023:   PetscDrawClear(draw);

    1025:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
    1026:   for (c = cStart; c < cEnd; ++c) {
    1027:     PetscScalar *coords = NULL;
    1028:     PetscInt     numCoords,coneSize;

    1030:     DMPlexGetConeSize(dm, c, &coneSize);
    1031:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
    1032:     switch (coneSize) {
    1033:     case 3:
    1034:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
    1035:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
    1036:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
    1037:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
    1038:       break;
    1039:     case 4:
    1040:       PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
    1041:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
    1042:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
    1043:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
    1044:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
    1045:       break;
    1046:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
    1047:     }
    1048:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
    1049:   }
    1050:   for (c = cStart; c < cEnd; ++c) {
    1051:     PetscScalar *coords = NULL;
    1052:     PetscInt     numCoords,coneSize;

    1054:     DMPlexGetConeSize(dm, c, &coneSize);
    1055:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
    1056:     switch (coneSize) {
    1057:     case 3:
    1058:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
    1059:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
    1060:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
    1061:       break;
    1062:     case 4:
    1063:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
    1064:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
    1065:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
    1066:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
    1067:       break;
    1068:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
    1069:     }
    1070:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
    1071:   }
    1072:   PetscDrawFlush(draw);
    1073:   PetscDrawPause(draw);
    1074:   PetscDrawSave(draw);
    1075:   return(0);
    1076: }

    1078: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
    1079: {
    1080:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
    1081:   PetscErrorCode    ierr;

    1086:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
    1087:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
    1088:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
    1089:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
    1090:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
    1091:   if (iascii) {
    1092:     PetscViewerFormat format;
    1093:     PetscViewerGetFormat(viewer, &format);
    1094:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
    1095:       DMPlexView_GLVis(dm, viewer);
    1096:     } else {
    1097:       DMPlexView_Ascii(dm, viewer);
    1098:     }
    1099:   } else if (ishdf5) {
    1100: #if defined(PETSC_HAVE_HDF5)
    1101:     DMPlexView_HDF5_Internal(dm, viewer);
    1102: #else
    1103:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
    1104: #endif
    1105:   } else if (isvtk) {
    1106:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
    1107:   } else if (isdraw) {
    1108:     DMPlexView_Draw(dm, viewer);
    1109:   } else if (isglvis) {
    1110:     DMPlexView_GLVis(dm, viewer);
    1111:   } else {
    1112:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
    1113:   }
    1114:   /* Optionally view the partition */
    1115:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
    1116:   if (flg) {
    1117:     Vec ranks;
    1118:     DMPlexCreateRankField(dm, &ranks);
    1119:     VecView(ranks, viewer);
    1120:     VecDestroy(&ranks);
    1121:   }
    1122:   return(0);
    1123: }

    1125: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
    1126: {
    1127:   PetscBool      ishdf5;

    1133:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
    1134:   if (ishdf5) {
    1135: #if defined(PETSC_HAVE_HDF5)
    1136:     PetscViewerFormat format;
    1137:     PetscViewerGetFormat(viewer, &format);
    1138:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
    1139:       DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
    1140:     } else {
    1141:       DMPlexLoad_HDF5_Internal(dm, viewer);
    1142:     }
    1143: #else
    1144:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
    1145: #endif
    1146:   } else {
    1147:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
    1148:   }
    1149:   return(0);
    1150: }

    1152: PetscErrorCode DMDestroy_Plex(DM dm)
    1153: {
    1154:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    1158:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
    1159:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
    1160:   if (--mesh->refct > 0) return(0);
    1161:   PetscSectionDestroy(&mesh->coneSection);
    1162:   PetscFree(mesh->cones);
    1163:   PetscFree(mesh->coneOrientations);
    1164:   PetscSectionDestroy(&mesh->supportSection);
    1165:   PetscSectionDestroy(&mesh->subdomainSection);
    1166:   PetscFree(mesh->supports);
    1167:   PetscFree(mesh->facesTmp);
    1168:   PetscFree(mesh->tetgenOpts);
    1169:   PetscFree(mesh->triangleOpts);
    1170:   PetscPartitionerDestroy(&mesh->partitioner);
    1171:   DMLabelDestroy(&mesh->subpointMap);
    1172:   ISDestroy(&mesh->globalVertexNumbers);
    1173:   ISDestroy(&mesh->globalCellNumbers);
    1174:   PetscSectionDestroy(&mesh->anchorSection);
    1175:   ISDestroy(&mesh->anchorIS);
    1176:   PetscSectionDestroy(&mesh->parentSection);
    1177:   PetscFree(mesh->parents);
    1178:   PetscFree(mesh->childIDs);
    1179:   PetscSectionDestroy(&mesh->childSection);
    1180:   PetscFree(mesh->children);
    1181:   DMDestroy(&mesh->referenceTree);
    1182:   PetscGridHashDestroy(&mesh->lbox);
    1183:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
    1184:   PetscFree(mesh);
    1185:   return(0);
    1186: }

    1188: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
    1189: {
    1190:   PetscSection           sectionGlobal;
    1191:   PetscInt               bs = -1, mbs;
    1192:   PetscInt               localSize;
    1193:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
    1194:   PetscErrorCode         ierr;
    1195:   MatType                mtype;
    1196:   ISLocalToGlobalMapping ltog;

    1199:   MatInitializePackage();
    1200:   mtype = dm->mattype;
    1201:   DMGetGlobalSection(dm, &sectionGlobal);
    1202:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
    1203:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
    1204:   MatCreate(PetscObjectComm((PetscObject)dm), J);
    1205:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
    1206:   MatSetType(*J, mtype);
    1207:   MatSetFromOptions(*J);
    1208:   MatGetBlockSize(*J, &mbs);
    1209:   if (mbs > 1) bs = mbs;
    1210:   PetscStrcmp(mtype, MATSHELL, &isShell);
    1211:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
    1212:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
    1213:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
    1214:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
    1215:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
    1216:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
    1217:   PetscStrcmp(mtype, MATIS, &isMatIS);
    1218:   if (!isShell) {
    1219:     PetscSection subSection;
    1220:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
    1221:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
    1222:     PetscInt     pStart, pEnd, p, dof, cdof;

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

    1229:       DMGetSection(dm, &section);
    1230:       PetscSectionGetStorageSize(section, &size);
    1231:       PetscMalloc1(size,&ltogidx);
    1232:       DMPlexGetSubdomainSection(dm, &subSection);
    1233:     } else {
    1234:       DMGetLocalToGlobalMapping(dm,&ltog);
    1235:     }
    1236:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
    1237:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
    1238:       PetscInt bdof;

    1240:       PetscSectionGetDof(sectionGlobal, p, &dof);
    1241:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
    1242:       dof  = dof < 0 ? -(dof+1) : dof;
    1243:       bdof = cdof && (dof-cdof) ? 1 : dof;
    1244:       if (dof) {
    1245:         if (bs < 0)          {bs = bdof;}
    1246:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
    1247:       }
    1248:       if (isMatIS) {
    1249:         PetscInt loff,c,off;
    1250:         PetscSectionGetOffset(subSection, p, &loff);
    1251:         PetscSectionGetOffset(sectionGlobal, p, &off);
    1252:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
    1253:       }
    1254:     }
    1255:     /* Must have same blocksize on all procs (some might have no points) */
    1256:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
    1257:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
    1258:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
    1259:     else                            {bs = bsMinMax[0];}
    1260:     bs = bs < 0 ? 1 : bs;
    1261:     if (isMatIS) {
    1262:       PetscInt l;
    1263:       /* Must reduce indices by blocksize */
    1264:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
    1265:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
    1266:     }
    1267:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
    1268:     if (isMatIS) {
    1269:       ISLocalToGlobalMappingDestroy(&ltog);
    1270:     }
    1271:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
    1272:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
    1273:     PetscFree4(dnz, onz, dnzu, onzu);
    1274:   }
    1275:   MatSetDM(*J, dm);
    1276:   return(0);
    1277: }

    1279: /*@
    1280:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

    1282:   Not collective

    1284:   Input Parameter:
    1285: . mesh - The DMPlex

    1287:   Output Parameters:
    1288: . subsection - The subdomain section

    1290:   Level: developer

    1292: .seealso:
    1293: @*/
    1294: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
    1295: {
    1296:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    1301:   if (!mesh->subdomainSection) {
    1302:     PetscSection section;
    1303:     PetscSF      sf;

    1305:     PetscSFCreate(PETSC_COMM_SELF,&sf);
    1306:     DMGetSection(dm,&section);
    1307:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
    1308:     PetscSFDestroy(&sf);
    1309:   }
    1310:   *subsection = mesh->subdomainSection;
    1311:   return(0);
    1312: }

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

    1317:   Not collective

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

    1322:   Output Parameters:
    1323: + pStart - The first mesh point
    1324: - pEnd   - The upper bound for mesh points

    1326:   Level: beginner

    1328: .seealso: DMPlexCreate(), DMPlexSetChart()
    1329: @*/
    1330: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
    1331: {
    1332:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    1337:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
    1338:   return(0);
    1339: }

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

    1344:   Not collective

    1346:   Input Parameters:
    1347: + mesh - The DMPlex
    1348: . pStart - The first mesh point
    1349: - pEnd   - The upper bound for mesh points

    1351:   Output Parameters:

    1353:   Level: beginner

    1355: .seealso: DMPlexCreate(), DMPlexGetChart()
    1356: @*/
    1357: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
    1358: {
    1359:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    1364:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
    1365:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
    1366:   return(0);
    1367: }

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

    1372:   Not collective

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

    1378:   Output Parameter:
    1379: . size - The cone size for point p

    1381:   Level: beginner

    1383: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
    1384: @*/
    1385: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
    1386: {
    1387:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    1393:   PetscSectionGetDof(mesh->coneSection, p, size);
    1394:   return(0);
    1395: }

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

    1400:   Not collective

    1402:   Input Parameters:
    1403: + mesh - The DMPlex
    1404: . p - The point, which must lie in the chart set with DMPlexSetChart()
    1405: - size - The cone size for point p

    1407:   Output Parameter:

    1409:   Note:
    1410:   This should be called after DMPlexSetChart().

    1412:   Level: beginner

    1414: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
    1415: @*/
    1416: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
    1417: {
    1418:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

    1425:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
    1426:   return(0);
    1427: }

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

    1432:   Not collective

    1434:   Input Parameters:
    1435: + mesh - The DMPlex
    1436: . p - The point, which must lie in the chart set with DMPlexSetChart()
    1437: - size - The additional cone size for point p

    1439:   Output Parameter:

    1441:   Note:
    1442:   This should be called after DMPlexSetChart().

    1444:   Level: beginner

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

    1456:   PetscSectionAddDof(mesh->coneSection, p, size);
    1457:   PetscSectionGetDof(mesh->coneSection, p, &csize);

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

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

    1466:   Not collective

    1468:   Input Parameters:
    1469: + mesh - The DMPlex
    1470: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

    1475:   Level: beginner

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

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

    1483: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
    1484: @*/
    1485: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
    1486: {
    1487:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1488:   PetscInt       off;

    1494:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    1495:   *cone = &mesh->cones[off];
    1496:   return(0);
    1497: }

    1499: /*@
    1500:   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

    1502:   Not collective

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

    1509:   Output Parameter:

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

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

    1516:   Level: beginner

    1518: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
    1519: @*/
    1520: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
    1521: {
    1522:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1523:   PetscInt       pStart, pEnd;
    1524:   PetscInt       dof, off, c;

    1529:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
    1530:   PetscSectionGetDof(mesh->coneSection, p, &dof);
    1532:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    1533:   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);
    1534:   for (c = 0; c < dof; ++c) {
    1535:     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);
    1536:     mesh->cones[off+c] = cone[c];
    1537:   }
    1538:   return(0);
    1539: }

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

    1544:   Not collective

    1546:   Input Parameters:
    1547: + mesh - The DMPlex
    1548: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

    1556:   Level: beginner

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

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

    1564: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
    1565: @*/
    1566: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
    1567: {
    1568:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1569:   PetscInt       off;

    1574: #if defined(PETSC_USE_DEBUG)
    1575:   {
    1576:     PetscInt dof;
    1577:     PetscSectionGetDof(mesh->coneSection, p, &dof);
    1579:   }
    1580: #endif
    1581:   PetscSectionGetOffset(mesh->coneSection, p, &off);

    1583:   *coneOrientation = &mesh->coneOrientations[off];
    1584:   return(0);
    1585: }

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

    1590:   Not collective

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

    1600:   Output Parameter:

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

    1605:   Level: beginner

    1607: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
    1608: @*/
    1609: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
    1610: {
    1611:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1612:   PetscInt       pStart, pEnd;
    1613:   PetscInt       dof, off, c;

    1618:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
    1619:   PetscSectionGetDof(mesh->coneSection, p, &dof);
    1621:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    1622:   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);
    1623:   for (c = 0; c < dof; ++c) {
    1624:     PetscInt cdof, o = coneOrientation[c];

    1626:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
    1627:     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);
    1628:     mesh->coneOrientations[off+c] = o;
    1629:   }
    1630:   return(0);
    1631: }

    1633: /*@
    1634:   DMPlexInsertCone - Insert a point into the in-edges for the point p 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: . conePos - The local index in the cone where the point should be put
    1642: - conePoint - The mesh point to insert

    1644:   Level: beginner

    1646: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
    1647: @*/
    1648: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
    1649: {
    1650:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1651:   PetscInt       pStart, pEnd;
    1652:   PetscInt       dof, off;

    1657:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
    1658:   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);
    1659:   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);
    1660:   PetscSectionGetDof(mesh->coneSection, p, &dof);
    1661:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    1662:   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);
    1663:   mesh->cones[off+conePos] = conePoint;
    1664:   return(0);
    1665: }

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

    1670:   Not collective

    1672:   Input Parameters:
    1673: + mesh - The DMPlex
    1674: . p - The point, which must lie in the chart set with DMPlexSetChart()
    1675: . conePos - The local index in the cone where the point should be put
    1676: - coneOrientation - The point orientation to insert

    1678:   Level: beginner

    1680: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
    1681: @*/
    1682: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
    1683: {
    1684:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1685:   PetscInt       pStart, pEnd;
    1686:   PetscInt       dof, off;

    1691:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
    1692:   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);
    1693:   PetscSectionGetDof(mesh->coneSection, p, &dof);
    1694:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    1695:   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);
    1696:   mesh->coneOrientations[off+conePos] = coneOrientation;
    1697:   return(0);
    1698: }

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

    1703:   Not collective

    1705:   Input Parameters:
    1706: + mesh - The DMPlex
    1707: - p - The point, which must lie in the chart set with DMPlexSetChart()

    1709:   Output Parameter:
    1710: . size - The support size for point p

    1712:   Level: beginner

    1714: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
    1715: @*/
    1716: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
    1717: {
    1718:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    1724:   PetscSectionGetDof(mesh->supportSection, p, size);
    1725:   return(0);
    1726: }

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

    1731:   Not collective

    1733:   Input Parameters:
    1734: + mesh - The DMPlex
    1735: . p - The point, which must lie in the chart set with DMPlexSetChart()
    1736: - size - The support size for point p

    1738:   Output Parameter:

    1740:   Note:
    1741:   This should be called after DMPlexSetChart().

    1743:   Level: beginner

    1745: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
    1746: @*/
    1747: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
    1748: {
    1749:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

    1756:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
    1757:   return(0);
    1758: }

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

    1763:   Not collective

    1765:   Input Parameters:
    1766: + mesh - The DMPlex
    1767: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

    1772:   Level: beginner

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

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

    1780: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
    1781: @*/
    1782: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
    1783: {
    1784:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1785:   PetscInt       off;

    1791:   PetscSectionGetOffset(mesh->supportSection, p, &off);
    1792:   *support = &mesh->supports[off];
    1793:   return(0);
    1794: }

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

    1799:   Not collective

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

    1806:   Output Parameter:

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

    1811:   Level: beginner

    1813: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
    1814: @*/
    1815: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
    1816: {
    1817:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1818:   PetscInt       pStart, pEnd;
    1819:   PetscInt       dof, off, c;

    1824:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
    1825:   PetscSectionGetDof(mesh->supportSection, p, &dof);
    1827:   PetscSectionGetOffset(mesh->supportSection, p, &off);
    1828:   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
    1829:   for (c = 0; c < dof; ++c) {
    1830:     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);
    1831:     mesh->supports[off+c] = support[c];
    1832:   }
    1833:   return(0);
    1834: }

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

    1839:   Not collective

    1841:   Input Parameters:
    1842: + mesh - The DMPlex
    1843: . p - The point, which must lie in the chart set with DMPlexSetChart()
    1844: . supportPos - The local index in the cone where the point should be put
    1845: - supportPoint - The mesh point to insert

    1847:   Level: beginner

    1849: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
    1850: @*/
    1851: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
    1852: {
    1853:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1854:   PetscInt       pStart, pEnd;
    1855:   PetscInt       dof, off;

    1860:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
    1861:   PetscSectionGetDof(mesh->supportSection, p, &dof);
    1862:   PetscSectionGetOffset(mesh->supportSection, p, &off);
    1863:   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);
    1864:   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);
    1865:   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);
    1866:   mesh->supports[off+supportPos] = supportPoint;
    1867:   return(0);
    1868: }

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

    1873:   Not collective

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

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

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

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

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

    1894:   Level: beginner

    1896: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
    1897: @*/
    1898: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
    1899: {
    1900:   DM_Plex        *mesh = (DM_Plex*) dm->data;
    1901:   PetscInt       *closure, *fifo;
    1902:   const PetscInt *tmp = NULL, *tmpO = NULL;
    1903:   PetscInt        tmpSize, t;
    1904:   PetscInt        depth       = 0, maxSize;
    1905:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
    1906:   PetscErrorCode  ierr;

    1910:   DMPlexGetDepth(dm, &depth);
    1911:   /* This is only 1-level */
    1912:   if (useCone) {
    1913:     DMPlexGetConeSize(dm, p, &tmpSize);
    1914:     DMPlexGetCone(dm, p, &tmp);
    1915:     DMPlexGetConeOrientation(dm, p, &tmpO);
    1916:   } else {
    1917:     DMPlexGetSupportSize(dm, p, &tmpSize);
    1918:     DMPlexGetSupport(dm, p, &tmp);
    1919:   }
    1920:   if (depth == 1) {
    1921:     if (*points) {
    1922:       closure = *points;
    1923:     } else {
    1924:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
    1925:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
    1926:     }
    1927:     closure[0] = p; closure[1] = 0;
    1928:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
    1929:       closure[closureSize]   = tmp[t];
    1930:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
    1931:     }
    1932:     if (numPoints) *numPoints = closureSize/2;
    1933:     if (points)    *points    = closure;
    1934:     return(0);
    1935:   }
    1936:   {
    1937:     PetscInt c, coneSeries, s,supportSeries;

    1939:     c = mesh->maxConeSize;
    1940:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
    1941:     s = mesh->maxSupportSize;
    1942:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
    1943:     maxSize = 2*PetscMax(coneSeries,supportSeries);
    1944:   }
    1945:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
    1946:   if (*points) {
    1947:     closure = *points;
    1948:   } else {
    1949:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
    1950:   }
    1951:   closure[0] = p; closure[1] = 0;
    1952:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
    1953:     const PetscInt cp = tmp[t];
    1954:     const PetscInt co = tmpO ? tmpO[t] : 0;

    1956:     closure[closureSize]   = cp;
    1957:     closure[closureSize+1] = co;
    1958:     fifo[fifoSize]         = cp;
    1959:     fifo[fifoSize+1]       = co;
    1960:   }
    1961:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
    1962:   while (fifoSize - fifoStart) {
    1963:     const PetscInt q   = fifo[fifoStart];
    1964:     const PetscInt o   = fifo[fifoStart+1];
    1965:     const PetscInt rev = o >= 0 ? 0 : 1;
    1966:     const PetscInt off = rev ? -(o+1) : o;

    1968:     if (useCone) {
    1969:       DMPlexGetConeSize(dm, q, &tmpSize);
    1970:       DMPlexGetCone(dm, q, &tmp);
    1971:       DMPlexGetConeOrientation(dm, q, &tmpO);
    1972:     } else {
    1973:       DMPlexGetSupportSize(dm, q, &tmpSize);
    1974:       DMPlexGetSupport(dm, q, &tmp);
    1975:       tmpO = NULL;
    1976:     }
    1977:     for (t = 0; t < tmpSize; ++t) {
    1978:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
    1979:       const PetscInt cp = tmp[i];
    1980:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
    1981:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
    1982:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
    1983:       PetscInt       co = tmpO ? tmpO[i] : 0;
    1984:       PetscInt       c;

    1986:       if (rev) {
    1987:         PetscInt childSize, coff;
    1988:         DMPlexGetConeSize(dm, cp, &childSize);
    1989:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
    1990:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
    1991:       }
    1992:       /* Check for duplicate */
    1993:       for (c = 0; c < closureSize; c += 2) {
    1994:         if (closure[c] == cp) break;
    1995:       }
    1996:       if (c == closureSize) {
    1997:         closure[closureSize]   = cp;
    1998:         closure[closureSize+1] = co;
    1999:         fifo[fifoSize]         = cp;
    2000:         fifo[fifoSize+1]       = co;
    2001:         closureSize           += 2;
    2002:         fifoSize              += 2;
    2003:       }
    2004:     }
    2005:     fifoStart += 2;
    2006:   }
    2007:   if (numPoints) *numPoints = closureSize/2;
    2008:   if (points)    *points    = closure;
    2009:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
    2010:   return(0);
    2011: }

    2013: /*@C
    2014:   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

    2016:   Not collective

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

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

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

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

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

    2038:   Level: beginner

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

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

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

    2102:     if (ornt < 0) {
    2103:       PetscInt childSize, coff;
    2104:       DMPlexGetConeSize(dm, cp, &childSize);
    2105:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
    2106:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
    2107:     }
    2108:     closure[closureSize]   = cp;
    2109:     closure[closureSize+1] = co;
    2110:     fifo[fifoSize]         = cp;
    2111:     fifo[fifoSize+1]       = co;
    2112:   }
    2113:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
    2114:   while (fifoSize - fifoStart) {
    2115:     const PetscInt q   = fifo[fifoStart];
    2116:     const PetscInt o   = fifo[fifoStart+1];
    2117:     const PetscInt rev = o >= 0 ? 0 : 1;
    2118:     const PetscInt off = rev ? -(o+1) : o;

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

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

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

    2168:   Not collective

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

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

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

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

    2186:   Level: beginner

    2188: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
    2189: @*/
    2190: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
    2191: {

    2198:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
    2199:   if (numPoints) *numPoints = 0;
    2200:   return(0);
    2201: }

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

    2206:   Not collective

    2208:   Input Parameter:
    2209: . mesh - The DMPlex

    2211:   Output Parameters:
    2212: + maxConeSize - The maximum number of in-edges
    2213: - maxSupportSize - The maximum number of out-edges

    2215:   Level: beginner

    2217: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
    2218: @*/
    2219: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
    2220: {
    2221:   DM_Plex *mesh = (DM_Plex*) dm->data;

    2225:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
    2226:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
    2227:   return(0);
    2228: }

    2230: PetscErrorCode DMSetUp_Plex(DM dm)
    2231: {
    2232:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2233:   PetscInt       size;

    2238:   PetscSectionSetUp(mesh->coneSection);
    2239:   PetscSectionGetStorageSize(mesh->coneSection, &size);
    2240:   PetscMalloc1(size, &mesh->cones);
    2241:   PetscCalloc1(size, &mesh->coneOrientations);
    2242:   if (mesh->maxSupportSize) {
    2243:     PetscSectionSetUp(mesh->supportSection);
    2244:     PetscSectionGetStorageSize(mesh->supportSection, &size);
    2245:     PetscMalloc1(size, &mesh->supports);
    2246:   }
    2247:   return(0);
    2248: }

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

    2255:   if (subdm) {DMClone(dm, subdm);}
    2256:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
    2257:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
    2258:   if (dm->useNatural && dm->sfMigration) {
    2259:     PetscSF        sfMigrationInv,sfNatural;
    2260:     PetscSection   section, sectionSeq;

    2262:     (*subdm)->sfMigration = dm->sfMigration;
    2263:     PetscObjectReference((PetscObject) dm->sfMigration);
    2264:     DMGetSection((*subdm), &section);
    2265:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
    2266:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
    2267:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

    2269:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
    2270:     (*subdm)->sfNatural = sfNatural;
    2271:     PetscSectionDestroy(&sectionSeq);
    2272:     PetscSFDestroy(&sfMigrationInv);
    2273:   }
    2274:   return(0);
    2275: }

    2277: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
    2278: {
    2280:   PetscInt       i = 0;

    2283:   if (superdm) {DMClone(dms[0], superdm);}
    2284:   DMCreateSuperDM_Section_Private(dms, len, is, superdm);
    2285:   (*superdm)->useNatural = PETSC_FALSE;
    2286:   for (i = 0; i < len; i++){
    2287:     if (dms[i]->useNatural && dms[i]->sfMigration) {
    2288:       PetscSF        sfMigrationInv,sfNatural;
    2289:       PetscSection   section, sectionSeq;

    2291:       (*superdm)->sfMigration = dms[i]->sfMigration;
    2292:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
    2293:       (*superdm)->useNatural = PETSC_TRUE;
    2294:       DMGetSection((*superdm), &section);
    2295:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
    2296:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
    2297:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

    2299:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
    2300:       (*superdm)->sfNatural = sfNatural;
    2301:       PetscSectionDestroy(&sectionSeq);
    2302:       PetscSFDestroy(&sfMigrationInv);
    2303:       break;
    2304:     }
    2305:   }
    2306:   return(0);
    2307: }

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

    2312:   Not collective

    2314:   Input Parameter:
    2315: . mesh - The DMPlex

    2317:   Output Parameter:

    2319:   Note:
    2320:   This should be called after all calls to DMPlexSetCone()

    2322:   Level: beginner

    2324: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
    2325: @*/
    2326: PetscErrorCode DMPlexSymmetrize(DM dm)
    2327: {
    2328:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2329:   PetscInt      *offsets;
    2330:   PetscInt       supportSize;
    2331:   PetscInt       pStart, pEnd, p;

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

    2342:     PetscSectionGetDof(mesh->coneSection, p, &dof);
    2343:     PetscSectionGetOffset(mesh->coneSection, p, &off);
    2344:     for (c = off; c < off+dof; ++c) {
    2345:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
    2346:     }
    2347:   }
    2348:   for (p = pStart; p < pEnd; ++p) {
    2349:     PetscInt dof;

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

    2353:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
    2354:   }
    2355:   PetscSectionSetUp(mesh->supportSection);
    2356:   /* Calculate supports */
    2357:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
    2358:   PetscMalloc1(supportSize, &mesh->supports);
    2359:   PetscCalloc1(pEnd - pStart, &offsets);
    2360:   for (p = pStart; p < pEnd; ++p) {
    2361:     PetscInt dof, off, c;

    2363:     PetscSectionGetDof(mesh->coneSection, p, &dof);
    2364:     PetscSectionGetOffset(mesh->coneSection, p, &off);
    2365:     for (c = off; c < off+dof; ++c) {
    2366:       const PetscInt q = mesh->cones[c];
    2367:       PetscInt       offS;

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

    2371:       mesh->supports[offS+offsets[q]] = p;
    2372:       ++offsets[q];
    2373:     }
    2374:   }
    2375:   PetscFree(offsets);
    2376:   return(0);
    2377: }

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

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

    2387:   Collective on dm

    2389:   Input Parameter:
    2390: . mesh - The DMPlex

    2392:   Output Parameter:

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

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

    2402:   Level: beginner

    2404: .seealso: DMPlexCreate(), DMPlexSymmetrize()
    2405: @*/
    2406: PetscErrorCode DMPlexStratify(DM dm)
    2407: {
    2408:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2409:   DMLabel        label;
    2410:   PetscInt       pStart, pEnd, p;
    2411:   PetscInt       numRoots = 0, numLeaves = 0;
    2412:   PetscInt       cMax, fMax, eMax, vMax;

    2417:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
    2418:   /* Calculate depth */
    2419:   DMPlexGetChart(dm, &pStart, &pEnd);
    2420:   DMCreateLabel(dm, "depth");
    2421:   DMPlexGetDepthLabel(dm, &label);
    2422:   /* Initialize roots and count leaves */
    2423:   for (p = pStart; p < pEnd; ++p) {
    2424:     PetscInt coneSize, supportSize;

    2426:     DMPlexGetConeSize(dm, p, &coneSize);
    2427:     DMPlexGetSupportSize(dm, p, &supportSize);
    2428:     if (!coneSize && supportSize) {
    2429:       ++numRoots;
    2430:       DMLabelSetValue(label, p, 0);
    2431:     } else if (!supportSize && coneSize) {
    2432:       ++numLeaves;
    2433:     } else if (!supportSize && !coneSize) {
    2434:       /* Isolated points */
    2435:       DMLabelSetValue(label, p, 0);
    2436:     }
    2437:   }
    2438:   if (numRoots + numLeaves == (pEnd - pStart)) {
    2439:     for (p = pStart; p < pEnd; ++p) {
    2440:       PetscInt coneSize, supportSize;

    2442:       DMPlexGetConeSize(dm, p, &coneSize);
    2443:       DMPlexGetSupportSize(dm, p, &supportSize);
    2444:       if (!supportSize && coneSize) {
    2445:         DMLabelSetValue(label, p, 1);
    2446:       }
    2447:     }
    2448:   } else {
    2449:     IS       pointIS;
    2450:     PetscInt numPoints = 0, level = 0;

    2452:     DMLabelGetStratumIS(label, level, &pointIS);
    2453:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
    2454:     while (numPoints) {
    2455:       const PetscInt *points;
    2456:       const PetscInt  newLevel = level+1;

    2458:       ISGetIndices(pointIS, &points);
    2459:       for (p = 0; p < numPoints; ++p) {
    2460:         const PetscInt  point = points[p];
    2461:         const PetscInt *support;
    2462:         PetscInt        supportSize, s;

    2464:         DMPlexGetSupportSize(dm, point, &supportSize);
    2465:         DMPlexGetSupport(dm, point, &support);
    2466:         for (s = 0; s < supportSize; ++s) {
    2467:           DMLabelSetValue(label, support[s], newLevel);
    2468:         }
    2469:       }
    2470:       ISRestoreIndices(pointIS, &points);
    2471:       ++level;
    2472:       ISDestroy(&pointIS);
    2473:       DMLabelGetStratumIS(label, level, &pointIS);
    2474:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
    2475:       else         {numPoints = 0;}
    2476:     }
    2477:     ISDestroy(&pointIS);
    2478:   }
    2479:   { /* just in case there is an empty process */
    2480:     PetscInt numValues, maxValues = 0, v;

    2482:     DMLabelGetNumValues(label,&numValues);
    2483:     for (v = 0; v < numValues; v++) {
    2484:       IS pointIS;

    2486:       DMLabelGetStratumIS(label, v, &pointIS);
    2487:       if (pointIS) {
    2488:         PetscInt  min, max, numPoints;
    2489:         PetscInt  start;
    2490:         PetscBool contig;

    2492:         ISGetLocalSize(pointIS, &numPoints);
    2493:         ISGetMinMax(pointIS, &min, &max);
    2494:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
    2495:         if (start == 0 && contig) {
    2496:           ISDestroy(&pointIS);
    2497:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
    2498:           DMLabelSetStratumIS(label, v, pointIS);
    2499:         }
    2500:       }
    2501:       ISDestroy(&pointIS);
    2502:     }
    2503:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
    2504:     for (v = numValues; v < maxValues; v++) {
    2505:       DMLabelAddStratum(label,v);
    2506:     }
    2507:   }
    2508:   DMLabelGetState(label, &mesh->depthState);

    2510:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    2511:   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
    2512:     DMLabel  dimLabel;
    2513:     PetscInt dim;

    2515:     DMGetDimension(dm, &dim);
    2516:     DMGetLabel(dm, "dim", &dimLabel);
    2517:     if (!dimLabel) {
    2518:       DMCreateLabel(dm, "dim");
    2519:       DMGetLabel(dm, "dim", &dimLabel);
    2520:     }
    2521:     if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
    2522:     if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
    2523:     if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
    2524:     if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
    2525:   }
    2526:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
    2527:   return(0);
    2528: }

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

    2533:   Not Collective

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

    2540:   Output Parameters:
    2541: + numCoveredPoints - The number of points in the join
    2542: - coveredPoints - The points in the join

    2544:   Level: intermediate

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

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

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

    2554: .keywords: mesh
    2555: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
    2556: @*/
    2557: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    2558: {
    2559:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2560:   PetscInt      *join[2];
    2561:   PetscInt       joinSize, i = 0;
    2562:   PetscInt       dof, off, p, c, m;

    2570:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
    2571:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
    2572:   /* Copy in support of first point */
    2573:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
    2574:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
    2575:   for (joinSize = 0; joinSize < dof; ++joinSize) {
    2576:     join[i][joinSize] = mesh->supports[off+joinSize];
    2577:   }
    2578:   /* Check each successive support */
    2579:   for (p = 1; p < numPoints; ++p) {
    2580:     PetscInt newJoinSize = 0;

    2582:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
    2583:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
    2584:     for (c = 0; c < dof; ++c) {
    2585:       const PetscInt point = mesh->supports[off+c];

    2587:       for (m = 0; m < joinSize; ++m) {
    2588:         if (point == join[i][m]) {
    2589:           join[1-i][newJoinSize++] = point;
    2590:           break;
    2591:         }
    2592:       }
    2593:     }
    2594:     joinSize = newJoinSize;
    2595:     i        = 1-i;
    2596:   }
    2597:   *numCoveredPoints = joinSize;
    2598:   *coveredPoints    = join[i];
    2599:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
    2600:   return(0);
    2601: }

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

    2606:   Not Collective

    2608:   Input Parameters:
    2609: + dm - The DMPlex object
    2610: . numPoints - The number of input points for the join
    2611: - points - The input points

    2613:   Output Parameters:
    2614: + numCoveredPoints - The number of points in the join
    2615: - coveredPoints - The points in the join

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

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

    2623:   Level: intermediate

    2625: .keywords: mesh
    2626: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
    2627: @*/
    2628: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    2629: {

    2637:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
    2638:   if (numCoveredPoints) *numCoveredPoints = 0;
    2639:   return(0);
    2640: }

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

    2645:   Not Collective

    2647:   Input Parameters:
    2648: + dm - The DMPlex object
    2649: . numPoints - The number of input points for the join
    2650: - points - The input points

    2652:   Output Parameters:
    2653: + numCoveredPoints - The number of points in the join
    2654: - coveredPoints - The points in the join

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

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

    2662:   Level: intermediate

    2664: .keywords: mesh
    2665: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
    2666: @*/
    2667: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    2668: {
    2669:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2670:   PetscInt      *offsets, **closures;
    2671:   PetscInt      *join[2];
    2672:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
    2673:   PetscInt       p, d, c, m, ms;

    2682:   DMPlexGetDepth(dm, &depth);
    2683:   PetscCalloc1(numPoints, &closures);
    2684:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
    2685:   ms      = mesh->maxSupportSize;
    2686:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
    2687:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
    2688:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

    2690:   for (p = 0; p < numPoints; ++p) {
    2691:     PetscInt closureSize;

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

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

    2699:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
    2700:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
    2701:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
    2702:           offsets[p*(depth+2)+d+1] = i;
    2703:           break;
    2704:         }
    2705:       }
    2706:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
    2707:     }
    2708:     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);
    2709:   }
    2710:   for (d = 0; d < depth+1; ++d) {
    2711:     PetscInt dof;

    2713:     /* Copy in support of first point */
    2714:     dof = offsets[d+1] - offsets[d];
    2715:     for (joinSize = 0; joinSize < dof; ++joinSize) {
    2716:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
    2717:     }
    2718:     /* Check each successive cone */
    2719:     for (p = 1; p < numPoints && joinSize; ++p) {
    2720:       PetscInt newJoinSize = 0;

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

    2726:         for (m = 0; m < joinSize; ++m) {
    2727:           if (point == join[i][m]) {
    2728:             join[1-i][newJoinSize++] = point;
    2729:             break;
    2730:           }
    2731:         }
    2732:       }
    2733:       joinSize = newJoinSize;
    2734:       i        = 1-i;
    2735:     }
    2736:     if (joinSize) break;
    2737:   }
    2738:   *numCoveredPoints = joinSize;
    2739:   *coveredPoints    = join[i];
    2740:   for (p = 0; p < numPoints; ++p) {
    2741:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
    2742:   }
    2743:   PetscFree(closures);
    2744:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
    2745:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
    2746:   return(0);
    2747: }

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

    2752:   Not Collective

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

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

    2763:   Level: intermediate

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

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

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

    2773: .keywords: mesh
    2774: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
    2775: @*/
    2776: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
    2777: {
    2778:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2779:   PetscInt      *meet[2];
    2780:   PetscInt       meetSize, i = 0;
    2781:   PetscInt       dof, off, p, c, m;

    2789:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
    2790:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
    2791:   /* Copy in cone of first point */
    2792:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
    2793:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
    2794:   for (meetSize = 0; meetSize < dof; ++meetSize) {
    2795:     meet[i][meetSize] = mesh->cones[off+meetSize];
    2796:   }
    2797:   /* Check each successive cone */
    2798:   for (p = 1; p < numPoints; ++p) {
    2799:     PetscInt newMeetSize = 0;

    2801:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
    2802:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
    2803:     for (c = 0; c < dof; ++c) {
    2804:       const PetscInt point = mesh->cones[off+c];

    2806:       for (m = 0; m < meetSize; ++m) {
    2807:         if (point == meet[i][m]) {
    2808:           meet[1-i][newMeetSize++] = point;
    2809:           break;
    2810:         }
    2811:       }
    2812:     }
    2813:     meetSize = newMeetSize;
    2814:     i        = 1-i;
    2815:   }
    2816:   *numCoveringPoints = meetSize;
    2817:   *coveringPoints    = meet[i];
    2818:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
    2819:   return(0);
    2820: }

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

    2825:   Not Collective

    2827:   Input Parameters:
    2828: + dm - The DMPlex object
    2829: . numPoints - The number of input points for the meet
    2830: - points - The input points

    2832:   Output Parameters:
    2833: + numCoveredPoints - The number of points in the meet
    2834: - coveredPoints - The points in the meet

    2836:   Level: intermediate

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

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

    2844: .keywords: mesh
    2845: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
    2846: @*/
    2847: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    2848: {

    2856:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
    2857:   if (numCoveredPoints) *numCoveredPoints = 0;
    2858:   return(0);
    2859: }

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

    2864:   Not Collective

    2866:   Input Parameters:
    2867: + dm - The DMPlex object
    2868: . numPoints - The number of input points for the meet
    2869: - points - The input points

    2871:   Output Parameters:
    2872: + numCoveredPoints - The number of points in the meet
    2873: - coveredPoints - The points in the meet

    2875:   Level: intermediate

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

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

    2883: .keywords: mesh
    2884: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
    2885: @*/
    2886: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    2887: {
    2888:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2889:   PetscInt      *offsets, **closures;
    2890:   PetscInt      *meet[2];
    2891:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
    2892:   PetscInt       p, h, c, m, mc;

    2901:   DMPlexGetDepth(dm, &height);
    2902:   PetscMalloc1(numPoints, &closures);
    2903:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
    2904:   mc      = mesh->maxConeSize;
    2905:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
    2906:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
    2907:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

    2909:   for (p = 0; p < numPoints; ++p) {
    2910:     PetscInt closureSize;

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

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

    2918:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
    2919:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
    2920:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
    2921:           offsets[p*(height+2)+h+1] = i;
    2922:           break;
    2923:         }
    2924:       }
    2925:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
    2926:     }
    2927:     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);
    2928:   }
    2929:   for (h = 0; h < height+1; ++h) {
    2930:     PetscInt dof;

    2932:     /* Copy in cone of first point */
    2933:     dof = offsets[h+1] - offsets[h];
    2934:     for (meetSize = 0; meetSize < dof; ++meetSize) {
    2935:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
    2936:     }
    2937:     /* Check each successive cone */
    2938:     for (p = 1; p < numPoints && meetSize; ++p) {
    2939:       PetscInt newMeetSize = 0;

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

    2945:         for (m = 0; m < meetSize; ++m) {
    2946:           if (point == meet[i][m]) {
    2947:             meet[1-i][newMeetSize++] = point;
    2948:             break;
    2949:           }
    2950:         }
    2951:       }
    2952:       meetSize = newMeetSize;
    2953:       i        = 1-i;
    2954:     }
    2955:     if (meetSize) break;
    2956:   }
    2957:   *numCoveredPoints = meetSize;
    2958:   *coveredPoints    = meet[i];
    2959:   for (p = 0; p < numPoints; ++p) {
    2960:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
    2961:   }
    2962:   PetscFree(closures);
    2963:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
    2964:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
    2965:   return(0);
    2966: }

    2968: /*@C
    2969:   DMPlexEqual - Determine if two DMs have the same topology

    2971:   Not Collective

    2973:   Input Parameters:
    2974: + dmA - A DMPlex object
    2975: - dmB - A DMPlex object

    2977:   Output Parameters:
    2978: . equal - PETSC_TRUE if the topologies are identical

    2980:   Level: intermediate

    2982:   Notes:
    2983:   We are not solving graph isomorphism, so we do not permutation.

    2985: .keywords: mesh
    2986: .seealso: DMPlexGetCone()
    2987: @*/
    2988: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
    2989: {
    2990:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;

    2998:   *equal = PETSC_FALSE;
    2999:   DMPlexGetDepth(dmA, &depth);
    3000:   DMPlexGetDepth(dmB, &depthB);
    3001:   if (depth != depthB) return(0);
    3002:   DMPlexGetChart(dmA, &pStart,  &pEnd);
    3003:   DMPlexGetChart(dmB, &pStartB, &pEndB);
    3004:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
    3005:   for (p = pStart; p < pEnd; ++p) {
    3006:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
    3007:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

    3009:     DMPlexGetConeSize(dmA, p, &coneSize);
    3010:     DMPlexGetCone(dmA, p, &cone);
    3011:     DMPlexGetConeOrientation(dmA, p, &ornt);
    3012:     DMPlexGetConeSize(dmB, p, &coneSizeB);
    3013:     DMPlexGetCone(dmB, p, &coneB);
    3014:     DMPlexGetConeOrientation(dmB, p, &orntB);
    3015:     if (coneSize != coneSizeB) return(0);
    3016:     for (c = 0; c < coneSize; ++c) {
    3017:       if (cone[c] != coneB[c]) return(0);
    3018:       if (ornt[c] != orntB[c]) return(0);
    3019:     }
    3020:     DMPlexGetSupportSize(dmA, p, &supportSize);
    3021:     DMPlexGetSupport(dmA, p, &support);
    3022:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
    3023:     DMPlexGetSupport(dmB, p, &supportB);
    3024:     if (supportSize != supportSizeB) return(0);
    3025:     for (s = 0; s < supportSize; ++s) {
    3026:       if (support[s] != supportB[s]) return(0);
    3027:     }
    3028:   }
    3029:   *equal = PETSC_TRUE;
    3030:   return(0);
    3031: }

    3033: /*@C
    3034:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

    3036:   Not Collective

    3038:   Input Parameters:
    3039: + dm         - The DMPlex
    3040: . cellDim    - The cell dimension
    3041: - numCorners - The number of vertices on a cell

    3043:   Output Parameters:
    3044: . numFaceVertices - The number of vertices on a face

    3046:   Level: developer

    3048:   Notes:
    3049:   Of course this can only work for a restricted set of symmetric shapes

    3051: .seealso: DMPlexGetCone()
    3052: @*/
    3053: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
    3054: {
    3055:   MPI_Comm       comm;

    3059:   PetscObjectGetComm((PetscObject)dm,&comm);
    3061:   switch (cellDim) {
    3062:   case 0:
    3063:     *numFaceVertices = 0;
    3064:     break;
    3065:   case 1:
    3066:     *numFaceVertices = 1;
    3067:     break;
    3068:   case 2:
    3069:     switch (numCorners) {
    3070:     case 3: /* triangle */
    3071:       *numFaceVertices = 2; /* Edge has 2 vertices */
    3072:       break;
    3073:     case 4: /* quadrilateral */
    3074:       *numFaceVertices = 2; /* Edge has 2 vertices */
    3075:       break;
    3076:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
    3077:       *numFaceVertices = 3; /* Edge has 3 vertices */
    3078:       break;
    3079:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
    3080:       *numFaceVertices = 3; /* Edge has 3 vertices */
    3081:       break;
    3082:     default:
    3083:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
    3084:     }
    3085:     break;
    3086:   case 3:
    3087:     switch (numCorners) {
    3088:     case 4: /* tetradehdron */
    3089:       *numFaceVertices = 3; /* Face has 3 vertices */
    3090:       break;
    3091:     case 6: /* tet cohesive cells */
    3092:       *numFaceVertices = 4; /* Face has 4 vertices */
    3093:       break;
    3094:     case 8: /* hexahedron */
    3095:       *numFaceVertices = 4; /* Face has 4 vertices */
    3096:       break;
    3097:     case 9: /* tet cohesive Lagrange cells */
    3098:       *numFaceVertices = 6; /* Face has 6 vertices */
    3099:       break;
    3100:     case 10: /* quadratic tetrahedron */
    3101:       *numFaceVertices = 6; /* Face has 6 vertices */
    3102:       break;
    3103:     case 12: /* hex cohesive Lagrange cells */
    3104:       *numFaceVertices = 6; /* Face has 6 vertices */
    3105:       break;
    3106:     case 18: /* quadratic tet cohesive Lagrange cells */
    3107:       *numFaceVertices = 6; /* Face has 6 vertices */
    3108:       break;
    3109:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
    3110:       *numFaceVertices = 9; /* Face has 9 vertices */
    3111:       break;
    3112:     default:
    3113:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
    3114:     }
    3115:     break;
    3116:   default:
    3117:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
    3118:   }
    3119:   return(0);
    3120: }

    3122: /*@
    3123:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

    3125:   Not Collective

    3127:   Input Parameter:
    3128: . dm    - The DMPlex object

    3130:   Output Parameter:
    3131: . depthLabel - The DMLabel recording point depth

    3133:   Level: developer

    3135: .keywords: mesh, points
    3136: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
    3137: @*/
    3138: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
    3139: {

    3145:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
    3146:   *depthLabel = dm->depthLabel;
    3147:   return(0);
    3148: }

    3150: /*@
    3151:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

    3153:   Not Collective

    3155:   Input Parameter:
    3156: . dm    - The DMPlex object

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

    3161:   Level: developer

    3163: .keywords: mesh, points
    3164: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
    3165: @*/
    3166: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
    3167: {
    3168:   DMLabel        label;
    3169:   PetscInt       d = 0;

    3175:   DMPlexGetDepthLabel(dm, &label);
    3176:   if (label) {DMLabelGetNumValues(label, &d);}
    3177:   *depth = d-1;
    3178:   return(0);
    3179: }

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

    3184:   Not Collective

    3186:   Input Parameters:
    3187: + dm           - The DMPlex object
    3188: - stratumValue - The requested depth

    3190:   Output Parameters:
    3191: + start - The first point at this depth
    3192: - end   - One beyond the last point at this depth

    3194:   Level: developer

    3196: .keywords: mesh, points
    3197: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
    3198: @*/
    3199: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
    3200: {
    3201:   DMLabel        label;
    3202:   PetscInt       pStart, pEnd;

    3209:   DMPlexGetChart(dm, &pStart, &pEnd);
    3210:   if (pStart == pEnd) return(0);
    3211:   if (stratumValue < 0) {
    3212:     if (start) *start = pStart;
    3213:     if (end)   *end   = pEnd;
    3214:     return(0);
    3215:   }
    3216:   DMPlexGetDepthLabel(dm, &label);
    3217:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
    3218:   DMLabelGetStratumBounds(label, stratumValue, start, end);
    3219:   return(0);
    3220: }

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

    3225:   Not Collective

    3227:   Input Parameters:
    3228: + dm           - The DMPlex object
    3229: - stratumValue - The requested height

    3231:   Output Parameters:
    3232: + start - The first point at this height
    3233: - end   - One beyond the last point at this height

    3235:   Level: developer

    3237: .keywords: mesh, points
    3238: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
    3239: @*/
    3240: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
    3241: {
    3242:   DMLabel        label;
    3243:   PetscInt       depth, pStart, pEnd;

    3250:   DMPlexGetChart(dm, &pStart, &pEnd);
    3251:   if (pStart == pEnd) return(0);
    3252:   if (stratumValue < 0) {
    3253:     if (start) *start = pStart;
    3254:     if (end)   *end   = pEnd;
    3255:     return(0);
    3256:   }
    3257:   DMPlexGetDepthLabel(dm, &label);
    3258:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
    3259:   DMLabelGetNumValues(label, &depth);
    3260:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
    3261:   return(0);
    3262: }

    3264: /* Set the number of dof on each point and separate by fields */
    3265: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
    3266: {
    3267:   PetscInt      *pMax;
    3268:   PetscInt       depth, cellHeight, pStart = 0, pEnd = 0;
    3269:   PetscInt       Nf, p, d, dep, f;
    3270:   PetscBool     *isFE;

    3274:   PetscMalloc1(numFields, &isFE);
    3275:   DMGetNumFields(dm, &Nf);
    3276:   for (f = 0; f < numFields; ++f) {
    3277:     PetscObject  obj;
    3278:     PetscClassId id;

    3280:     isFE[f] = PETSC_FALSE;
    3281:     if (f >= Nf) continue;
    3282:     DMGetField(dm, f, &obj);
    3283:     PetscObjectGetClassId(obj, &id);
    3284:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
    3285:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
    3286:   }
    3287:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
    3288:   if (numFields > 0) {
    3289:     PetscSectionSetNumFields(*section, numFields);
    3290:     if (numComp) {
    3291:       for (f = 0; f < numFields; ++f) {
    3292:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
    3293:         if (isFE[f]) {
    3294:           PetscFE           fe;
    3295:           PetscDualSpace    dspace;
    3296:           const PetscInt    ***perms;
    3297:           const PetscScalar ***flips;
    3298:           const PetscInt    *numDof;

    3300:           DMGetField(dm,f,(PetscObject *) &fe);
    3301:           PetscFEGetDualSpace(fe,&dspace);
    3302:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
    3303:           PetscDualSpaceGetNumDof(dspace,&numDof);
    3304:           if (perms || flips) {
    3305:             DM               K;
    3306:             DMLabel          depthLabel;
    3307:             PetscInt         depth, h;
    3308:             PetscSectionSym  sym;

    3310:             PetscDualSpaceGetDM(dspace,&K);
    3311:             DMPlexGetDepthLabel(dm,&depthLabel);
    3312:             DMPlexGetDepth(dm,&depth);
    3313:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
    3314:             for (h = 0; h <= depth; h++) {
    3315:               PetscDualSpace    hspace;
    3316:               PetscInt          kStart, kEnd;
    3317:               PetscInt          kConeSize;
    3318:               const PetscInt    **perms0 = NULL;
    3319:               const PetscScalar **flips0 = NULL;

    3321:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
    3322:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
    3323:               if (!hspace) continue;
    3324:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
    3325:               if (perms) perms0 = perms[0];
    3326:               if (flips) flips0 = flips[0];
    3327:               if (!(perms0 || flips0)) continue;
    3328:               DMPlexGetConeSize(K,kStart,&kConeSize);
    3329:               PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
    3330:             }
    3331:             PetscSectionSetFieldSym(*section,f,sym);
    3332:             PetscSectionSymDestroy(&sym);
    3333:           }
    3334:         }
    3335:       }
    3336:     }
    3337:   }
    3338:   DMPlexGetChart(dm, &pStart, &pEnd);
    3339:   PetscSectionSetChart(*section, pStart, pEnd);
    3340:   DMPlexGetDepth(dm, &depth);
    3341:   PetscMalloc1(depth+1,&pMax);
    3342:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
    3343:   DMPlexGetVTKCellHeight(dm, &cellHeight);
    3344:   for (dep = 0; dep <= depth - cellHeight; ++dep) {
    3345:     d    = dim == depth ? dep : (!dep ? 0 : dim);
    3346:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
    3347:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
    3348:     for (p = pStart; p < pEnd; ++p) {
    3349:       PetscInt tot = 0;

    3351:       for (f = 0; f < numFields; ++f) {
    3352:         if (isFE[f] && p >= pMax[dep]) continue;
    3353:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
    3354:         tot += numDof[f*(dim+1)+d];
    3355:       }
    3356:       PetscSectionSetDof(*section, p, tot);
    3357:     }
    3358:   }
    3359:   PetscFree(pMax);
    3360:   PetscFree(isFE);
    3361:   return(0);
    3362: }

    3364: /* Set the number of dof on each point and separate by fields
    3365:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
    3366: */
    3367: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
    3368: {
    3369:   PetscInt       numFields;
    3370:   PetscInt       bc;
    3371:   PetscSection   aSec;

    3375:   PetscSectionGetNumFields(section, &numFields);
    3376:   for (bc = 0; bc < numBC; ++bc) {
    3377:     PetscInt        field = 0;
    3378:     const PetscInt *comp;
    3379:     const PetscInt *idx;
    3380:     PetscInt        Nc = -1, n, i;

    3382:     if (numFields) field = bcField[bc];
    3383:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
    3384:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
    3385:     ISGetLocalSize(bcPoints[bc], &n);
    3386:     ISGetIndices(bcPoints[bc], &idx);
    3387:     for (i = 0; i < n; ++i) {
    3388:       const PetscInt p = idx[i];
    3389:       PetscInt       numConst;

    3391:       if (numFields) {
    3392:         PetscSectionGetFieldDof(section, p, field, &numConst);
    3393:       } else {
    3394:         PetscSectionGetDof(section, p, &numConst);
    3395:       }
    3396:       /* If Nc < 0, constrain every dof on the point */
    3397:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
    3398:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
    3399:       PetscSectionAddConstraintDof(section, p, numConst);
    3400:     }
    3401:     ISRestoreIndices(bcPoints[bc], &idx);
    3402:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
    3403:   }
    3404:   DMPlexGetAnchors(dm, &aSec, NULL);
    3405:   if (aSec) {
    3406:     PetscInt aStart, aEnd, a;

    3408:     PetscSectionGetChart(aSec, &aStart, &aEnd);
    3409:     for (a = aStart; a < aEnd; a++) {
    3410:       PetscInt dof, f;

    3412:       PetscSectionGetDof(aSec, a, &dof);
    3413:       if (dof) {
    3414:         /* if there are point-to-point constraints, then all dofs are constrained */
    3415:         PetscSectionGetDof(section, a, &dof);
    3416:         PetscSectionSetConstraintDof(section, a, dof);
    3417:         for (f = 0; f < numFields; f++) {
    3418:           PetscSectionGetFieldDof(section, a, f, &dof);
    3419:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
    3420:         }
    3421:       }
    3422:     }
    3423:   }
    3424:   return(0);
    3425: }

    3427: /* Set the constrained field indices on each point
    3428:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
    3429: */
    3430: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
    3431: {
    3432:   PetscSection   aSec;
    3433:   PetscInt      *indices;
    3434:   PetscInt       numFields, cdof, maxDof = 0, pStart, pEnd, p, bc, f, d;

    3438:   PetscSectionGetNumFields(section, &numFields);
    3439:   if (!numFields) return(0);
    3440:   /* Initialize all field indices to -1 */
    3441:   PetscSectionGetChart(section, &pStart, &pEnd);
    3442:   for (p = pStart; p < pEnd; ++p) {PetscSectionGetConstraintDof(section, p, &cdof); maxDof = PetscMax(maxDof, cdof);}
    3443:   PetscMalloc1(maxDof, &indices);
    3444:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
    3445:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
    3446:   /* Handle BC constraints */
    3447:   for (bc = 0; bc < numBC; ++bc) {
    3448:     const PetscInt  field = bcField[bc];
    3449:     const PetscInt *comp, *idx;
    3450:     PetscInt        Nc = -1, n, i;

    3452:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
    3453:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
    3454:     ISGetLocalSize(bcPoints[bc], &n);
    3455:     ISGetIndices(bcPoints[bc], &idx);
    3456:     for (i = 0; i < n; ++i) {
    3457:       const PetscInt  p = idx[i];
    3458:       const PetscInt *find;
    3459:       PetscInt        fdof, fcdof, c;

    3461:       PetscSectionGetFieldDof(section, p, field, &fdof);
    3462:       if (!fdof) continue;
    3463:       if (Nc < 0) {
    3464:         for (d = 0; d < fdof; ++d) indices[d] = d;
    3465:         fcdof = fdof;
    3466:       } else {
    3467:         PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
    3468:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
    3469:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
    3470:         for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
    3471:         PetscSortRemoveDupsInt(&d, indices);
    3472:         for (c = d; c < fcdof; ++c) indices[c] = -1;
    3473:         fcdof = d;
    3474:       }
    3475:       PetscSectionSetFieldConstraintDof(section, p, field, fcdof);
    3476:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
    3477:     }
    3478:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
    3479:     ISRestoreIndices(bcPoints[bc], &idx);
    3480:   }
    3481:   /* Handle anchors */
    3482:   DMPlexGetAnchors(dm, &aSec, NULL);
    3483:   if (aSec) {
    3484:     PetscInt aStart, aEnd, a;

    3486:     for (d = 0; d < maxDof; ++d) indices[d] = d;
    3487:     PetscSectionGetChart(aSec, &aStart, &aEnd);
    3488:     for (a = aStart; a < aEnd; a++) {
    3489:       PetscInt dof, f;

    3491:       PetscSectionGetDof(aSec, a, &dof);
    3492:       if (dof) {
    3493:         /* if there are point-to-point constraints, then all dofs are constrained */
    3494:         for (f = 0; f < numFields; f++) {
    3495:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
    3496:         }
    3497:       }
    3498:     }
    3499:   }
    3500:   PetscFree(indices);
    3501:   return(0);
    3502: }

    3504: /* Set the constrained indices on each point */
    3505: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
    3506: {
    3507:   PetscInt      *indices;
    3508:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

    3512:   PetscSectionGetNumFields(section, &numFields);
    3513:   PetscSectionGetMaxDof(section, &maxDof);
    3514:   PetscSectionGetChart(section, &pStart, &pEnd);
    3515:   PetscMalloc1(maxDof, &indices);
    3516:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
    3517:   for (p = pStart; p < pEnd; ++p) {
    3518:     PetscInt cdof, d;

    3520:     PetscSectionGetConstraintDof(section, p, &cdof);
    3521:     if (cdof) {
    3522:       if (numFields) {
    3523:         PetscInt numConst = 0, foff = 0;

    3525:         for (f = 0; f < numFields; ++f) {
    3526:           const PetscInt *find;
    3527:           PetscInt        fcdof, fdof;

    3529:           PetscSectionGetFieldDof(section, p, f, &fdof);
    3530:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
    3531:           /* Change constraint numbering from field component to local dof number */
    3532:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
    3533:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
    3534:           numConst += fcdof;
    3535:           foff     += fdof;
    3536:         }
    3537:         if (cdof != numConst) {PetscSectionSetConstraintDof(section, p, numConst);}
    3538:       } else {
    3539:         for (d = 0; d < cdof; ++d) indices[d] = d;
    3540:       }
    3541:       PetscSectionSetConstraintIndices(section, p, indices);
    3542:     }
    3543:   }
    3544:   PetscFree(indices);
    3545:   return(0);
    3546: }

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

    3551:   Not Collective

    3553:   Input Parameters:
    3554: + dm        - The DMPlex object
    3555: . dim       - The spatial dimension of the problem
    3556: . numFields - The number of fields in the problem
    3557: . numComp   - An array of size numFields that holds the number of components for each field
    3558: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
    3559: . numBC     - The number of boundary conditions
    3560: . bcField   - An array of size numBC giving the field number for each boundry condition
    3561: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
    3562: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
    3563: - perm      - Optional permutation of the chart, or NULL

    3565:   Output Parameter:
    3566: . section - The PetscSection object

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

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

    3574:   Level: developer

    3576:   Fortran Notes:
    3577:   A Fortran 90 version is available as DMPlexCreateSectionF90()

    3579: .keywords: mesh, elements
    3580: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
    3581: @*/
    3582: 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)
    3583: {
    3584:   PetscSection   aSec;

    3588:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
    3589:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
    3590:   if (perm) {PetscSectionSetPermutation(*section, perm);}
    3591:   PetscSectionSetUp(*section);
    3592:   DMPlexGetAnchors(dm,&aSec,NULL);
    3593:   if (numBC || aSec) {
    3594:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
    3595:     DMPlexCreateSectionBCIndices(dm, *section);
    3596:   }
    3597:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
    3598:   return(0);
    3599: }

    3601: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
    3602: {
    3603:   PetscSection   section, s;
    3604:   Mat            m;
    3605:   PetscInt       maxHeight;

    3609:   DMClone(dm, cdm);
    3610:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
    3611:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
    3612:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
    3613:   DMSetSection(*cdm, section);
    3614:   PetscSectionDestroy(&section);
    3615:   PetscSectionCreate(PETSC_COMM_SELF, &s);
    3616:   MatCreate(PETSC_COMM_SELF, &m);
    3617:   DMSetDefaultConstraints(*cdm, s, m);
    3618:   PetscSectionDestroy(&s);
    3619:   MatDestroy(&m);
    3620:   return(0);
    3621: }

    3623: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
    3624: {
    3625:   Vec            coordsLocal;
    3626:   DM             coordsDM;

    3630:   *field = NULL;
    3631:   DMGetCoordinatesLocal(dm,&coordsLocal);
    3632:   DMGetCoordinateDM(dm,&coordsDM);
    3633:   if (coordsLocal && coordsDM) {
    3634:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
    3635:   }
    3636:   return(0);
    3637: }

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

    3642:   Not Collective

    3644:   Input Parameters:
    3645: . dm        - The DMPlex object

    3647:   Output Parameter:
    3648: . section - The PetscSection object

    3650:   Level: developer

    3652: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
    3653: @*/
    3654: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
    3655: {
    3656:   DM_Plex *mesh = (DM_Plex*) dm->data;

    3660:   if (section) *section = mesh->coneSection;
    3661:   return(0);
    3662: }

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

    3667:   Not Collective

    3669:   Input Parameters:
    3670: . dm        - The DMPlex object

    3672:   Output Parameter:
    3673: . section - The PetscSection object

    3675:   Level: developer

    3677: .seealso: DMPlexGetConeSection()
    3678: @*/
    3679: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
    3680: {
    3681:   DM_Plex *mesh = (DM_Plex*) dm->data;

    3685:   if (section) *section = mesh->supportSection;
    3686:   return(0);
    3687: }

    3689: /*@C
    3690:   DMPlexGetCones - Return cone data

    3692:   Not Collective

    3694:   Input Parameters:
    3695: . dm        - The DMPlex object

    3697:   Output Parameter:
    3698: . cones - The cone for each point

    3700:   Level: developer

    3702: .seealso: DMPlexGetConeSection()
    3703: @*/
    3704: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
    3705: {
    3706:   DM_Plex *mesh = (DM_Plex*) dm->data;

    3710:   if (cones) *cones = mesh->cones;
    3711:   return(0);
    3712: }

    3714: /*@C
    3715:   DMPlexGetConeOrientations - Return cone orientation data

    3717:   Not Collective

    3719:   Input Parameters:
    3720: . dm        - The DMPlex object

    3722:   Output Parameter:
    3723: . coneOrientations - The cone orientation for each point

    3725:   Level: developer

    3727: .seealso: DMPlexGetConeSection()
    3728: @*/
    3729: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
    3730: {
    3731:   DM_Plex *mesh = (DM_Plex*) dm->data;

    3735:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
    3736:   return(0);
    3737: }

    3739: /******************************** FEM Support **********************************/

    3741: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
    3742: {
    3743:   DMLabel        label;
    3744:   PetscInt      *perm;
    3745:   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

    3749:   if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
    3750:   DMGetDimension(dm, &dim);
    3751:   DMPlexGetDepthLabel(dm, &label);
    3752:   DMLabelGetValue(label, point, &depth);
    3753:   if (depth == 1) {eStart = point;}
    3754:   else if  (depth == dim) {
    3755:     const PetscInt *cone;

    3757:     DMPlexGetCone(dm, point, &cone);
    3758:     eStart = cone[0];
    3759:   } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering", point, depth);
    3760:   if (!section) {DMGetSection(dm, &section);}
    3761:   PetscSectionGetNumFields(section, &Nf);
    3762:   if (dim <= 1) return(0);
    3763:   for (f = 0; f < Nf; ++f) {
    3764:     /* An order k SEM disc has k-1 dofs on an edge */
    3765:     PetscSectionGetFieldDof(section, eStart, f, &k);
    3766:     PetscSectionGetFieldComponents(section, f, &Nc);
    3767:     k = k/Nc + 1;
    3768:     size += PetscPowInt(k+1, dim)*Nc;
    3769:   }
    3770:   PetscMalloc1(size, &perm);
    3771:   for (f = 0; f < Nf; ++f) {
    3772:     switch (dim) {
    3773:     case 2:
    3774:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
    3775:       PetscSectionGetFieldDof(section, eStart, f, &k);
    3776:       PetscSectionGetFieldComponents(section, f, &Nc);
    3777:       k = k/Nc + 1;
    3778:       /* The SEM order is

    3780:          v_lb, {e_b}, v_rb,
    3781:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
    3782:          v_lt, reverse {e_t}, v_rt
    3783:       */
    3784:       {
    3785:         const PetscInt of   = 0;
    3786:         const PetscInt oeb  = of   + PetscSqr(k-1);
    3787:         const PetscInt oer  = oeb  + (k-1);
    3788:         const PetscInt oet  = oer  + (k-1);
    3789:         const PetscInt oel  = oet  + (k-1);
    3790:         const PetscInt ovlb = oel  + (k-1);
    3791:         const PetscInt ovrb = ovlb + 1;
    3792:         const PetscInt ovrt = ovrb + 1;
    3793:         const PetscInt ovlt = ovrt + 1;
    3794:         PetscInt       o;

    3796:         /* bottom */
    3797:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
    3798:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
    3799:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
    3800:         /* middle */
    3801:         for (i = 0; i < k-1; ++i) {
    3802:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
    3803:           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;
    3804:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
    3805:         }
    3806:         /* top */
    3807:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
    3808:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
    3809:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
    3810:         foffset = offset;
    3811:       }
    3812:       break;
    3813:     case 3:
    3814:       /* The original hex closure is

    3816:          {c,
    3817:           f_b, f_t, f_f, f_b, f_r, f_l,
    3818:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
    3819:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
    3820:       */
    3821:       PetscSectionGetFieldDof(section, eStart, f, &k);
    3822:       PetscSectionGetFieldComponents(section, f, &Nc);
    3823:       k = k/Nc + 1;
    3824:       /* The SEM order is
    3825:          Bottom Slice
    3826:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
    3827:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
    3828:          v_blb, {e_bb}, v_brb,

    3830:          Middle Slice (j)
    3831:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
    3832:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
    3833:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

    3835:          Top Slice
    3836:          v_tlf, {e_tf}, v_trf,
    3837:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
    3838:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
    3839:       */
    3840:       {
    3841:         const PetscInt oc    = 0;
    3842:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
    3843:         const PetscInt oft   = ofb   + PetscSqr(k-1);
    3844:         const PetscInt off   = oft   + PetscSqr(k-1);
    3845:         const PetscInt ofk   = off   + PetscSqr(k-1);
    3846:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
    3847:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
    3848:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
    3849:         const PetscInt oebb  = oebl  + (k-1);
    3850:         const PetscInt oebr  = oebb  + (k-1);
    3851:         const PetscInt oebf  = oebr  + (k-1);
    3852:         const PetscInt oetf  = oebf  + (k-1);
    3853:         const PetscInt oetr  = oetf  + (k-1);
    3854:         const PetscInt oetb  = oetr  + (k-1);
    3855:         const PetscInt oetl  = oetb  + (k-1);
    3856:         const PetscInt oerf  = oetl  + (k-1);
    3857:         const PetscInt oelf  = oerf  + (k-1);
    3858:         const PetscInt oelb  = oelf  + (k-1);
    3859:         const PetscInt oerb  = oelb  + (k-1);
    3860:         const PetscInt ovblf = oerb  + (k-1);
    3861:         const PetscInt ovblb = ovblf + 1;
    3862:         const PetscInt ovbrb = ovblb + 1;
    3863:         const PetscInt ovbrf = ovbrb + 1;
    3864:         const PetscInt ovtlf = ovbrf + 1;
    3865:         const PetscInt ovtrf = ovtlf + 1;
    3866:         const PetscInt ovtrb = ovtrf + 1;
    3867:         const PetscInt ovtlb = ovtrb + 1;
    3868:         PetscInt       o, n;

    3870:         /* Bottom Slice */
    3871:         /*   bottom */
    3872:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
    3873:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
    3874:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
    3875:         /*   middle */
    3876:         for (i = 0; i < k-1; ++i) {
    3877:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
    3878:           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;}
    3879:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
    3880:         }
    3881:         /*   top */
    3882:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
    3883:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
    3884:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

    3886:         /* Middle Slice */
    3887:         for (j = 0; j < k-1; ++j) {
    3888:           /*   bottom */
    3889:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
    3890:           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;
    3891:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
    3892:           /*   middle */
    3893:           for (i = 0; i < k-1; ++i) {
    3894:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
    3895:             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;
    3896:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
    3897:           }
    3898:           /*   top */
    3899:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
    3900:           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;
    3901:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
    3902:         }

    3904:         /* Top Slice */
    3905:         /*   bottom */
    3906:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
    3907:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
    3908:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
    3909:         /*   middle */
    3910:         for (i = 0; i < k-1; ++i) {
    3911:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
    3912:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
    3913:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
    3914:         }
    3915:         /*   top */
    3916:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
    3917:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
    3918:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

    3920:         foffset = offset;
    3921:       }
    3922:       break;
    3923:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
    3924:     }
    3925:   }
    3926:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
    3927:   /* Check permutation */
    3928:   {
    3929:     PetscInt *check;

    3931:     PetscMalloc1(size, &check);
    3932:     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]);}
    3933:     for (i = 0; i < size; ++i) check[perm[i]] = i;
    3934:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
    3935:     PetscFree(check);
    3936:   }
    3937:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
    3938:   return(0);
    3939: }

    3941: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
    3942: {
    3943:   PetscDS        prob;
    3944:   PetscInt       depth, Nf, h;
    3945:   DMLabel        label;

    3949:   prob    = dm->prob;
    3950:   Nf      = prob->Nf;
    3951:   label   = dm->depthLabel;
    3952:   *dspace = NULL;
    3953:   if (field < Nf) {
    3954:     PetscObject disc = prob->disc[field];

    3956:     if (disc->classid == PETSCFE_CLASSID) {
    3957:       PetscDualSpace dsp;

    3959:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
    3960:       DMLabelGetNumValues(label,&depth);
    3961:       DMLabelGetValue(label,point,&h);
    3962:       h    = depth - 1 - h;
    3963:       if (h) {
    3964:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
    3965:       } else {
    3966:         *dspace = dsp;
    3967:       }
    3968:     }
    3969:   }
    3970:   return(0);
    3971: }

    3974: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
    3975: {
    3976:   PetscScalar    *array, *vArray;
    3977:   const PetscInt *cone, *coneO;
    3978:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
    3979:   PetscErrorCode  ierr;

    3982:   PetscSectionGetChart(section, &pStart, &pEnd);
    3983:   DMPlexGetConeSize(dm, point, &numPoints);
    3984:   DMPlexGetCone(dm, point, &cone);
    3985:   DMPlexGetConeOrientation(dm, point, &coneO);
    3986:   if (!values || !*values) {
    3987:     if ((point >= pStart) && (point < pEnd)) {
    3988:       PetscInt dof;

    3990:       PetscSectionGetDof(section, point, &dof);
    3991:       size += dof;
    3992:     }
    3993:     for (p = 0; p < numPoints; ++p) {
    3994:       const PetscInt cp = cone[p];
    3995:       PetscInt       dof;

    3997:       if ((cp < pStart) || (cp >= pEnd)) continue;
    3998:       PetscSectionGetDof(section, cp, &dof);
    3999:       size += dof;
    4000:     }
    4001:     if (!values) {
    4002:       if (csize) *csize = size;
    4003:       return(0);
    4004:     }
    4005:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
    4006:   } else {
    4007:     array = *values;
    4008:   }
    4009:   size = 0;
    4010:   VecGetArray(v, &vArray);
    4011:   if ((point >= pStart) && (point < pEnd)) {
    4012:     PetscInt     dof, off, d;
    4013:     PetscScalar *varr;

    4015:     PetscSectionGetDof(section, point, &dof);
    4016:     PetscSectionGetOffset(section, point, &off);
    4017:     varr = &vArray[off];
    4018:     for (d = 0; d < dof; ++d, ++offset) {
    4019:       array[offset] = varr[d];
    4020:     }
    4021:     size += dof;
    4022:   }
    4023:   for (p = 0; p < numPoints; ++p) {
    4024:     const PetscInt cp = cone[p];
    4025:     PetscInt       o  = coneO[p];
    4026:     PetscInt       dof, off, d;
    4027:     PetscScalar   *varr;

    4029:     if ((cp < pStart) || (cp >= pEnd)) continue;
    4030:     PetscSectionGetDof(section, cp, &dof);
    4031:     PetscSectionGetOffset(section, cp, &off);
    4032:     varr = &vArray[off];
    4033:     if (o >= 0) {
    4034:       for (d = 0; d < dof; ++d, ++offset) {
    4035:         array[offset] = varr[d];
    4036:       }
    4037:     } else {
    4038:       for (d = dof-1; d >= 0; --d, ++offset) {
    4039:         array[offset] = varr[d];
    4040:       }
    4041:     }
    4042:     size += dof;
    4043:   }
    4044:   VecRestoreArray(v, &vArray);
    4045:   if (!*values) {
    4046:     if (csize) *csize = size;
    4047:     *values = array;
    4048:   } else {
    4049:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
    4050:     *csize = size;
    4051:   }
    4052:   return(0);
    4053: }

    4055: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
    4056: {
    4057:   const PetscInt *cla;
    4058:   PetscInt       np, *pts = NULL;

    4062:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
    4063:   if (!*clPoints) {
    4064:     PetscInt pStart, pEnd, p, q;

    4066:     PetscSectionGetChart(section, &pStart, &pEnd);
    4067:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
    4068:     /* Compress out points not in the section */
    4069:     for (p = 0, q = 0; p < np; p++) {
    4070:       PetscInt r = pts[2*p];
    4071:       if ((r >= pStart) && (r < pEnd)) {
    4072:         pts[q*2]   = r;
    4073:         pts[q*2+1] = pts[2*p+1];
    4074:         ++q;
    4075:       }
    4076:     }
    4077:     np = q;
    4078:     cla = NULL;
    4079:   } else {
    4080:     PetscInt dof, off;

    4082:     PetscSectionGetDof(*clSec, point, &dof);
    4083:     PetscSectionGetOffset(*clSec, point, &off);
    4084:     ISGetIndices(*clPoints, &cla);
    4085:     np   = dof/2;
    4086:     pts  = (PetscInt *) &cla[off];
    4087:   }
    4088:   *numPoints = np;
    4089:   *points    = pts;
    4090:   *clp       = cla;

    4092:   return(0);
    4093: }

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

    4100:   if (!*clPoints) {
    4101:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
    4102:   } else {
    4103:     ISRestoreIndices(*clPoints, clp);
    4104:   }
    4105:   *numPoints = 0;
    4106:   *points    = NULL;
    4107:   *clSec     = NULL;
    4108:   *clPoints  = NULL;
    4109:   *clp       = NULL;
    4110:   return(0);
    4111: }

    4113: 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[])
    4114: {
    4115:   PetscInt          offset = 0, p;
    4116:   const PetscInt    **perms = NULL;
    4117:   const PetscScalar **flips = NULL;
    4118:   PetscErrorCode    ierr;

    4121:   *size = 0;
    4122:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
    4123:   for (p = 0; p < numPoints; p++) {
    4124:     const PetscInt    point = points[2*p];
    4125:     const PetscInt    *perm = perms ? perms[p] : NULL;
    4126:     const PetscScalar *flip = flips ? flips[p] : NULL;
    4127:     PetscInt          dof, off, d;
    4128:     const PetscScalar *varr;

    4130:     PetscSectionGetDof(section, point, &dof);
    4131:     PetscSectionGetOffset(section, point, &off);
    4132:     varr = &vArray[off];
    4133:     if (clperm) {
    4134:       if (perm) {
    4135:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
    4136:       } else {
    4137:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
    4138:       }
    4139:       if (flip) {
    4140:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
    4141:       }
    4142:     } else {
    4143:       if (perm) {
    4144:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
    4145:       } else {
    4146:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
    4147:       }
    4148:       if (flip) {
    4149:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
    4150:       }
    4151:     }
    4152:     offset += dof;
    4153:   }
    4154:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
    4155:   *size = offset;
    4156:   return(0);
    4157: }

    4159: 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[])
    4160: {
    4161:   PetscInt          offset = 0, f;
    4162:   PetscErrorCode    ierr;

    4165:   *size = 0;
    4166:   for (f = 0; f < numFields; ++f) {
    4167:     PetscInt          p;
    4168:     const PetscInt    **perms = NULL;
    4169:     const PetscScalar **flips = NULL;

    4171:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
    4172:     for (p = 0; p < numPoints; p++) {
    4173:       const PetscInt    point = points[2*p];
    4174:       PetscInt          fdof, foff, b;
    4175:       const PetscScalar *varr;
    4176:       const PetscInt    *perm = perms ? perms[p] : NULL;
    4177:       const PetscScalar *flip = flips ? flips[p] : NULL;

    4179:       PetscSectionGetFieldDof(section, point, f, &fdof);
    4180:       PetscSectionGetFieldOffset(section, point, f, &foff);
    4181:       varr = &vArray[foff];
    4182:       if (clperm) {
    4183:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
    4184:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
    4185:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
    4186:       } else {
    4187:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
    4188:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
    4189:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
    4190:       }
    4191:       offset += fdof;
    4192:     }
    4193:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
    4194:   }
    4195:   *size = offset;
    4196:   return(0);
    4197: }

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

    4202:   Not collective

    4204:   Input Parameters:
    4205: + dm - The DM
    4206: . section - The section describing the layout in v, or NULL to use the default section
    4207: . v - The local vector
    4208: . point - The point in the DM
    4209: . csize - The size of the input values array, or NULL
    4210: - values - An array to use for the values, or NULL to have it allocated automatically

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

    4216: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
    4217: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
    4218: $ assembly function, and a user may already have allocated storage for this operation.
    4219: $
    4220: $ A typical use could be
    4221: $
    4222: $  values = NULL;
    4223: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
    4224: $  for (cl = 0; cl < clSize; ++cl) {
    4225: $    <Compute on closure>
    4226: $  }
    4227: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
    4228: $
    4229: $ or
    4230: $
    4231: $  PetscMalloc1(clMaxSize, &values);
    4232: $  for (p = pStart; p < pEnd; ++p) {
    4233: $    clSize = clMaxSize;
    4234: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
    4235: $    for (cl = 0; cl < clSize; ++cl) {
    4236: $      <Compute on closure>
    4237: $    }
    4238: $  }
    4239: $  PetscFree(values);

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

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

    4247:   Level: intermediate

    4249: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
    4250: @*/
    4251: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
    4252: {
    4253:   PetscSection       clSection;
    4254:   IS                 clPoints;
    4255:   PetscScalar       *array;
    4256:   const PetscScalar *vArray;
    4257:   PetscInt          *points = NULL;
    4258:   const PetscInt    *clp, *perm;
    4259:   PetscInt           depth, numFields, numPoints, size;
    4260:   PetscErrorCode     ierr;

    4264:   if (!section) {DMGetSection(dm, &section);}
    4267:   DMPlexGetDepth(dm, &depth);
    4268:   PetscSectionGetNumFields(section, &numFields);
    4269:   if (depth == 1 && numFields < 2) {
    4270:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
    4271:     return(0);
    4272:   }
    4273:   /* Get points */
    4274:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    4275:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
    4276:   /* Get array */
    4277:   if (!values || !*values) {
    4278:     PetscInt asize = 0, dof, p;

    4280:     for (p = 0; p < numPoints*2; p += 2) {
    4281:       PetscSectionGetDof(section, points[p], &dof);
    4282:       asize += dof;
    4283:     }
    4284:     if (!values) {
    4285:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    4286:       if (csize) *csize = asize;
    4287:       return(0);
    4288:     }
    4289:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
    4290:   } else {
    4291:     array = *values;
    4292:   }
    4293:   VecGetArrayRead(v, &vArray);
    4294:   /* Get values */
    4295:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
    4296:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
    4297:   /* Cleanup points */
    4298:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    4299:   /* Cleanup array */
    4300:   VecRestoreArrayRead(v, &vArray);
    4301:   if (!*values) {
    4302:     if (csize) *csize = size;
    4303:     *values = array;
    4304:   } else {
    4305:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
    4306:     *csize = size;
    4307:   }
    4308:   return(0);
    4309: }

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

    4314:   Not collective

    4316:   Input Parameters:
    4317: + dm - The DM
    4318: . section - The section describing the layout in v, or NULL to use the default section
    4319: . v - The local vector
    4320: . point - The point in the DM
    4321: . csize - The number of values in the closure, or NULL
    4322: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

    4332:   Level: intermediate

    4334: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
    4335: @*/
    4336: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
    4337: {
    4338:   PetscInt       size = 0;

    4342:   /* Should work without recalculating size */
    4343:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
    4344:   *values = NULL;
    4345:   return(0);
    4346: }

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

    4351: 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[])
    4352: {
    4353:   PetscInt        cdof;   /* The number of constraints on this point */
    4354:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
    4355:   PetscScalar    *a;
    4356:   PetscInt        off, cind = 0, k;
    4357:   PetscErrorCode  ierr;

    4360:   PetscSectionGetConstraintDof(section, point, &cdof);
    4361:   PetscSectionGetOffset(section, point, &off);
    4362:   a    = &array[off];
    4363:   if (!cdof || setBC) {
    4364:     if (clperm) {
    4365:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
    4366:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
    4367:     } else {
    4368:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
    4369:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
    4370:     }
    4371:   } else {
    4372:     PetscSectionGetConstraintIndices(section, point, &cdofs);
    4373:     if (clperm) {
    4374:       if (perm) {for (k = 0; k < dof; ++k) {
    4375:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    4376:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
    4377:         }
    4378:       } else {
    4379:         for (k = 0; k < dof; ++k) {
    4380:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    4381:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
    4382:         }
    4383:       }
    4384:     } else {
    4385:       if (perm) {
    4386:         for (k = 0; k < dof; ++k) {
    4387:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    4388:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
    4389:         }
    4390:       } else {
    4391:         for (k = 0; k < dof; ++k) {
    4392:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    4393:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
    4394:         }
    4395:       }
    4396:     }
    4397:   }
    4398:   return(0);
    4399: }

    4401: 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[])
    4402: {
    4403:   PetscInt        cdof;   /* The number of constraints on this point */
    4404:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
    4405:   PetscScalar    *a;
    4406:   PetscInt        off, cind = 0, k;
    4407:   PetscErrorCode  ierr;

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

    4452: 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[])
    4453: {
    4454:   PetscScalar    *a;
    4455:   PetscInt        fdof, foff, fcdof, foffset = *offset;
    4456:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
    4457:   PetscInt        cind = 0, b;
    4458:   PetscErrorCode  ierr;

    4461:   PetscSectionGetFieldDof(section, point, f, &fdof);
    4462:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
    4463:   PetscSectionGetFieldOffset(section, point, f, &foff);
    4464:   a    = &array[foff];
    4465:   if (!fcdof || setBC) {
    4466:     if (clperm) {
    4467:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
    4468:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
    4469:     } else {
    4470:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
    4471:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
    4472:     }
    4473:   } else {
    4474:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
    4475:     if (clperm) {
    4476:       if (perm) {
    4477:         for (b = 0; b < fdof; b++) {
    4478:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
    4479:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
    4480:         }
    4481:       } else {
    4482:         for (b = 0; b < fdof; b++) {
    4483:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
    4484:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
    4485:         }
    4486:       }
    4487:     } else {
    4488:       if (perm) {
    4489:         for (b = 0; b < fdof; b++) {
    4490:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
    4491:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
    4492:         }
    4493:       } else {
    4494:         for (b = 0; b < fdof; b++) {
    4495:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
    4496:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
    4497:         }
    4498:       }
    4499:     }
    4500:   }
    4501:   *offset += fdof;
    4502:   return(0);
    4503: }

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

    4515:   PetscSectionGetFieldDof(section, point, f, &fdof);
    4516:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
    4517:   PetscSectionGetFieldOffset(section, point, f, &foff);
    4518:   a    = &array[foff];
    4519:   if (fcdof) {
    4520:     /* We just override fcdof and fcdofs with Ncc and comps */
    4521:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
    4522:     if (clperm) {
    4523:       if (perm) {
    4524:         if (comps) {
    4525:           for (b = 0; b < fdof; b++) {
    4526:             ncSet = fcSet = PETSC_FALSE;
    4527:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
    4528:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
    4529:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
    4530:           }
    4531:         } else {
    4532:           for (b = 0; b < fdof; b++) {
    4533:             if ((cind < fcdof) && (b == fcdofs[cind])) {
    4534:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
    4535:               ++cind;
    4536:             }
    4537:           }
    4538:         }
    4539:       } else {
    4540:         if (comps) {
    4541:           for (b = 0; b < fdof; b++) {
    4542:             ncSet = fcSet = PETSC_FALSE;
    4543:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
    4544:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
    4545:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
    4546:           }
    4547:         } else {
    4548:           for (b = 0; b < fdof; b++) {
    4549:             if ((cind < fcdof) && (b == fcdofs[cind])) {
    4550:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
    4551:               ++cind;
    4552:             }
    4553:           }
    4554:         }
    4555:       }
    4556:     } else {
    4557:       if (perm) {
    4558:         if (comps) {
    4559:           for (b = 0; b < fdof; b++) {
    4560:             ncSet = fcSet = PETSC_FALSE;
    4561:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
    4562:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
    4563:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
    4564:           }
    4565:         } else {
    4566:           for (b = 0; b < fdof; b++) {
    4567:             if ((cind < fcdof) && (b == fcdofs[cind])) {
    4568:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
    4569:               ++cind;
    4570:             }
    4571:           }
    4572:         }
    4573:       } else {
    4574:         if (comps) {
    4575:           for (b = 0; b < fdof; b++) {
    4576:             ncSet = fcSet = PETSC_FALSE;
    4577:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
    4578:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
    4579:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
    4580:           }
    4581:         } else {
    4582:           for (b = 0; b < fdof; b++) {
    4583:             if ((cind < fcdof) && (b == fcdofs[cind])) {
    4584:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
    4585:               ++cind;
    4586:             }
    4587:           }
    4588:         }
    4589:       }
    4590:     }
    4591:   }
    4592:   *offset += fdof;
    4593:   return(0);
    4594: }

    4596: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
    4597: {
    4598:   PetscScalar    *array;
    4599:   const PetscInt *cone, *coneO;
    4600:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
    4601:   PetscErrorCode  ierr;

    4604:   PetscSectionGetChart(section, &pStart, &pEnd);
    4605:   DMPlexGetConeSize(dm, point, &numPoints);
    4606:   DMPlexGetCone(dm, point, &cone);
    4607:   DMPlexGetConeOrientation(dm, point, &coneO);
    4608:   VecGetArray(v, &array);
    4609:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
    4610:     const PetscInt cp = !p ? point : cone[p-1];
    4611:     const PetscInt o  = !p ? 0     : coneO[p-1];

    4613:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
    4614:     PetscSectionGetDof(section, cp, &dof);
    4615:     /* ADD_VALUES */
    4616:     {
    4617:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
    4618:       PetscScalar    *a;
    4619:       PetscInt        cdof, coff, cind = 0, k;

    4621:       PetscSectionGetConstraintDof(section, cp, &cdof);
    4622:       PetscSectionGetOffset(section, cp, &coff);
    4623:       a    = &array[coff];
    4624:       if (!cdof) {
    4625:         if (o >= 0) {
    4626:           for (k = 0; k < dof; ++k) {
    4627:             a[k] += values[off+k];
    4628:           }
    4629:         } else {
    4630:           for (k = 0; k < dof; ++k) {
    4631:             a[k] += values[off+dof-k-1];
    4632:           }
    4633:         }
    4634:       } else {
    4635:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
    4636:         if (o >= 0) {
    4637:           for (k = 0; k < dof; ++k) {
    4638:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    4639:             a[k] += values[off+k];
    4640:           }
    4641:         } else {
    4642:           for (k = 0; k < dof; ++k) {
    4643:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    4644:             a[k] += values[off+dof-k-1];
    4645:           }
    4646:         }
    4647:       }
    4648:     }
    4649:   }
    4650:   VecRestoreArray(v, &array);
    4651:   return(0);
    4652: }

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

    4657:   Not collective

    4659:   Input Parameters:
    4660: + dm - The DM
    4661: . section - The section describing the layout in v, or NULL to use the default section
    4662: . v - The local vector
    4663: . point - The point in the DM
    4664: . values - The array of values
    4665: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
    4666:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

    4671:   Level: intermediate

    4673: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
    4674: @*/
    4675: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
    4676: {
    4677:   PetscSection    clSection;
    4678:   IS              clPoints;
    4679:   PetscScalar    *array;
    4680:   PetscInt       *points = NULL;
    4681:   const PetscInt *clp, *clperm;
    4682:   PetscInt        depth, numFields, numPoints, p;
    4683:   PetscErrorCode  ierr;

    4687:   if (!section) {DMGetSection(dm, &section);}
    4690:   DMPlexGetDepth(dm, &depth);
    4691:   PetscSectionGetNumFields(section, &numFields);
    4692:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
    4693:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
    4694:     return(0);
    4695:   }
    4696:   /* Get points */
    4697:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
    4698:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    4699:   /* Get array */
    4700:   VecGetArray(v, &array);
    4701:   /* Get values */
    4702:   if (numFields > 0) {
    4703:     PetscInt offset = 0, f;
    4704:     for (f = 0; f < numFields; ++f) {
    4705:       const PetscInt    **perms = NULL;
    4706:       const PetscScalar **flips = NULL;

    4708:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
    4709:       switch (mode) {
    4710:       case INSERT_VALUES:
    4711:         for (p = 0; p < numPoints; p++) {
    4712:           const PetscInt    point = points[2*p];
    4713:           const PetscInt    *perm = perms ? perms[p] : NULL;
    4714:           const PetscScalar *flip = flips ? flips[p] : NULL;
    4715:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
    4716:         } break;
    4717:       case INSERT_ALL_VALUES:
    4718:         for (p = 0; p < numPoints; p++) {
    4719:           const PetscInt    point = points[2*p];
    4720:           const PetscInt    *perm = perms ? perms[p] : NULL;
    4721:           const PetscScalar *flip = flips ? flips[p] : NULL;
    4722:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
    4723:         } break;
    4724:       case INSERT_BC_VALUES:
    4725:         for (p = 0; p < numPoints; p++) {
    4726:           const PetscInt    point = points[2*p];
    4727:           const PetscInt    *perm = perms ? perms[p] : NULL;
    4728:           const PetscScalar *flip = flips ? flips[p] : NULL;
    4729:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
    4730:         } break;
    4731:       case ADD_VALUES:
    4732:         for (p = 0; p < numPoints; p++) {
    4733:           const PetscInt    point = points[2*p];
    4734:           const PetscInt    *perm = perms ? perms[p] : NULL;
    4735:           const PetscScalar *flip = flips ? flips[p] : NULL;
    4736:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
    4737:         } break;
    4738:       case ADD_ALL_VALUES:
    4739:         for (p = 0; p < numPoints; p++) {
    4740:           const PetscInt    point = points[2*p];
    4741:           const PetscInt    *perm = perms ? perms[p] : NULL;
    4742:           const PetscScalar *flip = flips ? flips[p] : NULL;
    4743:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
    4744:         } break;
    4745:       case ADD_BC_VALUES:
    4746:         for (p = 0; p < numPoints; p++) {
    4747:           const PetscInt    point = points[2*p];
    4748:           const PetscInt    *perm = perms ? perms[p] : NULL;
    4749:           const PetscScalar *flip = flips ? flips[p] : NULL;
    4750:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
    4751:         } break;
    4752:       default:
    4753:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
    4754:       }
    4755:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
    4756:     }
    4757:   } else {
    4758:     PetscInt dof, off;
    4759:     const PetscInt    **perms = NULL;
    4760:     const PetscScalar **flips = NULL;

    4762:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
    4763:     switch (mode) {
    4764:     case INSERT_VALUES:
    4765:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
    4766:         const PetscInt    point = points[2*p];
    4767:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4768:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4769:         PetscSectionGetDof(section, point, &dof);
    4770:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
    4771:       } break;
    4772:     case INSERT_ALL_VALUES:
    4773:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
    4774:         const PetscInt    point = points[2*p];
    4775:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4776:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4777:         PetscSectionGetDof(section, point, &dof);
    4778:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
    4779:       } break;
    4780:     case INSERT_BC_VALUES:
    4781:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
    4782:         const PetscInt    point = points[2*p];
    4783:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4784:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4785:         PetscSectionGetDof(section, point, &dof);
    4786:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
    4787:       } break;
    4788:     case ADD_VALUES:
    4789:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
    4790:         const PetscInt    point = points[2*p];
    4791:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4792:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4793:         PetscSectionGetDof(section, point, &dof);
    4794:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
    4795:       } break;
    4796:     case ADD_ALL_VALUES:
    4797:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
    4798:         const PetscInt    point = points[2*p];
    4799:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4800:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4801:         PetscSectionGetDof(section, point, &dof);
    4802:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
    4803:       } break;
    4804:     case ADD_BC_VALUES:
    4805:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
    4806:         const PetscInt    point = points[2*p];
    4807:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4808:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4809:         PetscSectionGetDof(section, point, &dof);
    4810:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
    4811:       } break;
    4812:     default:
    4813:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
    4814:     }
    4815:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
    4816:   }
    4817:   /* Cleanup points */
    4818:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    4819:   /* Cleanup array */
    4820:   VecRestoreArray(v, &array);
    4821:   return(0);
    4822: }

    4824: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
    4825: {
    4826:   PetscSection      clSection;
    4827:   IS                clPoints;
    4828:   PetscScalar       *array;
    4829:   PetscInt          *points = NULL;
    4830:   const PetscInt    *clp, *clperm;
    4831:   PetscInt          numFields, numPoints, p;
    4832:   PetscInt          offset = 0, f;
    4833:   PetscErrorCode    ierr;

    4837:   if (!section) {DMGetSection(dm, &section);}
    4840:   PetscSectionGetNumFields(section, &numFields);
    4841:   /* Get points */
    4842:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
    4843:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    4844:   /* Get array */
    4845:   VecGetArray(v, &array);
    4846:   /* Get values */
    4847:   for (f = 0; f < numFields; ++f) {
    4848:     const PetscInt    **perms = NULL;
    4849:     const PetscScalar **flips = NULL;

    4851:     if (!fieldActive[f]) {
    4852:       for (p = 0; p < numPoints*2; p += 2) {
    4853:         PetscInt fdof;
    4854:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
    4855:         offset += fdof;
    4856:       }
    4857:       continue;
    4858:     }
    4859:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
    4860:     switch (mode) {
    4861:     case INSERT_VALUES:
    4862:       for (p = 0; p < numPoints; p++) {
    4863:         const PetscInt    point = points[2*p];
    4864:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4865:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4866:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
    4867:       } break;
    4868:     case INSERT_ALL_VALUES:
    4869:       for (p = 0; p < numPoints; p++) {
    4870:         const PetscInt    point = points[2*p];
    4871:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4872:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4873:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
    4874:         } break;
    4875:     case INSERT_BC_VALUES:
    4876:       for (p = 0; p < numPoints; p++) {
    4877:         const PetscInt    point = points[2*p];
    4878:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4879:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4880:         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
    4881:       } break;
    4882:     case ADD_VALUES:
    4883:       for (p = 0; p < numPoints; p++) {
    4884:         const PetscInt    point = points[2*p];
    4885:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4886:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4887:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
    4888:       } break;
    4889:     case ADD_ALL_VALUES:
    4890:       for (p = 0; p < numPoints; p++) {
    4891:         const PetscInt    point = points[2*p];
    4892:         const PetscInt    *perm = perms ? perms[p] : NULL;
    4893:         const PetscScalar *flip = flips ? flips[p] : NULL;
    4894:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
    4895:       } break;
    4896:     default:
    4897:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
    4898:     }
    4899:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
    4900:   }
    4901:   /* Cleanup points */
    4902:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    4903:   /* Cleanup array */
    4904:   VecRestoreArray(v, &array);
    4905:   return(0);
    4906: }

    4908: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
    4909: {
    4910:   PetscMPIInt    rank;
    4911:   PetscInt       i, j;

    4915:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
    4916:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
    4917:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
    4918:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
    4919:   numCIndices = numCIndices ? numCIndices : numRIndices;
    4920:   for (i = 0; i < numRIndices; i++) {
    4921:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
    4922:     for (j = 0; j < numCIndices; j++) {
    4923: #if defined(PETSC_USE_COMPLEX)
    4924:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
    4925: #else
    4926:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
    4927: #endif
    4928:     }
    4929:     PetscViewerASCIIPrintf(viewer, "\n");
    4930:   }
    4931:   return(0);
    4932: }

    4934: /* . off - The global offset of this point */
    4935: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
    4936: {
    4937:   PetscInt        dof;    /* The number of unknowns on this point */
    4938:   PetscInt        cdof;   /* The number of constraints on this point */
    4939:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
    4940:   PetscInt        cind = 0, k;
    4941:   PetscErrorCode  ierr;

    4944:   PetscSectionGetDof(section, point, &dof);
    4945:   PetscSectionGetConstraintDof(section, point, &cdof);
    4946:   if (!cdof || setBC) {
    4947:     if (perm) {
    4948:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
    4949:     } else {
    4950:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
    4951:     }
    4952:   } else {
    4953:     PetscSectionGetConstraintIndices(section, point, &cdofs);
    4954:     if (perm) {
    4955:       for (k = 0; k < dof; ++k) {
    4956:         if ((cind < cdof) && (k == cdofs[cind])) {
    4957:           /* Insert check for returning constrained indices */
    4958:           indices[*loff+perm[k]] = -(off+k+1);
    4959:           ++cind;
    4960:         } else {
    4961:           indices[*loff+perm[k]] = off+k-cind;
    4962:         }
    4963:       }
    4964:     } else {
    4965:       for (k = 0; k < dof; ++k) {
    4966:         if ((cind < cdof) && (k == cdofs[cind])) {
    4967:           /* Insert check for returning constrained indices */
    4968:           indices[*loff+k] = -(off+k+1);
    4969:           ++cind;
    4970:         } else {
    4971:           indices[*loff+k] = off+k-cind;
    4972:         }
    4973:       }
    4974:     }
    4975:   }
    4976:   *loff += dof;
    4977:   return(0);
    4978: }

    4980: /*
    4981:   This version only believes the point offset from the globalSection

    4983:  . off - The global offset of this point
    4984: */
    4985: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
    4986: {
    4987:   PetscInt       numFields, foff, f;

    4991:   PetscSectionGetNumFields(section, &numFields);
    4992:   for (f = 0, foff = 0; f < numFields; ++f) {
    4993:     PetscInt        fdof, cfdof;
    4994:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
    4995:     PetscInt        cind = 0, b;
    4996:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

    4998:     PetscSectionGetFieldDof(section, point, f, &fdof);
    4999:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
    5000:     if (!cfdof || setBC) {
    5001:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
    5002:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
    5003:     } else {
    5004:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
    5005:       if (perm) {
    5006:         for (b = 0; b < fdof; b++) {
    5007:           if ((cind < cfdof) && (b == fcdofs[cind])) {
    5008:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
    5009:             ++cind;
    5010:           } else {
    5011:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
    5012:           }
    5013:         }
    5014:       } else {
    5015:         for (b = 0; b < fdof; b++) {
    5016:           if ((cind < cfdof) && (b == fcdofs[cind])) {
    5017:             indices[foffs[f]+b] = -(off+foff+b+1);
    5018:             ++cind;
    5019:           } else {
    5020:             indices[foffs[f]+b] = off+foff+b-cind;
    5021:           }
    5022:         }
    5023:       }
    5024:     }
    5025:     foff     += (setBC ? fdof : (fdof - cfdof));
    5026:     foffs[f] += fdof;
    5027:   }
    5028:   return(0);
    5029: }

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

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

    5042:   PetscSectionGetNumFields(section, &numFields);
    5043:   for (f = 0; f < numFields; ++f) {
    5044:     PetscInt        fdof, cfdof;
    5045:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
    5046:     PetscInt        cind = 0, b;
    5047:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

    5049:     PetscSectionGetFieldDof(section, point, f, &fdof);
    5050:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
    5051:     PetscSectionGetFieldOffset(globalSection, point, f, &foff);
    5052:     if (!cfdof || setBC) {
    5053:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = foff+b;}}
    5054:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = foff+b;}}
    5055:     } else {
    5056:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
    5057:       if (perm) {
    5058:         for (b = 0; b < fdof; b++) {
    5059:           if ((cind < cfdof) && (b == fcdofs[cind])) {
    5060:             indices[foffs[f]+perm[b]] = -(foff+b+1);
    5061:             ++cind;
    5062:           } else {
    5063:             indices[foffs[f]+perm[b]] = foff+b-cind;
    5064:           }
    5065:         }
    5066:       } else {
    5067:         for (b = 0; b < fdof; b++) {
    5068:           if ((cind < cfdof) && (b == fcdofs[cind])) {
    5069:             indices[foffs[f]+b] = -(foff+b+1);
    5070:             ++cind;
    5071:           } else {
    5072:             indices[foffs[f]+b] = foff+b-cind;
    5073:           }
    5074:         }
    5075:       }
    5076:     }
    5077:     foffs[f] += fdof;
    5078:   }
    5079:   return(0);
    5080: }

    5082: 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)
    5083: {
    5084:   Mat             cMat;
    5085:   PetscSection    aSec, cSec;
    5086:   IS              aIS;
    5087:   PetscInt        aStart = -1, aEnd = -1;
    5088:   const PetscInt  *anchors;
    5089:   PetscInt        numFields, f, p, q, newP = 0;
    5090:   PetscInt        newNumPoints = 0, newNumIndices = 0;
    5091:   PetscInt        *newPoints, *indices, *newIndices;
    5092:   PetscInt        maxAnchor, maxDof;
    5093:   PetscInt        newOffsets[32];
    5094:   PetscInt        *pointMatOffsets[32];
    5095:   PetscInt        *newPointOffsets[32];
    5096:   PetscScalar     *pointMat[32];
    5097:   PetscScalar     *newValues=NULL,*tmpValues;
    5098:   PetscBool       anyConstrained = PETSC_FALSE;
    5099:   PetscErrorCode  ierr;

    5104:   PetscSectionGetNumFields(section, &numFields);

    5106:   DMPlexGetAnchors(dm,&aSec,&aIS);
    5107:   /* if there are point-to-point constraints */
    5108:   if (aSec) {
    5109:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
    5110:     ISGetIndices(aIS,&anchors);
    5111:     PetscSectionGetChart(aSec,&aStart,&aEnd);
    5112:     /* figure out how many points are going to be in the new element matrix
    5113:      * (we allow double counting, because it's all just going to be summed
    5114:      * into the global matrix anyway) */
    5115:     for (p = 0; p < 2*numPoints; p+=2) {
    5116:       PetscInt b    = points[p];
    5117:       PetscInt bDof = 0, bSecDof;

    5119:       PetscSectionGetDof(section,b,&bSecDof);
    5120:       if (!bSecDof) {
    5121:         continue;
    5122:       }
    5123:       if (b >= aStart && b < aEnd) {
    5124:         PetscSectionGetDof(aSec,b,&bDof);
    5125:       }
    5126:       if (bDof) {
    5127:         /* this point is constrained */
    5128:         /* it is going to be replaced by its anchors */
    5129:         PetscInt bOff, q;

    5131:         anyConstrained = PETSC_TRUE;
    5132:         newNumPoints  += bDof;
    5133:         PetscSectionGetOffset(aSec,b,&bOff);
    5134:         for (q = 0; q < bDof; q++) {
    5135:           PetscInt a = anchors[bOff + q];
    5136:           PetscInt aDof;

    5138:           PetscSectionGetDof(section,a,&aDof);
    5139:           newNumIndices += aDof;
    5140:           for (f = 0; f < numFields; ++f) {
    5141:             PetscInt fDof;

    5143:             PetscSectionGetFieldDof(section, a, f, &fDof);
    5144:             newOffsets[f+1] += fDof;
    5145:           }
    5146:         }
    5147:       }
    5148:       else {
    5149:         /* this point is not constrained */
    5150:         newNumPoints++;
    5151:         newNumIndices += bSecDof;
    5152:         for (f = 0; f < numFields; ++f) {
    5153:           PetscInt fDof;

    5155:           PetscSectionGetFieldDof(section, b, f, &fDof);
    5156:           newOffsets[f+1] += fDof;
    5157:         }
    5158:       }
    5159:     }
    5160:   }
    5161:   if (!anyConstrained) {
    5162:     if (outNumPoints)  *outNumPoints  = 0;
    5163:     if (outNumIndices) *outNumIndices = 0;
    5164:     if (outPoints)     *outPoints     = NULL;
    5165:     if (outValues)     *outValues     = NULL;
    5166:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
    5167:     return(0);
    5168:   }

    5170:   if (outNumPoints)  *outNumPoints  = newNumPoints;
    5171:   if (outNumIndices) *outNumIndices = newNumIndices;

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

    5175:   if (!outPoints && !outValues) {
    5176:     if (offsets) {
    5177:       for (f = 0; f <= numFields; f++) {
    5178:         offsets[f] = newOffsets[f];
    5179:       }
    5180:     }
    5181:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
    5182:     return(0);
    5183:   }

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

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

    5189:   /* workspaces */
    5190:   if (numFields) {
    5191:     for (f = 0; f < numFields; f++) {
    5192:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
    5193:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
    5194:     }
    5195:   }
    5196:   else {
    5197:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
    5198:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
    5199:   }

    5201:   /* get workspaces for the point-to-point matrices */
    5202:   if (numFields) {
    5203:     PetscInt totalOffset, totalMatOffset;

    5205:     for (p = 0; p < numPoints; p++) {
    5206:       PetscInt b    = points[2*p];
    5207:       PetscInt bDof = 0, bSecDof;

    5209:       PetscSectionGetDof(section,b,&bSecDof);
    5210:       if (!bSecDof) {
    5211:         for (f = 0; f < numFields; f++) {
    5212:           newPointOffsets[f][p + 1] = 0;
    5213:           pointMatOffsets[f][p + 1] = 0;
    5214:         }
    5215:         continue;
    5216:       }
    5217:       if (b >= aStart && b < aEnd) {
    5218:         PetscSectionGetDof(aSec, b, &bDof);
    5219:       }
    5220:       if (bDof) {
    5221:         for (f = 0; f < numFields; f++) {
    5222:           PetscInt fDof, q, bOff, allFDof = 0;

    5224:           PetscSectionGetFieldDof(section, b, f, &fDof);
    5225:           PetscSectionGetOffset(aSec, b, &bOff);
    5226:           for (q = 0; q < bDof; q++) {
    5227:             PetscInt a = anchors[bOff + q];
    5228:             PetscInt aFDof;

    5230:             PetscSectionGetFieldDof(section, a, f, &aFDof);
    5231:             allFDof += aFDof;
    5232:           }
    5233:           newPointOffsets[f][p+1] = allFDof;
    5234:           pointMatOffsets[f][p+1] = fDof * allFDof;
    5235:         }
    5236:       }
    5237:       else {
    5238:         for (f = 0; f < numFields; f++) {
    5239:           PetscInt fDof;

    5241:           PetscSectionGetFieldDof(section, b, f, &fDof);
    5242:           newPointOffsets[f][p+1] = fDof;
    5243:           pointMatOffsets[f][p+1] = 0;
    5244:         }
    5245:       }
    5246:     }
    5247:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
    5248:       newPointOffsets[f][0] = totalOffset;
    5249:       pointMatOffsets[f][0] = totalMatOffset;
    5250:       for (p = 0; p < numPoints; p++) {
    5251:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
    5252:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
    5253:       }
    5254:       totalOffset    = newPointOffsets[f][numPoints];
    5255:       totalMatOffset = pointMatOffsets[f][numPoints];
    5256:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
    5257:     }
    5258:   }
    5259:   else {
    5260:     for (p = 0; p < numPoints; p++) {
    5261:       PetscInt b    = points[2*p];
    5262:       PetscInt bDof = 0, bSecDof;

    5264:       PetscSectionGetDof(section,b,&bSecDof);
    5265:       if (!bSecDof) {
    5266:         newPointOffsets[0][p + 1] = 0;
    5267:         pointMatOffsets[0][p + 1] = 0;
    5268:         continue;
    5269:       }
    5270:       if (b >= aStart && b < aEnd) {
    5271:         PetscSectionGetDof(aSec, b, &bDof);
    5272:       }
    5273:       if (bDof) {
    5274:         PetscInt bOff, q, allDof = 0;

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

    5280:           PetscSectionGetDof(section, a, &aDof);
    5281:           allDof += aDof;
    5282:         }
    5283:         newPointOffsets[0][p+1] = allDof;
    5284:         pointMatOffsets[0][p+1] = bSecDof * allDof;
    5285:       }
    5286:       else {
    5287:         newPointOffsets[0][p+1] = bSecDof;
    5288:         pointMatOffsets[0][p+1] = 0;
    5289:       }
    5290:     }
    5291:     newPointOffsets[0][0] = 0;
    5292:     pointMatOffsets[0][0] = 0;
    5293:     for (p = 0; p < numPoints; p++) {
    5294:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
    5295:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
    5296:     }
    5297:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
    5298:   }

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

    5303:   /* get the point-to-point matrices; construct newPoints */
    5304:   PetscSectionGetMaxDof(aSec, &maxAnchor);
    5305:   PetscSectionGetMaxDof(section, &maxDof);
    5306:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
    5307:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
    5308:   if (numFields) {
    5309:     for (p = 0, newP = 0; p < numPoints; p++) {
    5310:       PetscInt b    = points[2*p];
    5311:       PetscInt o    = points[2*p+1];
    5312:       PetscInt bDof = 0, bSecDof;

    5314:       PetscSectionGetDof(section, b, &bSecDof);
    5315:       if (!bSecDof) {
    5316:         continue;
    5317:       }
    5318:       if (b >= aStart && b < aEnd) {
    5319:         PetscSectionGetDof(aSec, b, &bDof);
    5320:       }
    5321:       if (bDof) {
    5322:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

    5324:         fStart[0] = 0;
    5325:         fEnd[0]   = 0;
    5326:         for (f = 0; f < numFields; f++) {
    5327:           PetscInt fDof;

    5329:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
    5330:           fStart[f+1] = fStart[f] + fDof;
    5331:           fEnd[f+1]   = fStart[f+1];
    5332:         }
    5333:         PetscSectionGetOffset(cSec, b, &bOff);
    5334:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

    5336:         fAnchorStart[0] = 0;
    5337:         fAnchorEnd[0]   = 0;
    5338:         for (f = 0; f < numFields; f++) {
    5339:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

    5341:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
    5342:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
    5343:         }
    5344:         PetscSectionGetOffset(aSec, b, &bOff);
    5345:         for (q = 0; q < bDof; q++) {
    5346:           PetscInt a = anchors[bOff + q], aOff;

    5348:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
    5349:           newPoints[2*(newP + q)]     = a;
    5350:           newPoints[2*(newP + q) + 1] = 0;
    5351:           PetscSectionGetOffset(section, a, &aOff);
    5352:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
    5353:         }
    5354:         newP += bDof;

    5356:         if (outValues) {
    5357:           /* get the point-to-point submatrix */
    5358:           for (f = 0; f < numFields; f++) {
    5359:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
    5360:           }
    5361:         }
    5362:       }
    5363:       else {
    5364:         newPoints[2 * newP]     = b;
    5365:         newPoints[2 * newP + 1] = o;
    5366:         newP++;
    5367:       }
    5368:     }
    5369:   } else {
    5370:     for (p = 0; p < numPoints; p++) {
    5371:       PetscInt b    = points[2*p];
    5372:       PetscInt o    = points[2*p+1];
    5373:       PetscInt bDof = 0, bSecDof;

    5375:       PetscSectionGetDof(section, b, &bSecDof);
    5376:       if (!bSecDof) {
    5377:         continue;
    5378:       }
    5379:       if (b >= aStart && b < aEnd) {
    5380:         PetscSectionGetDof(aSec, b, &bDof);
    5381:       }
    5382:       if (bDof) {
    5383:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

    5394:           newPoints[2*(newP + q)]     = a;
    5395:           newPoints[2*(newP + q) + 1] = 0;
    5396:           PetscSectionGetOffset(section, a, &aOff);
    5397:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
    5398:         }
    5399:         newP += bDof;

    5401:         /* get the point-to-point submatrix */
    5402:         if (outValues) {
    5403:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
    5404:         }
    5405:       }
    5406:       else {
    5407:         newPoints[2 * newP]     = b;
    5408:         newPoints[2 * newP + 1] = o;
    5409:         newP++;
    5410:       }
    5411:     }
    5412:   }

    5414:   if (outValues) {
    5415:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
    5416:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
    5417:     /* multiply constraints on the right */
    5418:     if (numFields) {
    5419:       for (f = 0; f < numFields; f++) {
    5420:         PetscInt oldOff = offsets[f];

    5422:         for (p = 0; p < numPoints; p++) {
    5423:           PetscInt cStart = newPointOffsets[f][p];
    5424:           PetscInt b      = points[2 * p];
    5425:           PetscInt c, r, k;
    5426:           PetscInt dof;

    5428:           PetscSectionGetFieldDof(section,b,f,&dof);
    5429:           if (!dof) {
    5430:             continue;
    5431:           }
    5432:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
    5433:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
    5434:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

    5436:             for (r = 0; r < numIndices; r++) {
    5437:               for (c = 0; c < nCols; c++) {
    5438:                 for (k = 0; k < dof; k++) {
    5439:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
    5440:                 }
    5441:               }
    5442:             }
    5443:           }
    5444:           else {
    5445:             /* copy this column as is */
    5446:             for (r = 0; r < numIndices; r++) {
    5447:               for (c = 0; c < dof; c++) {
    5448:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
    5449:               }
    5450:             }
    5451:           }
    5452:           oldOff += dof;
    5453:         }
    5454:       }
    5455:     }
    5456:     else {
    5457:       PetscInt oldOff = 0;
    5458:       for (p = 0; p < numPoints; p++) {
    5459:         PetscInt cStart = newPointOffsets[0][p];
    5460:         PetscInt b      = points[2 * p];
    5461:         PetscInt c, r, k;
    5462:         PetscInt dof;

    5464:         PetscSectionGetDof(section,b,&dof);
    5465:         if (!dof) {
    5466:           continue;
    5467:         }
    5468:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
    5469:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
    5470:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

    5472:           for (r = 0; r < numIndices; r++) {
    5473:             for (c = 0; c < nCols; c++) {
    5474:               for (k = 0; k < dof; k++) {
    5475:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
    5476:               }
    5477:             }
    5478:           }
    5479:         }
    5480:         else {
    5481:           /* copy this column as is */
    5482:           for (r = 0; r < numIndices; r++) {
    5483:             for (c = 0; c < dof; c++) {
    5484:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
    5485:             }
    5486:           }
    5487:         }
    5488:         oldOff += dof;
    5489:       }
    5490:     }

    5492:     if (multiplyLeft) {
    5493:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
    5494:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
    5495:       /* multiply constraints transpose on the left */
    5496:       if (numFields) {
    5497:         for (f = 0; f < numFields; f++) {
    5498:           PetscInt oldOff = offsets[f];

    5500:           for (p = 0; p < numPoints; p++) {
    5501:             PetscInt rStart = newPointOffsets[f][p];
    5502:             PetscInt b      = points[2 * p];
    5503:             PetscInt c, r, k;
    5504:             PetscInt dof;

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

    5511:               for (r = 0; r < nRows; r++) {
    5512:                 for (c = 0; c < newNumIndices; c++) {
    5513:                   for (k = 0; k < dof; k++) {
    5514:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
    5515:                   }
    5516:                 }
    5517:               }
    5518:             }
    5519:             else {
    5520:               /* copy this row as is */
    5521:               for (r = 0; r < dof; r++) {
    5522:                 for (c = 0; c < newNumIndices; c++) {
    5523:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
    5524:                 }
    5525:               }
    5526:             }
    5527:             oldOff += dof;
    5528:           }
    5529:         }
    5530:       }
    5531:       else {
    5532:         PetscInt oldOff = 0;

    5534:         for (p = 0; p < numPoints; p++) {
    5535:           PetscInt rStart = newPointOffsets[0][p];
    5536:           PetscInt b      = points[2 * p];
    5537:           PetscInt c, r, k;
    5538:           PetscInt dof;

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

    5545:             for (r = 0; r < nRows; r++) {
    5546:               for (c = 0; c < newNumIndices; c++) {
    5547:                 for (k = 0; k < dof; k++) {
    5548:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
    5549:                 }
    5550:               }
    5551:             }
    5552:           }
    5553:           else {
    5554:             /* copy this row as is */
    5555:             for (r = 0; r < dof; r++) {
    5556:               for (c = 0; c < newNumIndices; c++) {
    5557:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
    5558:               }
    5559:             }
    5560:           }
    5561:           oldOff += dof;
    5562:         }
    5563:       }

    5565:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
    5566:     }
    5567:     else {
    5568:       newValues = tmpValues;
    5569:     }
    5570:   }

    5572:   /* clean up */
    5573:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
    5574:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

    5576:   if (numFields) {
    5577:     for (f = 0; f < numFields; f++) {
    5578:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
    5579:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
    5580:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
    5581:     }
    5582:   }
    5583:   else {
    5584:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
    5585:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
    5586:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
    5587:   }
    5588:   ISRestoreIndices(aIS,&anchors);

    5590:   /* output */
    5591:   if (outPoints) {
    5592:     *outPoints = newPoints;
    5593:   }
    5594:   else {
    5595:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
    5596:   }
    5597:   if (outValues) {
    5598:     *outValues = newValues;
    5599:   }
    5600:   for (f = 0; f <= numFields; f++) {
    5601:     offsets[f] = newOffsets[f];
    5602:   }
    5603:   return(0);
    5604: }

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

    5609:   Not collective

    5611:   Input Parameters:
    5612: + dm - The DM
    5613: . section - The section describing the layout in v, or NULL to use the default section
    5614: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
    5615: - point - The mesh point

    5617:   Output parameters:
    5618: + numIndices - The number of indices
    5619: . indices - The indices
    5620: - outOffsets - Field offset if not NULL

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

    5624:   Level: advanced

    5626: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
    5627: @*/
    5628: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
    5629: {
    5630:   PetscSection    clSection;
    5631:   IS              clPoints;
    5632:   const PetscInt *clp;
    5633:   const PetscInt  **perms[32] = {NULL};
    5634:   PetscInt       *points = NULL, *pointsNew;
    5635:   PetscInt        numPoints, numPointsNew;
    5636:   PetscInt        offsets[32];
    5637:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
    5638:   PetscErrorCode  ierr;

    5646:   PetscSectionGetNumFields(section, &Nf);
    5647:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
    5648:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
    5649:   /* Get points in closure */
    5650:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    5651:   /* Get number of indices and indices per field */
    5652:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
    5653:     PetscInt dof, fdof;

    5655:     PetscSectionGetDof(section, points[p], &dof);
    5656:     for (f = 0; f < Nf; ++f) {
    5657:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
    5658:       offsets[f+1] += fdof;
    5659:     }
    5660:     Nind += dof;
    5661:   }
    5662:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
    5663:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
    5664:   if (!Nf) offsets[1] = Nind;
    5665:   /* Get dual space symmetries */
    5666:   for (f = 0; f < PetscMax(1,Nf); f++) {
    5667:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
    5668:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
    5669:   }
    5670:   /* Correct for hanging node constraints */
    5671:   {
    5672:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
    5673:     if (numPointsNew) {
    5674:       for (f = 0; f < PetscMax(1,Nf); f++) {
    5675:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
    5676:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
    5677:       }
    5678:       for (f = 0; f < PetscMax(1,Nf); f++) {
    5679:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
    5680:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
    5681:       }
    5682:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    5683:       numPoints = numPointsNew;
    5684:       Nind      = NindNew;
    5685:       points    = pointsNew;
    5686:     }
    5687:   }
    5688:   /* Calculate indices */
    5689:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
    5690:   if (Nf) {
    5691:     if (outOffsets) {
    5692:       PetscInt f;

    5694:       for (f = 0; f <= Nf; f++) {
    5695:         outOffsets[f] = offsets[f];
    5696:       }
    5697:     }
    5698:     for (p = 0; p < numPoints; p++) {
    5699:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
    5700:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
    5701:     }
    5702:   } else {
    5703:     for (p = 0, off = 0; p < numPoints; p++) {
    5704:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

    5706:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
    5707:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
    5708:     }
    5709:   }
    5710:   /* Cleanup points */
    5711:   for (f = 0; f < PetscMax(1,Nf); f++) {
    5712:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
    5713:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
    5714:   }
    5715:   if (numPointsNew) {
    5716:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
    5717:   } else {
    5718:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    5719:   }
    5720:   if (numIndices) *numIndices = Nind;
    5721:   return(0);
    5722: }

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

    5727:   Not collective

    5729:   Input Parameters:
    5730: + dm - The DM
    5731: . section - The section describing the layout in v, or NULL to use the default section
    5732: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
    5733: . point - The mesh point
    5734: . numIndices - The number of indices
    5735: . indices - The indices
    5736: - outOffsets - Field offset if not NULL

    5738:   Level: advanced

    5740: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
    5741: @*/
    5742: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
    5743: {

    5749:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
    5750:   return(0);
    5751: }

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

    5756:   Not collective

    5758:   Input Parameters:
    5759: + dm - The DM
    5760: . section - The section describing the layout in v, or NULL to use the default section
    5761: . globalSection - The section describing the layout in v, or NULL to use the default global section
    5762: . A - The matrix
    5763: . point - The point in the DM
    5764: . values - The array of values
    5765: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

    5770:   Level: intermediate

    5772: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
    5773: @*/
    5774: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
    5775: {
    5776:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
    5777:   PetscSection        clSection;
    5778:   IS                  clPoints;
    5779:   PetscInt           *points = NULL, *newPoints;
    5780:   const PetscInt     *clp;
    5781:   PetscInt           *indices;
    5782:   PetscInt            offsets[32];
    5783:   const PetscInt    **perms[32] = {NULL};
    5784:   const PetscScalar **flips[32] = {NULL};
    5785:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
    5786:   PetscScalar        *valCopy = NULL;
    5787:   PetscScalar        *newValues;
    5788:   PetscErrorCode      ierr;

    5792:   if (!section) {DMGetSection(dm, &section);}
    5794:   if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
    5797:   PetscSectionGetNumFields(section, &numFields);
    5798:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
    5799:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
    5800:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    5801:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
    5802:     PetscInt fdof;

    5804:     PetscSectionGetDof(section, points[p], &dof);
    5805:     for (f = 0; f < numFields; ++f) {
    5806:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
    5807:       offsets[f+1] += fdof;
    5808:     }
    5809:     numIndices += dof;
    5810:   }
    5811:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

    5825:         if (!numFields) {
    5826:           PetscSectionGetDof(section,point,&fdof);
    5827:         } else {
    5828:           PetscSectionGetFieldDof(section,point,f,&fdof);
    5829:         }
    5830:         if (flip) {
    5831:           PetscInt i, j, k;

    5833:           if (!valCopy) {
    5834:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
    5835:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
    5836:             values = valCopy;
    5837:           }
    5838:           for (i = 0; i < fdof; i++) {
    5839:             PetscScalar fval = flip[i];

    5841:             for (k = 0; k < numIndices; k++) {
    5842:               valCopy[numIndices * (foffset + i) + k] *= fval;
    5843:               valCopy[numIndices * k + (foffset + i)] *= fval;
    5844:             }
    5845:           }
    5846:         }
    5847:         foffset += fdof;
    5848:       }
    5849:     }
    5850:   }
    5851:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
    5852:   if (newNumPoints) {
    5853:     if (valCopy) {
    5854:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
    5855:     }
    5856:     for (f = 0; f < PetscMax(1,numFields); f++) {
    5857:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
    5858:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
    5859:     }
    5860:     for (f = 0; f < PetscMax(1,numFields); f++) {
    5861:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
    5862:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
    5863:     }
    5864:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    5865:     numPoints  = newNumPoints;
    5866:     numIndices = newNumIndices;
    5867:     points     = newPoints;
    5868:     values     = newValues;
    5869:   }
    5870:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
    5871:   if (numFields) {
    5872:     PetscBool useFieldOffsets;

    5874:     PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
    5875:     if (useFieldOffsets) {
    5876:       for (p = 0; p < numPoints; p++) {
    5877:         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, indices);
    5878:       }
    5879:     } else {
    5880:       for (p = 0; p < numPoints; p++) {
    5881:         PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
    5882:         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
    5883:       }
    5884:     }
    5885:   } else {
    5886:     for (p = 0, off = 0; p < numPoints; p++) {
    5887:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
    5888:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
    5889:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
    5890:     }
    5891:   }
    5892:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
    5893:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
    5894:   if (mesh->printFEM > 1) {
    5895:     PetscInt i;
    5896:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
    5897:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
    5898:     PetscPrintf(PETSC_COMM_SELF, "\n");
    5899:   }
    5900:   if (ierr) {
    5901:     PetscMPIInt    rank;
    5902:     PetscErrorCode ierr2;

    5904:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
    5905:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
    5906:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
    5907:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
    5908:
    5909:   }
    5910:   for (f = 0; f < PetscMax(1,numFields); f++) {
    5911:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
    5912:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
    5913:   }
    5914:   if (newNumPoints) {
    5915:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
    5916:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
    5917:   }
    5918:   else {
    5919:     if (valCopy) {
    5920:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
    5921:     }
    5922:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
    5923:   }
    5924:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
    5925:   return(0);
    5926: }

    5928: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
    5929: {
    5930:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
    5931:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
    5932:   PetscInt       *cpoints = NULL;
    5933:   PetscInt       *findices, *cindices;
    5934:   PetscInt        foffsets[32], coffsets[32];
    5935:   CellRefiner     cellRefiner;
    5936:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
    5937:   PetscErrorCode  ierr;

    5942:   if (!fsection) {DMGetSection(dmf, &fsection);}
    5944:   if (!csection) {DMGetSection(dmc, &csection);}
    5946:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
    5948:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
    5951:   PetscSectionGetNumFields(fsection, &numFields);
    5952:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
    5953:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
    5954:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
    5955:   /* Column indices */
    5956:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
    5957:   maxFPoints = numCPoints;
    5958:   /* Compress out points not in the section */
    5959:   /*   TODO: Squeeze out points with 0 dof as well */
    5960:   PetscSectionGetChart(csection, &pStart, &pEnd);
    5961:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
    5962:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
    5963:       cpoints[q*2]   = cpoints[p];
    5964:       cpoints[q*2+1] = cpoints[p+1];
    5965:       ++q;
    5966:     }
    5967:   }
    5968:   numCPoints = q;
    5969:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
    5970:     PetscInt fdof;

    5972:     PetscSectionGetDof(csection, cpoints[p], &dof);
    5973:     if (!dof) continue;
    5974:     for (f = 0; f < numFields; ++f) {
    5975:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
    5976:       coffsets[f+1] += fdof;
    5977:     }
    5978:     numCIndices += dof;
    5979:   }
    5980:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
    5981:   /* Row indices */
    5982:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
    5983:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
    5984:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
    5985:   for (r = 0, q = 0; r < numSubcells; ++r) {
    5986:     /* TODO Map from coarse to fine cells */
    5987:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
    5988:     /* Compress out points not in the section */
    5989:     PetscSectionGetChart(fsection, &pStart, &pEnd);
    5990:     for (p = 0; p < numFPoints*2; p += 2) {
    5991:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
    5992:         PetscSectionGetDof(fsection, fpoints[p], &dof);
    5993:         if (!dof) continue;
    5994:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
    5995:         if (s < q) continue;
    5996:         ftotpoints[q*2]   = fpoints[p];
    5997:         ftotpoints[q*2+1] = fpoints[p+1];
    5998:         ++q;
    5999:       }
    6000:     }
    6001:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
    6002:   }
    6003:   numFPoints = q;
    6004:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
    6005:     PetscInt fdof;

    6007:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
    6008:     if (!dof) continue;
    6009:     for (f = 0; f < numFields; ++f) {
    6010:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
    6011:       foffsets[f+1] += fdof;
    6012:     }
    6013:     numFIndices += dof;
    6014:   }
    6015:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

    6017:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
    6018:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
    6019:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
    6020:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
    6021:   if (numFields) {
    6022:     const PetscInt **permsF[32] = {NULL};
    6023:     const PetscInt **permsC[32] = {NULL};

    6025:     for (f = 0; f < numFields; f++) {
    6026:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
    6027:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
    6028:     }
    6029:     for (p = 0; p < numFPoints; p++) {
    6030:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
    6031:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
    6032:     }
    6033:     for (p = 0; p < numCPoints; p++) {
    6034:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
    6035:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
    6036:     }
    6037:     for (f = 0; f < numFields; f++) {
    6038:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
    6039:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
    6040:     }
    6041:   } else {
    6042:     const PetscInt **permsF = NULL;
    6043:     const PetscInt **permsC = NULL;

    6045:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
    6046:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
    6047:     for (p = 0, off = 0; p < numFPoints; p++) {
    6048:       const PetscInt *perm = permsF ? permsF[p] : NULL;

    6050:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
    6051:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
    6052:     }
    6053:     for (p = 0, off = 0; p < numCPoints; p++) {
    6054:       const PetscInt *perm = permsC ? permsC[p] : NULL;

    6056:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
    6057:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
    6058:     }
    6059:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
    6060:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
    6061:   }
    6062:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
    6063:   /* TODO: flips */
    6064:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
    6065:   if (ierr) {
    6066:     PetscMPIInt    rank;
    6067:     PetscErrorCode ierr2;

    6069:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
    6070:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
    6071:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
    6072:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
    6073:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
    6074:
    6075:   }
    6076:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
    6077:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
    6078:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
    6079:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
    6080:   return(0);
    6081: }

    6083: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
    6084: {
    6085:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
    6086:   PetscInt      *cpoints = NULL;
    6087:   PetscInt       foffsets[32], coffsets[32];
    6088:   CellRefiner    cellRefiner;
    6089:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

    6095:   if (!fsection) {DMGetSection(dmf, &fsection);}
    6097:   if (!csection) {DMGetSection(dmc, &csection);}
    6099:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
    6101:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
    6103:   PetscSectionGetNumFields(fsection, &numFields);
    6104:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
    6105:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
    6106:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
    6107:   /* Column indices */
    6108:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
    6109:   maxFPoints = numCPoints;
    6110:   /* Compress out points not in the section */
    6111:   /*   TODO: Squeeze out points with 0 dof as well */
    6112:   PetscSectionGetChart(csection, &pStart, &pEnd);
    6113:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
    6114:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
    6115:       cpoints[q*2]   = cpoints[p];
    6116:       cpoints[q*2+1] = cpoints[p+1];
    6117:       ++q;
    6118:     }
    6119:   }
    6120:   numCPoints = q;
    6121:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
    6122:     PetscInt fdof;

    6124:     PetscSectionGetDof(csection, cpoints[p], &dof);
    6125:     if (!dof) continue;
    6126:     for (f = 0; f < numFields; ++f) {
    6127:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
    6128:       coffsets[f+1] += fdof;
    6129:     }
    6130:     numCIndices += dof;
    6131:   }
    6132:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
    6133:   /* Row indices */
    6134:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
    6135:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
    6136:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
    6137:   for (r = 0, q = 0; r < numSubcells; ++r) {
    6138:     /* TODO Map from coarse to fine cells */
    6139:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
    6140:     /* Compress out points not in the section */
    6141:     PetscSectionGetChart(fsection, &pStart, &pEnd);
    6142:     for (p = 0; p < numFPoints*2; p += 2) {
    6143:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
    6144:         PetscSectionGetDof(fsection, fpoints[p], &dof);
    6145:         if (!dof) continue;
    6146:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
    6147:         if (s < q) continue;
    6148:         ftotpoints[q*2]   = fpoints[p];
    6149:         ftotpoints[q*2+1] = fpoints[p+1];
    6150:         ++q;
    6151:       }
    6152:     }
    6153:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
    6154:   }
    6155:   numFPoints = q;
    6156:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
    6157:     PetscInt fdof;

    6159:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
    6160:     if (!dof) continue;
    6161:     for (f = 0; f < numFields; ++f) {
    6162:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
    6163:       foffsets[f+1] += fdof;
    6164:     }
    6165:     numFIndices += dof;
    6166:   }
    6167:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

    6175:     for (f = 0; f < numFields; f++) {
    6176:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
    6177:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
    6178:     }
    6179:     for (p = 0; p < numFPoints; p++) {
    6180:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
    6181:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
    6182:     }
    6183:     for (p = 0; p < numCPoints; p++) {
    6184:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
    6185:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
    6186:     }
    6187:     for (f = 0; f < numFields; f++) {
    6188:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
    6189:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
    6190:     }
    6191:   } else {
    6192:     const PetscInt **permsF = NULL;
    6193:     const PetscInt **permsC = NULL;

    6195:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
    6196:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
    6197:     for (p = 0, off = 0; p < numFPoints; p++) {
    6198:       const PetscInt *perm = permsF ? permsF[p] : NULL;

    6200:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
    6201:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
    6202:     }
    6203:     for (p = 0, off = 0; p < numCPoints; p++) {
    6204:       const PetscInt *perm = permsC ? permsC[p] : NULL;

    6206:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
    6207:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
    6208:     }
    6209:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
    6210:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
    6211:   }
    6212:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
    6213:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
    6214:   return(0);
    6215: }

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

    6220:   Input Parameter:
    6221: . dm - The DMPlex object

    6223:   Output Parameters:
    6224: + cMax - The first hybrid cell
    6225: . fMax - The first hybrid face
    6226: . eMax - The first hybrid edge
    6227: - vMax - The first hybrid vertex

    6229:   Level: developer

    6231: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
    6232: @*/
    6233: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
    6234: {
    6235:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    6236:   PetscInt       dim;

    6241:   DMGetDimension(dm, &dim);
    6242:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
    6243:   if (cMax) *cMax = mesh->hybridPointMax[dim];
    6244:   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
    6245:   if (eMax) *eMax = mesh->hybridPointMax[1];
    6246:   if (vMax) *vMax = mesh->hybridPointMax[0];
    6247:   return(0);
    6248: }

    6250: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
    6251: {
    6252:   IS             is, his;
    6253:   PetscInt       first = 0, stride;
    6254:   PetscBool      isStride;

    6258:   DMLabelGetStratumIS(depthLabel, d, &is);
    6259:   PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
    6260:   if (isStride) {
    6261:     ISStrideGetInfo(is, &first, &stride);
    6262:   }
    6263:   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
    6264:   ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
    6265:   DMLabelSetStratumIS(dimLabel, d, his);
    6266:   ISDestroy(&his);
    6267:   ISDestroy(&is);
    6268:   return(0);
    6269: }

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

    6274:   Input Parameters:
    6275: . dm   - The DMPlex object
    6276: . cMax - The first hybrid cell
    6277: . fMax - The first hybrid face
    6278: . eMax - The first hybrid edge
    6279: - vMax - The first hybrid vertex

    6281:   Level: developer

    6283: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
    6284: @*/
    6285: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
    6286: {
    6287:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    6288:   PetscInt       dim;

    6293:   DMGetDimension(dm, &dim);
    6294:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
    6295:   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
    6296:   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
    6297:   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
    6298:   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
    6299:   return(0);
    6300: }

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

    6305:   Input Parameter:
    6306: . dm   - The DMPlex object

    6308:   Output Parameter:
    6309: . cellHeight - The height of a cell

    6311:   Level: developer

    6313: .seealso DMPlexSetVTKCellHeight()
    6314: @*/
    6315: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
    6316: {
    6317:   DM_Plex *mesh = (DM_Plex*) dm->data;

    6322:   *cellHeight = mesh->vtkCellHeight;
    6323:   return(0);
    6324: }

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

    6329:   Input Parameters:
    6330: + dm   - The DMPlex object
    6331: - cellHeight - The height of a cell

    6333:   Level: developer

    6335: .seealso DMPlexGetVTKCellHeight()
    6336: @*/
    6337: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
    6338: {
    6339:   DM_Plex *mesh = (DM_Plex*) dm->data;

    6343:   mesh->vtkCellHeight = cellHeight;
    6344:   return(0);
    6345: }

    6347: /* We can easily have a form that takes an IS instead */
    6348: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
    6349: {
    6350:   PetscSection   section, globalSection;
    6351:   PetscInt      *numbers, p;

    6355:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
    6356:   PetscSectionSetChart(section, pStart, pEnd);
    6357:   for (p = pStart; p < pEnd; ++p) {
    6358:     PetscSectionSetDof(section, p, 1);
    6359:   }
    6360:   PetscSectionSetUp(section);
    6361:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
    6362:   PetscMalloc1(pEnd - pStart, &numbers);
    6363:   for (p = pStart; p < pEnd; ++p) {
    6364:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
    6365:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
    6366:     else                       numbers[p-pStart] += shift;
    6367:   }
    6368:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
    6369:   if (globalSize) {
    6370:     PetscLayout layout;
    6371:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
    6372:     PetscLayoutGetSize(layout, globalSize);
    6373:     PetscLayoutDestroy(&layout);
    6374:   }
    6375:   PetscSectionDestroy(&section);
    6376:   PetscSectionDestroy(&globalSection);
    6377:   return(0);
    6378: }

    6380: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
    6381: {
    6382:   PetscInt       cellHeight, cStart, cEnd, cMax;

    6386:   DMPlexGetVTKCellHeight(dm, &cellHeight);
    6387:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
    6388:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
    6389:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
    6390:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
    6391:   return(0);
    6392: }

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

    6397:   Input Parameter:
    6398: . dm   - The DMPlex object

    6400:   Output Parameter:
    6401: . globalCellNumbers - Global cell numbers for all cells on this process

    6403:   Level: developer

    6405: .seealso DMPlexGetVertexNumbering()
    6406: @*/
    6407: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
    6408: {
    6409:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    6414:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
    6415:   *globalCellNumbers = mesh->globalCellNumbers;
    6416:   return(0);
    6417: }

    6419: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
    6420: {
    6421:   PetscInt       vStart, vEnd, vMax;

    6426:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    6427:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
    6428:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
    6429:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
    6430:   return(0);
    6431: }

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

    6436:   Input Parameter:
    6437: . dm   - The DMPlex object

    6439:   Output Parameter:
    6440: . globalVertexNumbers - Global vertex numbers for all vertices on this process

    6442:   Level: developer

    6444: .seealso DMPlexGetCellNumbering()
    6445: @*/
    6446: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
    6447: {
    6448:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    6453:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
    6454:   *globalVertexNumbers = mesh->globalVertexNumbers;
    6455:   return(0);
    6456: }

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

    6461:   Input Parameter:
    6462: . dm   - The DMPlex object

    6464:   Output Parameter:
    6465: . globalPointNumbers - Global numbers for all points on this process

    6467:   Level: developer

    6469: .seealso DMPlexGetCellNumbering()
    6470: @*/
    6471: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
    6472: {
    6473:   IS             nums[4];
    6474:   PetscInt       depths[4];
    6475:   PetscInt       depth, d, shift = 0;

    6480:   DMPlexGetDepth(dm, &depth);
    6481:   /* For unstratified meshes use dim instead of depth */
    6482:   if (depth < 0) {DMGetDimension(dm, &depth);}
    6483:   depths[0] = depth; depths[1] = 0;
    6484:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
    6485:   for (d = 0; d <= depth; ++d) {
    6486:     PetscInt pStart, pEnd, gsize;

    6488:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
    6489:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
    6490:     shift += gsize;
    6491:   }
    6492:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
    6493:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
    6494:   return(0);
    6495: }

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

    6501:   Input Parameter:
    6502: . dm - The DMPlex object

    6504:   Output Parameter:
    6505: . ranks - The rank field

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

    6510:   Level: intermediate

    6512: .seealso: DMView()
    6513: @*/
    6514: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
    6515: {
    6516:   DM             rdm;
    6517:   PetscDS        prob;
    6518:   PetscFE        fe;
    6519:   PetscScalar   *r;
    6520:   PetscMPIInt    rank;
    6521:   PetscInt       dim, cStart, cEnd, c;

    6525:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
    6526:   DMClone(dm, &rdm);
    6527:   DMGetDimension(rdm, &dim);
    6528:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, NULL, -1, &fe);
    6529:   PetscObjectSetName((PetscObject) fe, "rank");
    6530:   DMGetDS(rdm, &prob);
    6531:   PetscDSSetDiscretization(prob, 0, (PetscObject) fe);
    6532:   PetscFEDestroy(&fe);
    6533:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
    6534:   DMCreateGlobalVector(rdm, ranks);
    6535:   PetscObjectSetName((PetscObject) *ranks, "partition");
    6536:   VecGetArray(*ranks, &r);
    6537:   for (c = cStart; c < cEnd; ++c) {
    6538:     PetscScalar *lr;

    6540:     DMPlexPointGlobalRef(rdm, c, r, &lr);
    6541:     *lr = rank;
    6542:   }
    6543:   VecRestoreArray(*ranks, &r);
    6544:   DMDestroy(&rdm);
    6545:   return(0);
    6546: }

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

    6551:   Input Parameter:
    6552: . dm - The DMPlex object

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

    6556:   Level: developer

    6558: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
    6559: @*/
    6560: PetscErrorCode DMPlexCheckSymmetry(DM dm)
    6561: {
    6562:   PetscSection    coneSection, supportSection;
    6563:   const PetscInt *cone, *support;
    6564:   PetscInt        coneSize, c, supportSize, s;
    6565:   PetscInt        pStart, pEnd, p, csize, ssize;
    6566:   PetscErrorCode  ierr;

    6570:   DMPlexGetConeSection(dm, &coneSection);
    6571:   DMPlexGetSupportSection(dm, &supportSection);
    6572:   /* Check that point p is found in the support of its cone points, and vice versa */
    6573:   DMPlexGetChart(dm, &pStart, &pEnd);
    6574:   for (p = pStart; p < pEnd; ++p) {
    6575:     DMPlexGetConeSize(dm, p, &coneSize);
    6576:     DMPlexGetCone(dm, p, &cone);
    6577:     for (c = 0; c < coneSize; ++c) {
    6578:       PetscBool dup = PETSC_FALSE;
    6579:       PetscInt  d;
    6580:       for (d = c-1; d >= 0; --d) {
    6581:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
    6582:       }
    6583:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
    6584:       DMPlexGetSupport(dm, cone[c], &support);
    6585:       for (s = 0; s < supportSize; ++s) {
    6586:         if (support[s] == p) break;
    6587:       }
    6588:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
    6589:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
    6590:         for (s = 0; s < coneSize; ++s) {
    6591:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
    6592:         }
    6593:         PetscPrintf(PETSC_COMM_SELF, "\n");
    6594:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
    6595:         for (s = 0; s < supportSize; ++s) {
    6596:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
    6597:         }
    6598:         PetscPrintf(PETSC_COMM_SELF, "\n");
    6599:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
    6600:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
    6601:       }
    6602:     }
    6603:     DMPlexGetSupportSize(dm, p, &supportSize);
    6604:     DMPlexGetSupport(dm, p, &support);
    6605:     for (s = 0; s < supportSize; ++s) {
    6606:       DMPlexGetConeSize(dm, support[s], &coneSize);
    6607:       DMPlexGetCone(dm, support[s], &cone);
    6608:       for (c = 0; c < coneSize; ++c) {
    6609:         if (cone[c] == p) break;
    6610:       }
    6611:       if (c >= coneSize) {
    6612:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
    6613:         for (c = 0; c < supportSize; ++c) {
    6614:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
    6615:         }
    6616:         PetscPrintf(PETSC_COMM_SELF, "\n");
    6617:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
    6618:         for (c = 0; c < coneSize; ++c) {
    6619:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
    6620:         }
    6621:         PetscPrintf(PETSC_COMM_SELF, "\n");
    6622:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
    6623:       }
    6624:     }
    6625:   }
    6626:   PetscSectionGetStorageSize(coneSection, &csize);
    6627:   PetscSectionGetStorageSize(supportSection, &ssize);
    6628:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
    6629:   return(0);
    6630: }

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

    6635:   Input Parameters:
    6636: + dm - The DMPlex object
    6637: . isSimplex - Are the cells simplices or tensor products
    6638: - cellHeight - Normally 0

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

    6642:   Level: developer

    6644: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
    6645: @*/
    6646: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
    6647: {
    6648:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

    6653:   DMGetDimension(dm, &dim);
    6654:   switch (dim) {
    6655:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
    6656:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
    6657:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
    6658:   default:
    6659:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
    6660:   }
    6661:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    6662:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
    6663:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
    6664:   cMax = cMax >= 0 ? cMax : cEnd;
    6665:   for (c = cStart; c < cMax; ++c) {
    6666:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

    6668:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    6669:     for (cl = 0; cl < closureSize*2; cl += 2) {
    6670:       const PetscInt p = closure[cl];
    6671:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
    6672:     }
    6673:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    6674:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
    6675:   }
    6676:   for (c = cMax; c < cEnd; ++c) {
    6677:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

    6679:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    6680:     for (cl = 0; cl < closureSize*2; cl += 2) {
    6681:       const PetscInt p = closure[cl];
    6682:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
    6683:     }
    6684:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    6685:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
    6686:   }
    6687:   return(0);
    6688: }

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

    6693:   Input Parameters:
    6694: + dm - The DMPlex object
    6695: . isSimplex - Are the cells simplices or tensor products
    6696: - cellHeight - Normally 0

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

    6700:   Level: developer

    6702: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
    6703: @*/
    6704: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
    6705: {
    6706:   PetscInt       pMax[4];
    6707:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

    6712:   DMGetDimension(dm, &dim);
    6713:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    6714:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
    6715:   for (h = cellHeight; h < dim; ++h) {
    6716:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
    6717:     for (c = cStart; c < cEnd; ++c) {
    6718:       const PetscInt *cone, *ornt, *faces;
    6719:       PetscInt        numFaces, faceSize, coneSize,f;
    6720:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

    6722:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
    6723:       DMPlexGetConeSize(dm, c, &coneSize);
    6724:       DMPlexGetCone(dm, c, &cone);
    6725:       DMPlexGetConeOrientation(dm, c, &ornt);
    6726:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    6727:       for (cl = 0; cl < closureSize*2; cl += 2) {
    6728:         const PetscInt p = closure[cl];
    6729:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
    6730:       }
    6731:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
    6732:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
    6733:       for (f = 0; f < numFaces; ++f) {
    6734:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

    6736:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
    6737:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
    6738:           const PetscInt p = fclosure[cl];
    6739:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
    6740:         }
    6741:         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);
    6742:         for (v = 0; v < fnumCorners; ++v) {
    6743:           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]);
    6744:         }
    6745:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
    6746:       }
    6747:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
    6748:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    6749:     }
    6750:   }
    6751:   return(0);
    6752: }

    6754: /* Pointwise interpolation
    6755:      Just code FEM for now
    6756:      u^f = I u^c
    6757:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
    6758:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
    6759:      I_{ij} = psi^f_i phi^c_j
    6760: */
    6761: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
    6762: {
    6763:   PetscSection   gsc, gsf;
    6764:   PetscInt       m, n;
    6765:   void          *ctx;
    6766:   DM             cdm;
    6767:   PetscBool      regular, ismatis;

    6771:   DMGetGlobalSection(dmFine, &gsf);
    6772:   PetscSectionGetConstrainedStorageSize(gsf, &m);
    6773:   DMGetGlobalSection(dmCoarse, &gsc);
    6774:   PetscSectionGetConstrainedStorageSize(gsc, &n);

    6776:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
    6777:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
    6778:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
    6779:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
    6780:   DMGetApplicationContext(dmFine, &ctx);

    6782:   DMGetCoarseDM(dmFine, &cdm);
    6783:   DMPlexGetRegularRefinement(dmFine, &regular);
    6784:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
    6785:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
    6786:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
    6787:   /* Use naive scaling */
    6788:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
    6789:   return(0);
    6790: }

    6792: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
    6793: {
    6795:   VecScatter     ctx;

    6798:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
    6799:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
    6800:   VecScatterDestroy(&ctx);
    6801:   return(0);
    6802: }

    6804: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
    6805: {
    6806:   PetscSection   gsc, gsf;
    6807:   PetscInt       m, n;
    6808:   void          *ctx;
    6809:   DM             cdm;
    6810:   PetscBool      regular;

    6814:   DMGetGlobalSection(dmFine, &gsf);
    6815:   PetscSectionGetConstrainedStorageSize(gsf, &m);
    6816:   DMGetGlobalSection(dmCoarse, &gsc);
    6817:   PetscSectionGetConstrainedStorageSize(gsc, &n);

    6819:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
    6820:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
    6821:   MatSetType(*mass, dmCoarse->mattype);
    6822:   DMGetApplicationContext(dmFine, &ctx);

    6824:   DMGetCoarseDM(dmFine, &cdm);
    6825:   DMPlexGetRegularRefinement(dmFine, &regular);
    6826:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
    6827:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
    6828:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
    6829:   return(0);
    6830: }

    6832: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
    6833: {
    6834:   PetscSection   section;
    6835:   IS            *bcPoints, *bcComps;
    6836:   PetscBool     *isFE;
    6837:   PetscInt      *bcFields, *numComp, *numDof;
    6838:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
    6839:   PetscInt       cStart, cEnd, cEndInterior;

    6843:   DMGetNumFields(dm, &numFields);
    6844:   /* FE and FV boundary conditions are handled slightly differently */
    6845:   PetscMalloc1(numFields, &isFE);
    6846:   for (f = 0; f < numFields; ++f) {
    6847:     PetscObject  obj;
    6848:     PetscClassId id;

    6850:     DMGetField(dm, f, &obj);
    6851:     PetscObjectGetClassId(obj, &id);
    6852:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
    6853:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
    6854:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
    6855:   }
    6856:   /* Allocate boundary point storage for FEM boundaries */
    6857:   DMPlexGetDepth(dm, &depth);
    6858:   DMGetDimension(dm, &dim);
    6859:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    6860:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
    6861:   PetscDSGetNumBoundary(dm->prob, &numBd);
    6862:   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)");
    6863:   for (bd = 0; bd < numBd; ++bd) {
    6864:     PetscInt                field;
    6865:     DMBoundaryConditionType type;
    6866:     const char             *labelName;
    6867:     DMLabel                 label;

    6869:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
    6870:     DMGetLabel(dm,labelName,&label);
    6871:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
    6872:   }
    6873:   /* Add ghost cell boundaries for FVM */
    6874:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
    6875:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
    6876:   /* Constrain ghost cells for FV */
    6877:   for (f = 0; f < numFields; ++f) {
    6878:     PetscInt *newidx, c;

    6880:     if (isFE[f] || cEndInterior < 0) continue;
    6881:     PetscMalloc1(cEnd-cEndInterior,&newidx);
    6882:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
    6883:     bcFields[bc] = f;
    6884:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
    6885:   }
    6886:   /* Handle FEM Dirichlet boundaries */
    6887:   for (bd = 0; bd < numBd; ++bd) {
    6888:     const char             *bdLabel;
    6889:     DMLabel                 label;
    6890:     const PetscInt         *comps;
    6891:     const PetscInt         *values;
    6892:     PetscInt                bd2, field, numComps, numValues;
    6893:     DMBoundaryConditionType type;
    6894:     PetscBool               duplicate = PETSC_FALSE;

    6896:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
    6897:     DMGetLabel(dm, bdLabel, &label);
    6898:     if (!isFE[field] || !label) continue;
    6899:     /* Only want to modify label once */
    6900:     for (bd2 = 0; bd2 < bd; ++bd2) {
    6901:       const char *bdname;
    6902:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    6903:       PetscStrcmp(bdname, bdLabel, &duplicate);
    6904:       if (duplicate) break;
    6905:     }
    6906:     if (!duplicate && (isFE[field])) {
    6907:       /* don't complete cells, which are just present to give orientation to the boundary */
    6908:       DMPlexLabelComplete(dm, label);
    6909:     }
    6910:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
    6911:     if (type & DM_BC_ESSENTIAL) {
    6912:       PetscInt       *newidx;
    6913:       PetscInt        n, newn = 0, p, v;

    6915:       bcFields[bc] = field;
    6916:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
    6917:       for (v = 0; v < numValues; ++v) {
    6918:         IS              tmp;
    6919:         const PetscInt *idx;

    6921:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
    6922:         if (!tmp) continue;
    6923:         ISGetLocalSize(tmp, &n);
    6924:         ISGetIndices(tmp, &idx);
    6925:         if (isFE[field]) {
    6926:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
    6927:         } else {
    6928:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
    6929:         }
    6930:         ISRestoreIndices(tmp, &idx);
    6931:         ISDestroy(&tmp);
    6932:       }
    6933:       PetscMalloc1(newn,&newidx);
    6934:       newn = 0;
    6935:       for (v = 0; v < numValues; ++v) {
    6936:         IS              tmp;
    6937:         const PetscInt *idx;

    6939:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
    6940:         if (!tmp) continue;
    6941:         ISGetLocalSize(tmp, &n);
    6942:         ISGetIndices(tmp, &idx);
    6943:         if (isFE[field]) {
    6944:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
    6945:         } else {
    6946:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
    6947:         }
    6948:         ISRestoreIndices(tmp, &idx);
    6949:         ISDestroy(&tmp);
    6950:       }
    6951:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
    6952:     }
    6953:   }
    6954:   /* Handle discretization */
    6955:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
    6956:   for (f = 0; f < numFields; ++f) {
    6957:     PetscObject obj;

    6959:     DMGetField(dm, f, &obj);
    6960:     if (isFE[f]) {
    6961:       PetscFE         fe = (PetscFE) obj;
    6962:       const PetscInt *numFieldDof;
    6963:       PetscInt        d;

    6965:       PetscFEGetNumComponents(fe, &numComp[f]);
    6966:       PetscFEGetNumDof(fe, &numFieldDof);
    6967:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
    6968:     } else {
    6969:       PetscFV fv = (PetscFV) obj;

    6971:       PetscFVGetNumComponents(fv, &numComp[f]);
    6972:       numDof[f*(dim+1)+dim] = numComp[f];
    6973:     }
    6974:   }
    6975:   for (f = 0; f < numFields; ++f) {
    6976:     PetscInt d;
    6977:     for (d = 1; d < dim; ++d) {
    6978:       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.");
    6979:     }
    6980:   }
    6981:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
    6982:   for (f = 0; f < numFields; ++f) {
    6983:     PetscFE     fe;
    6984:     const char *name;

    6986:     DMGetField(dm, f, (PetscObject *) &fe);
    6987:     PetscObjectGetName((PetscObject) fe, &name);
    6988:     PetscSectionSetFieldName(section, f, name);
    6989:   }
    6990:   DMSetSection(dm, section);
    6991:   PetscSectionDestroy(&section);
    6992:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
    6993:   PetscFree3(bcFields,bcPoints,bcComps);
    6994:   PetscFree2(numComp,numDof);
    6995:   PetscFree(isFE);
    6996:   return(0);
    6997: }

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

    7002:   Input Parameter:
    7003: . dm - The DMPlex object

    7005:   Output Parameter:
    7006: . regular - The flag

    7008:   Level: intermediate

    7010: .seealso: DMPlexSetRegularRefinement()
    7011: @*/
    7012: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
    7013: {
    7017:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
    7018:   return(0);
    7019: }

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

    7024:   Input Parameters:
    7025: + dm - The DMPlex object
    7026: - regular - The flag

    7028:   Level: intermediate

    7030: .seealso: DMPlexGetRegularRefinement()
    7031: @*/
    7032: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
    7033: {
    7036:   ((DM_Plex *) dm->data)->regularRefinement = regular;
    7037:   return(0);
    7038: }

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

    7045:   not collective

    7047:   Input Parameters:
    7048: . dm - The DMPlex object

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

    7055:   Level: intermediate

    7057: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
    7058: @*/
    7059: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
    7060: {
    7061:   DM_Plex *plex = (DM_Plex *)dm->data;

    7066:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
    7067:   if (anchorSection) *anchorSection = plex->anchorSection;
    7068:   if (anchorIS) *anchorIS = plex->anchorIS;
    7069:   return(0);
    7070: }

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

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

    7080:   collective on dm

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

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

    7089:   Level: intermediate

    7091: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
    7092: @*/
    7093: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
    7094: {
    7095:   DM_Plex        *plex = (DM_Plex *)dm->data;
    7096:   PetscMPIInt    result;

    7101:   if (anchorSection) {
    7103:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
    7104:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
    7105:   }
    7106:   if (anchorIS) {
    7108:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
    7109:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
    7110:   }

    7112:   PetscObjectReference((PetscObject)anchorSection);
    7113:   PetscSectionDestroy(&plex->anchorSection);
    7114:   plex->anchorSection = anchorSection;

    7116:   PetscObjectReference((PetscObject)anchorIS);
    7117:   ISDestroy(&plex->anchorIS);
    7118:   plex->anchorIS = anchorIS;

    7120: #if defined(PETSC_USE_DEBUG)
    7121:   if (anchorIS && anchorSection) {
    7122:     PetscInt size, a, pStart, pEnd;
    7123:     const PetscInt *anchors;

    7125:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
    7126:     ISGetLocalSize(anchorIS,&size);
    7127:     ISGetIndices(anchorIS,&anchors);
    7128:     for (a = 0; a < size; a++) {
    7129:       PetscInt p;

    7131:       p = anchors[a];
    7132:       if (p >= pStart && p < pEnd) {
    7133:         PetscInt dof;

    7135:         PetscSectionGetDof(anchorSection,p,&dof);
    7136:         if (dof) {
    7137:           PetscErrorCode ierr2;

    7139:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
    7140:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
    7141:         }
    7142:       }
    7143:     }
    7144:     ISRestoreIndices(anchorIS,&anchors);
    7145:   }
    7146: #endif
    7147:   /* reset the generic constraints */
    7148:   DMSetDefaultConstraints(dm,NULL,NULL);
    7149:   return(0);
    7150: }

    7152: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
    7153: {
    7154:   PetscSection anchorSection;
    7155:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

    7160:   DMPlexGetAnchors(dm,&anchorSection,NULL);
    7161:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
    7162:   PetscSectionGetNumFields(section,&numFields);
    7163:   if (numFields) {
    7164:     PetscInt f;
    7165:     PetscSectionSetNumFields(*cSec,numFields);

    7167:     for (f = 0; f < numFields; f++) {
    7168:       PetscInt numComp;

    7170:       PetscSectionGetFieldComponents(section,f,&numComp);
    7171:       PetscSectionSetFieldComponents(*cSec,f,numComp);
    7172:     }
    7173:   }
    7174:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
    7175:   PetscSectionGetChart(section,&sStart,&sEnd);
    7176:   pStart = PetscMax(pStart,sStart);
    7177:   pEnd   = PetscMin(pEnd,sEnd);
    7178:   pEnd   = PetscMax(pStart,pEnd);
    7179:   PetscSectionSetChart(*cSec,pStart,pEnd);
    7180:   for (p = pStart; p < pEnd; p++) {
    7181:     PetscSectionGetDof(anchorSection,p,&dof);
    7182:     if (dof) {
    7183:       PetscSectionGetDof(section,p,&dof);
    7184:       PetscSectionSetDof(*cSec,p,dof);
    7185:       for (f = 0; f < numFields; f++) {
    7186:         PetscSectionGetFieldDof(section,p,f,&dof);
    7187:         PetscSectionSetFieldDof(*cSec,p,f,dof);
    7188:       }
    7189:     }
    7190:   }
    7191:   PetscSectionSetUp(*cSec);
    7192:   return(0);
    7193: }

    7195: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
    7196: {
    7197:   PetscSection aSec;
    7198:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
    7199:   const PetscInt *anchors;
    7200:   PetscInt numFields, f;
    7201:   IS aIS;

    7206:   PetscSectionGetStorageSize(cSec, &m);
    7207:   PetscSectionGetStorageSize(section, &n);
    7208:   MatCreate(PETSC_COMM_SELF,cMat);
    7209:   MatSetSizes(*cMat,m,n,m,n);
    7210:   MatSetType(*cMat,MATSEQAIJ);
    7211:   DMPlexGetAnchors(dm,&aSec,&aIS);
    7212:   ISGetIndices(aIS,&anchors);
    7213:   /* cSec will be a subset of aSec and section */
    7214:   PetscSectionGetChart(cSec,&pStart,&pEnd);
    7215:   PetscMalloc1(m+1,&i);
    7216:   i[0] = 0;
    7217:   PetscSectionGetNumFields(section,&numFields);
    7218:   for (p = pStart; p < pEnd; p++) {
    7219:     PetscInt rDof, rOff, r;

    7221:     PetscSectionGetDof(aSec,p,&rDof);
    7222:     if (!rDof) continue;
    7223:     PetscSectionGetOffset(aSec,p,&rOff);
    7224:     if (numFields) {
    7225:       for (f = 0; f < numFields; f++) {
    7226:         annz = 0;
    7227:         for (r = 0; r < rDof; r++) {
    7228:           a = anchors[rOff + r];
    7229:           PetscSectionGetFieldDof(section,a,f,&aDof);
    7230:           annz += aDof;
    7231:         }
    7232:         PetscSectionGetFieldDof(cSec,p,f,&dof);
    7233:         PetscSectionGetFieldOffset(cSec,p,f,&off);
    7234:         for (q = 0; q < dof; q++) {
    7235:           i[off + q + 1] = i[off + q] + annz;
    7236:         }
    7237:       }
    7238:     }
    7239:     else {
    7240:       annz = 0;
    7241:       for (q = 0; q < dof; q++) {
    7242:         a = anchors[off + q];
    7243:         PetscSectionGetDof(section,a,&aDof);
    7244:         annz += aDof;
    7245:       }
    7246:       PetscSectionGetDof(cSec,p,&dof);
    7247:       PetscSectionGetOffset(cSec,p,&off);
    7248:       for (q = 0; q < dof; q++) {
    7249:         i[off + q + 1] = i[off + q] + annz;
    7250:       }
    7251:     }
    7252:   }
    7253:   nnz = i[m];
    7254:   PetscMalloc1(nnz,&j);
    7255:   offset = 0;
    7256:   for (p = pStart; p < pEnd; p++) {
    7257:     if (numFields) {
    7258:       for (f = 0; f < numFields; f++) {
    7259:         PetscSectionGetFieldDof(cSec,p,f,&dof);
    7260:         for (q = 0; q < dof; q++) {
    7261:           PetscInt rDof, rOff, r;
    7262:           PetscSectionGetDof(aSec,p,&rDof);
    7263:           PetscSectionGetOffset(aSec,p,&rOff);
    7264:           for (r = 0; r < rDof; r++) {
    7265:             PetscInt s;

    7267:             a = anchors[rOff + r];
    7268:             PetscSectionGetFieldDof(section,a,f,&aDof);
    7269:             PetscSectionGetFieldOffset(section,a,f,&aOff);
    7270:             for (s = 0; s < aDof; s++) {
    7271:               j[offset++] = aOff + s;
    7272:             }
    7273:           }
    7274:         }
    7275:       }
    7276:     }
    7277:     else {
    7278:       PetscSectionGetDof(cSec,p,&dof);
    7279:       for (q = 0; q < dof; q++) {
    7280:         PetscInt rDof, rOff, r;
    7281:         PetscSectionGetDof(aSec,p,&rDof);
    7282:         PetscSectionGetOffset(aSec,p,&rOff);
    7283:         for (r = 0; r < rDof; r++) {
    7284:           PetscInt s;

    7286:           a = anchors[rOff + r];
    7287:           PetscSectionGetDof(section,a,&aDof);
    7288:           PetscSectionGetOffset(section,a,&aOff);
    7289:           for (s = 0; s < aDof; s++) {
    7290:             j[offset++] = aOff + s;
    7291:           }
    7292:         }
    7293:       }
    7294:     }
    7295:   }
    7296:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
    7297:   PetscFree(i);
    7298:   PetscFree(j);
    7299:   ISRestoreIndices(aIS,&anchors);
    7300:   return(0);
    7301: }

    7303: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
    7304: {
    7305:   DM_Plex        *plex = (DM_Plex *)dm->data;
    7306:   PetscSection   anchorSection, section, cSec;
    7307:   Mat            cMat;

    7312:   DMPlexGetAnchors(dm,&anchorSection,NULL);
    7313:   if (anchorSection) {
    7314:     PetscDS  ds;
    7315:     PetscInt nf;

    7317:     DMGetSection(dm,&section);
    7318:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
    7319:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
    7320:     DMGetDS(dm,&ds);
    7321:     PetscDSGetNumFields(ds,&nf);
    7322:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
    7323:     DMSetDefaultConstraints(dm,cSec,cMat);
    7324:     PetscSectionDestroy(&cSec);
    7325:     MatDestroy(&cMat);
    7326:   }
    7327:   return(0);
    7328: }

    7330: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
    7331: {
    7332:   PetscDS        prob;
    7333:   IS             subis;
    7334:   PetscSection   section, subsection;

    7338:   DMGetDefaultSection(dm, &section);
    7339:   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
    7340:   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
    7341:   /* Create subdomain */
    7342:   DMPlexFilter(dm, label, value, subdm);
    7343:   /* Create submodel */
    7344:   DMPlexCreateSubpointIS(*subdm, &subis);
    7345:   PetscSectionCreateSubmeshSection(section, subis, &subsection);
    7346:   ISDestroy(&subis);
    7347:   DMSetDefaultSection(*subdm, subsection);
    7348:   PetscSectionDestroy(&subsection);
    7349:   DMGetDS(dm, &prob);
    7350:   DMSetDS(*subdm, prob);
    7351:   /* Create map from submodel to global model */
    7352:   if (is) {
    7353:     PetscSection    sectionGlobal, subsectionGlobal;
    7354:     IS              spIS;
    7355:     const PetscInt *spmap;
    7356:     PetscInt       *subIndices;
    7357:     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
    7358:     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];

    7360:     DMPlexCreateSubpointIS(*subdm, &spIS);
    7361:     ISGetIndices(spIS, &spmap);
    7362:     PetscSectionGetNumFields(section, &Nf);
    7363:     DMGetDefaultGlobalSection(dm, &sectionGlobal);
    7364:     DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);
    7365:     PetscSectionGetChart(subsection, &pStart, &pEnd);
    7366:     for (p = pStart; p < pEnd; ++p) {
    7367:       PetscInt gdof, pSubSize  = 0;

    7369:       PetscSectionGetDof(sectionGlobal, p, &gdof);
    7370:       if (gdof > 0) {
    7371:         for (f = 0; f < Nf; ++f) {
    7372:           PetscInt fdof, fcdof;

    7374:           PetscSectionGetFieldDof(subsection, p, f, &fdof);
    7375:           PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
    7376:           pSubSize += fdof-fcdof;
    7377:         }
    7378:         subSize += pSubSize;
    7379:         if (pSubSize) {
    7380:           if (bs < 0) {
    7381:             bs = pSubSize;
    7382:           } else if (bs != pSubSize) {
    7383:             /* Layout does not admit a pointwise block size */
    7384:             bs = 1;
    7385:           }
    7386:         }
    7387:       }
    7388:     }
    7389:     /* Must have same blocksize on all procs (some might have no points) */
    7390:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
    7391:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
    7392:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
    7393:     else                            {bs = bsMinMax[0];}
    7394:     PetscMalloc1(subSize, &subIndices);
    7395:     for (p = pStart; p < pEnd; ++p) {
    7396:       PetscInt gdof, goff;

    7398:       PetscSectionGetDof(subsectionGlobal, p, &gdof);
    7399:       if (gdof > 0) {
    7400:         const PetscInt point = spmap[p];

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

    7406:           /* Can get rid of this loop by storing field information in the global section */
    7407:           for (f2 = 0; f2 < f; ++f2) {
    7408:             PetscSectionGetFieldDof(section, p, f2, &fdof);
    7409:             PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
    7410:             poff += fdof-fcdof;
    7411:           }
    7412:           PetscSectionGetFieldDof(section, p, f, &fdof);
    7413:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
    7414:           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
    7415:             subIndices[subOff] = goff+poff+fc;
    7416:           }
    7417:         }
    7418:       }
    7419:     }
    7420:     ISRestoreIndices(spIS, &spmap);
    7421:     ISDestroy(&spIS);
    7422:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
    7423:     if (bs > 1) {
    7424:       /* We need to check that the block size does not come from non-contiguous fields */
    7425:       PetscInt i, j, set = 1;
    7426:       for (i = 0; i < subSize; i += bs) {
    7427:         for (j = 0; j < bs; ++j) {
    7428:           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
    7429:         }
    7430:       }
    7431:       if (set) {ISSetBlockSize(*is, bs);}
    7432:     }
    7433:     /* Attach nullspace */
    7434:     for (f = 0; f < Nf; ++f) {
    7435:       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
    7436:       if ((*subdm)->nullspaceConstructors[f]) break;
    7437:     }
    7438:     if (f < Nf) {
    7439:       MatNullSpace nullSpace;

    7441:       (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
    7442:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
    7443:       MatNullSpaceDestroy(&nullSpace);
    7444:     }
    7445:   }
    7446:   return(0);
    7447: }