Date: 2015-10-02T22:14:14+00:00

Actual source code: plex.c
petsc-3.6.2 2015-10-02
Report Typos and Errors

      1: #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
      2: #include <petsc/private/isimpl.h>
      3: #include <petscsf.h>
      4: #include <petscds.h>

      6: /* Logging support */
      7: PetscLogEvent DMPLEX_Interpolate, PETSCPARTITIONER_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;

      9: PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
     10: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
     11: PETSC_EXTERN PetscErrorCode VecLoad_Default(Vec, PetscViewer);

     15: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
     16: {
     17:   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior, vdof = 0, cdof = 0;

     21:   *ft  = PETSC_VTK_POINT_FIELD;
     22:   DMGetDimension(dm, &dim);
     23:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
     24:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
     25:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
     26:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
     27:   PetscSectionGetChart(section, &pStart, &pEnd);
     28:   if (field >= 0) {
     29:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vdof);}
     30:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &cdof);}
     31:   } else {
     32:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vdof);}
     33:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &cdof);}
     34:   }
     35:   if (vdof) {
     36:     *sStart = vStart;
     37:     *sEnd   = vEnd;
     38:     if (vdof == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
     39:     else             *ft = PETSC_VTK_POINT_FIELD;
     40:   } else if (cdof) {
     41:     *sStart = cStart;
     42:     *sEnd   = cEnd;
     43:     if (cdof == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
     44:     else             *ft = PETSC_VTK_CELL_FIELD;
     45:   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
     46:   return(0);
     47: }

     51: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
     52: {
     53:   DM             dm;
     54:   PetscBool      isvtk, ishdf5, isseq;

     58:   VecGetDM(v, &dm);
     59:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
     60:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
     61:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
     62:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
     63:   if (isvtk || ishdf5) {
     64:     PetscInt  numFields;
     65:     PetscBool fem = PETSC_FALSE;

     67:     DMGetNumFields(dm, &numFields);
     68:     if (numFields) {
     69:       PetscObject fe;

     71:       DMGetField(dm, 0, &fe);
     72:       if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE;
     73:     }
     74:     if (fem) {DMPlexInsertBoundaryValues(dm, v, 0.0, NULL, NULL, NULL);}
     75:   }
     76:   if (isvtk) {
     77:     PetscSection            section;
     78:     PetscViewerVTKFieldType ft;
     79:     PetscInt                pStart, pEnd;

     81:     DMGetDefaultSection(dm, &section);
     82:     DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
     83:     PetscObjectReference((PetscObject) dm); /* viewer drops reference */
     84:     PetscObjectReference((PetscObject) v);  /* viewer drops reference */
     85:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
     86:   } else if (ishdf5) {
     87: #if defined(PETSC_HAVE_HDF5)
     88:     VecView_Plex_Local_HDF5(v, viewer);
     89: #else
     90:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
     91: #endif
     92:   } else {
     93:     if (isseq) {VecView_Seq(v, viewer);}
     94:     else       {VecView_MPI(v, viewer);}
     95:   }
     96:   return(0);
     97: }

    101: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
    102: {
    103:   DM             dm;
    104:   PetscBool      isvtk, ishdf5, isseq;

    108:   VecGetDM(v, &dm);
    109:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
    110:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
    111:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
    112:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
    113:   if (isvtk) {
    114:     Vec         locv;
    115:     const char *name;

    117:     DMGetLocalVector(dm, &locv);
    118:     PetscObjectGetName((PetscObject) v, &name);
    119:     PetscObjectSetName((PetscObject) locv, name);
    120:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
    121:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
    122:     VecView_Plex_Local(locv, viewer);
    123:     DMRestoreLocalVector(dm, &locv);
    124:   } else if (ishdf5) {
    125: #if defined(PETSC_HAVE_HDF5)
    126:     VecView_Plex_HDF5(v, viewer);
    127: #else
    128:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
    129: #endif
    130:   } else {
    131:     if (isseq) {VecView_Seq(v, viewer);}
    132:     else       {VecView_MPI(v, viewer);}
    133:   }
    134:   return(0);
    135: }

    139: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
    140: {
    141:   DM             dm;
    142:   PetscBool      ishdf5;

    146:   VecGetDM(v, &dm);
    147:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
    148:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
    149:   if (ishdf5) {
    150:     DM          dmBC;
    151:     Vec         gv;
    152:     const char *name;

    154:     DMGetOutputDM(dm, &dmBC);
    155:     DMGetGlobalVector(dmBC, &gv);
    156:     PetscObjectGetName((PetscObject) v, &name);
    157:     PetscObjectSetName((PetscObject) gv, name);
    158:     VecLoad_Default(gv, viewer);
    159:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
    160:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
    161:     DMRestoreGlobalVector(dmBC, &gv);
    162:   } else {
    163:     VecLoad_Default(v, viewer);
    164:   }
    165:   return(0);
    166: }

    170: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
    171: {
    172:   DM             dm;
    173:   PetscBool      ishdf5;

    177:   VecGetDM(v, &dm);
    178:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
    179:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
    180:   if (ishdf5) {
    181: #if defined(PETSC_HAVE_HDF5)
    182:     VecLoad_Plex_HDF5(v, viewer);
    183: #else
    184:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
    185: #endif
    186:   } else {
    187:     VecLoad_Default(v, viewer);
    188:   }
    189:   return(0);
    190: }

    194: PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
    195: {
    196:   PetscSection       coordSection;
    197:   Vec                coordinates;
    198:   DMLabel            depthLabel;
    199:   const char        *name[4];
    200:   const PetscScalar *a;
    201:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
    202:   PetscErrorCode     ierr;

    205:   DMGetDimension(dm, &dim);
    206:   DMGetCoordinatesLocal(dm, &coordinates);
    207:   DMGetCoordinateSection(dm, &coordSection);
    208:   DMPlexGetDepthLabel(dm, &depthLabel);
    209:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    210:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
    211:   VecGetArrayRead(coordinates, &a);
    212:   name[0]     = "vertex";
    213:   name[1]     = "edge";
    214:   name[dim-1] = "face";
    215:   name[dim]   = "cell";
    216:   for (c = cStart; c < cEnd; ++c) {
    217:     PetscInt *closure = NULL;
    218:     PetscInt  closureSize, cl;

    220:     PetscViewerASCIIPrintf(viewer, "Geometry for cell %d:\n", c);
    221:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    222:     PetscViewerASCIIPushTab(viewer);
    223:     for (cl = 0; cl < closureSize*2; cl += 2) {
    224:       PetscInt point = closure[cl], depth, dof, off, d, p;

    226:       if ((point < pStart) || (point >= pEnd)) continue;
    227:       PetscSectionGetDof(coordSection, point, &dof);
    228:       if (!dof) continue;
    229:       DMLabelGetValue(depthLabel, point, &depth);
    230:       PetscSectionGetOffset(coordSection, point, &off);
    231:       PetscViewerASCIIPrintf(viewer, "%s %d coords:", name[depth], point);
    232:       for (p = 0; p < dof/dim; ++p) {
    233:         PetscViewerASCIIPrintf(viewer, " (");
    234:         for (d = 0; d < dim; ++d) {
    235:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
    236:           PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
    237:         }
    238:         PetscViewerASCIIPrintf(viewer, ")");
    239:       }
    240:       PetscViewerASCIIPrintf(viewer, "\n");
    241:     }
    242:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    243:     PetscViewerASCIIPopTab(viewer);
    244:   }
    245:   VecRestoreArrayRead(coordinates, &a);
    246:   return(0);
    247: }

    251: PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
    252: {
    253:   DM_Plex          *mesh = (DM_Plex*) dm->data;
    254:   DM                cdm;
    255:   DMLabel           markers;
    256:   PetscSection      coordSection;
    257:   Vec               coordinates;
    258:   PetscViewerFormat format;
    259:   PetscErrorCode    ierr;

    262:   DMGetCoordinateDM(dm, &cdm);
    263:   DMGetDefaultSection(cdm, &coordSection);
    264:   DMGetCoordinatesLocal(dm, &coordinates);
    265:   PetscViewerGetFormat(viewer, &format);
    266:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
    267:     const char *name;
    268:     PetscInt    maxConeSize, maxSupportSize;
    269:     PetscInt    pStart, pEnd, p;
    270:     PetscMPIInt rank, size;

    272:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
    273:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
    274:     PetscObjectGetName((PetscObject) dm, &name);
    275:     DMPlexGetChart(dm, &pStart, &pEnd);
    276:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
    277:     PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);
    278:     PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);
    279:     PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);
    280:     PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
    281:     PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
    282:     for (p = pStart; p < pEnd; ++p) {
    283:       PetscInt dof, off, s;

    285:       PetscSectionGetDof(mesh->supportSection, p, &dof);
    286:       PetscSectionGetOffset(mesh->supportSection, p, &off);
    287:       for (s = off; s < off+dof; ++s) {
    288:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
    289:       }
    290:     }
    291:     PetscViewerFlush(viewer);
    292:     PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
    293:     for (p = pStart; p < pEnd; ++p) {
    294:       PetscInt dof, off, c;

    296:       PetscSectionGetDof(mesh->coneSection, p, &dof);
    297:       PetscSectionGetOffset(mesh->coneSection, p, &off);
    298:       for (c = off; c < off+dof; ++c) {
    299:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
    300:       }
    301:     }
    302:     PetscViewerFlush(viewer);
    303:     PetscSectionGetChart(coordSection, &pStart, NULL);
    304:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
    305:     DMPlexGetLabel(dm, "marker", &markers);
    306:     DMLabelView(markers,viewer);
    307:     if (size > 1) {
    308:       PetscSF sf;

    310:       DMGetPointSF(dm, &sf);
    311:       PetscSFView(sf, viewer);
    312:     }
    313:     PetscViewerFlush(viewer);
    314:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
    315:     const char  *name, *color;
    316:     const char  *defcolors[3]  = {"gray", "orange", "green"};
    317:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
    318:     PetscReal    scale         = 2.0;
    319:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
    320:     double       tcoords[3];
    321:     PetscScalar *coords;
    322:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
    323:     PetscMPIInt  rank, size;
    324:     char         **names, **colors, **lcolors;

    326:     DMGetDimension(dm, &dim);
    327:     DMPlexGetDepth(dm, &depth);
    328:     DMPlexGetNumLabels(dm, &numLabels);
    329:     numLabels  = PetscMax(numLabels, 10);
    330:     numColors  = 10;
    331:     numLColors = 10;
    332:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
    333:     PetscOptionsGetReal(((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
    334:     PetscOptionsGetBool(((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
    335:     PetscOptionsGetStringArray(((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
    336:     if (!useLabels) numLabels = 0;
    337:     PetscOptionsGetStringArray(((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
    338:     if (!useColors) {
    339:       numColors = 3;
    340:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
    341:     }
    342:     PetscOptionsGetStringArray(((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
    343:     if (!useColors) {
    344:       numLColors = 4;
    345:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
    346:     }
    347:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
    348:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
    349:     PetscObjectGetName((PetscObject) dm, &name);
    350:     PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);
    351:     PetscViewerASCIIPrintf(viewer, "\
    352: \\documentclass[tikz]{standalone}\n\n\
    353: \\usepackage{pgflibraryshapes}\n\
    354: \\usetikzlibrary{backgrounds}\n\
    355: \\usetikzlibrary{arrows}\n\
    356: \\begin{document}\n");
    357:     if (size > 1) {
    358:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
    359:       for (p = 0; p < size; ++p) {
    360:         if (p > 0 && p == size-1) {
    361:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
    362:         } else if (p > 0) {
    363:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
    364:         }
    365:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
    366:       }
    367:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
    368:     }
    369:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);
    370:     /* Plot vertices */
    371:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    372:     VecGetArray(coordinates, &coords);
    373:     for (v = vStart; v < vEnd; ++v) {
    374:       PetscInt  off, dof, d;
    375:       PetscBool isLabeled = PETSC_FALSE;

    377:       PetscSectionGetDof(coordSection, v, &dof);
    378:       PetscSectionGetOffset(coordSection, v, &off);
    379:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
    380:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
    381:       for (d = 0; d < dof; ++d) {
    382:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
    383:         tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
    384:       }
    385:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
    386:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
    387:       for (d = 0; d < dof; ++d) {
    388:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
    389:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
    390:       }
    391:       color = colors[rank%numColors];
    392:       for (l = 0; l < numLabels; ++l) {
    393:         PetscInt val;
    394:         DMPlexGetLabelValue(dm, names[l], v, &val);
    395:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
    396:       }
    397:       if (useNumbers) {
    398:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
    399:       } else {
    400:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
    401:       }
    402:     }
    403:     VecRestoreArray(coordinates, &coords);
    404:     PetscViewerFlush(viewer);
    405:     /* Plot edges */
    406:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
    407:     if (dim < 3 && useNumbers) {
    408:       VecGetArray(coordinates, &coords);
    409:       PetscViewerASCIIPrintf(viewer, "\\path\n");
    410:       for (e = eStart; e < eEnd; ++e) {
    411:         const PetscInt *cone;
    412:         PetscInt        coneSize, offA, offB, dof, d;

    414:         DMPlexGetConeSize(dm, e, &coneSize);
    415:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
    416:         DMPlexGetCone(dm, e, &cone);
    417:         PetscSectionGetDof(coordSection, cone[0], &dof);
    418:         PetscSectionGetOffset(coordSection, cone[0], &offA);
    419:         PetscSectionGetOffset(coordSection, cone[1], &offB);
    420:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
    421:         for (d = 0; d < dof; ++d) {
    422:           tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
    423:           tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
    424:         }
    425:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
    426:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
    427:         for (d = 0; d < dof; ++d) {
    428:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
    429:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
    430:         }
    431:         color = colors[rank%numColors];
    432:         for (l = 0; l < numLabels; ++l) {
    433:           PetscInt val;
    434:           DMPlexGetLabelValue(dm, names[l], v, &val);
    435:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
    436:         }
    437:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
    438:       }
    439:       VecRestoreArray(coordinates, &coords);
    440:       PetscViewerFlush(viewer);
    441:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
    442:     }
    443:     /* Plot cells */
    444:     if (dim == 3 || !useNumbers) {
    445:       for (e = eStart; e < eEnd; ++e) {
    446:         const PetscInt *cone;

    448:         color = colors[rank%numColors];
    449:         for (l = 0; l < numLabels; ++l) {
    450:           PetscInt val;
    451:           DMPlexGetLabelValue(dm, names[l], e, &val);
    452:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
    453:         }
    454:         DMPlexGetCone(dm, e, &cone);
    455:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
    456:       }
    457:     } else {
    458:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    459:       for (c = cStart; c < cEnd; ++c) {
    460:         PetscInt *closure = NULL;
    461:         PetscInt  closureSize, firstPoint = -1;

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

    468:           if ((point < vStart) || (point >= vEnd)) continue;
    469:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
    470:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
    471:           if (firstPoint < 0) firstPoint = point;
    472:         }
    473:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
    474:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
    475:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    476:       }
    477:     }
    478:     PetscViewerFlush(viewer);
    479:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
    480:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
    481:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
    482:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
    483:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
    484:     PetscFree3(names, colors, lcolors);
    485:   } else {
    486:     MPI_Comm    comm;
    487:     PetscInt   *sizes, *hybsizes;
    488:     PetscInt    locDepth, depth, dim, d, pMax[4];
    489:     PetscInt    pStart, pEnd, p;
    490:     PetscInt    numLabels, l;
    491:     const char *name;
    492:     PetscMPIInt size;

    494:     PetscObjectGetComm((PetscObject)dm,&comm);
    495:     MPI_Comm_size(comm, &size);
    496:     DMGetDimension(dm, &dim);
    497:     PetscObjectGetName((PetscObject) dm, &name);
    498:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);}
    499:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);}
    500:     DMPlexGetDepth(dm, &locDepth);
    501:     MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
    502:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
    503:     PetscMalloc2(size,&sizes,size,&hybsizes);
    504:     if (depth == 1) {
    505:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
    506:       pEnd = pEnd - pStart;
    507:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
    508:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);
    509:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
    510:       PetscViewerASCIIPrintf(viewer, "\n");
    511:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
    512:       pEnd = pEnd - pStart;
    513:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
    514:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
    515:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
    516:       PetscViewerASCIIPrintf(viewer, "\n");
    517:     } else {
    518:       for (d = 0; d <= dim; d++) {
    519:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
    520:         pEnd    -= pStart;
    521:         pMax[d] -= pStart;
    522:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
    523:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
    524:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
    525:         for (p = 0; p < size; ++p) {
    526:           if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
    527:           else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
    528:         }
    529:         PetscViewerASCIIPrintf(viewer, "\n");
    530:       }
    531:     }
    532:     PetscFree2(sizes,hybsizes);
    533:     DMPlexGetNumLabels(dm, &numLabels);
    534:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
    535:     for (l = 0; l < numLabels; ++l) {
    536:       DMLabel         label;
    537:       const char     *name;
    538:       IS              valueIS;
    539:       const PetscInt *values;
    540:       PetscInt        numValues, v;

    542:       DMPlexGetLabelName(dm, l, &name);
    543:       DMPlexGetLabel(dm, name, &label);
    544:       DMLabelGetNumValues(label, &numValues);
    545:       PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);
    546:       DMLabelGetValueIS(label, &valueIS);
    547:       ISGetIndices(valueIS, &values);
    548:       for (v = 0; v < numValues; ++v) {
    549:         PetscInt size;

    551:         DMLabelGetStratumSize(label, values[v], &size);
    552:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
    553:         PetscViewerASCIIPrintf(viewer, "%d", size);
    554:       }
    555:       PetscViewerASCIIPrintf(viewer, ")\n");
    556:       ISRestoreIndices(valueIS, &values);
    557:       ISDestroy(&valueIS);
    558:     }
    559:   }
    560:   return(0);
    561: }

    565: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
    566: {
    567:   PetscBool      iascii, ishdf5, isvtk;

    573:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
    574:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
    575:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
    576:   if (iascii) {
    577:     DMPlexView_Ascii(dm, viewer);
    578:   } else if (ishdf5) {
    579: #if defined(PETSC_HAVE_HDF5)
    580:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
    581:     DMPlexView_HDF5(dm, viewer);
    582:     PetscViewerPopFormat(viewer);
    583: #else
    584:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
    585: #endif
    586:   }
    587:   else if (isvtk) {
    588:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
    589:   }
    590:   return(0);
    591: }

    595: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
    596: {
    597:   PetscBool      isbinary, ishdf5;

    603:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
    604:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
    605:   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
    606:   else if (ishdf5) {
    607: #if defined(PETSC_HAVE_HDF5)
    608:     DMPlexLoad_HDF5(dm, viewer);
    609: #else
    610:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
    611: #endif
    612:   }
    613:   return(0);
    614: }

    618: static PetscErrorCode BoundaryDestroy(DMBoundary *boundary)
    619: {
    620:   DMBoundary     b, next;

    624:   if (!boundary) return(0);
    625:   b = *boundary;
    626:   *boundary = NULL;
    627:   for (; b; b = next) {
    628:     next = b->next;
    629:     PetscFree(b->comps);
    630:     PetscFree(b->ids);
    631:     PetscFree(b->name);
    632:     PetscFree(b->labelname);
    633:     PetscFree(b);
    634:   }
    635:   return(0);
    636: }

    640: PetscErrorCode DMDestroy_Plex(DM dm)
    641: {
    642:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    643:   PlexLabel      next = mesh->labels;

    647:   if (--mesh->refct > 0) return(0);
    648:   PetscSectionDestroy(&mesh->coneSection);
    649:   PetscFree(mesh->cones);
    650:   PetscFree(mesh->coneOrientations);
    651:   PetscSectionDestroy(&mesh->supportSection);
    652:   PetscFree(mesh->supports);
    653:   PetscFree(mesh->facesTmp);
    654:   PetscFree(mesh->tetgenOpts);
    655:   PetscFree(mesh->triangleOpts);
    656:   PetscPartitionerDestroy(&mesh->partitioner);
    657:   while (next) {
    658:     PlexLabel tmp = next->next;

    660:     DMLabelDestroy(&next->label);
    661:     PetscFree(next);
    662:     next = tmp;
    663:   }
    664:   DMDestroy(&mesh->coarseMesh);
    665:   DMLabelDestroy(&mesh->subpointMap);
    666:   ISDestroy(&mesh->globalVertexNumbers);
    667:   ISDestroy(&mesh->globalCellNumbers);
    668:   BoundaryDestroy(&mesh->boundary);
    669:   PetscSectionDestroy(&mesh->anchorSection);
    670:   ISDestroy(&mesh->anchorIS);
    671:   PetscSectionDestroy(&mesh->parentSection);
    672:   PetscFree(mesh->parents);
    673:   PetscFree(mesh->childIDs);
    674:   PetscSectionDestroy(&mesh->childSection);
    675:   PetscFree(mesh->children);
    676:   DMDestroy(&mesh->referenceTree);
    677:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
    678:   PetscFree(mesh);
    679:   return(0);
    680: }

    684: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
    685: {
    686:   PetscSection   sectionGlobal;
    687:   PetscInt       bs = -1;
    688:   PetscInt       localSize;
    689:   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock;
    691:   MatType        mtype;
    692:   ISLocalToGlobalMapping ltog;

    695:   MatInitializePackage();
    696:   mtype = dm->mattype;
    697:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
    698:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
    699:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
    700:   MatCreate(PetscObjectComm((PetscObject)dm), J);
    701:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
    702:   MatSetType(*J, mtype);
    703:   MatSetFromOptions(*J);
    704:   PetscStrcmp(mtype, MATSHELL, &isShell);
    705:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
    706:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
    707:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
    708:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
    709:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
    710:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
    711:   if (!isShell) {
    712:     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
    713:     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;

    715:     if (bs < 0) {
    716:       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
    717:         PetscInt pStart, pEnd, p, dof, cdof;

    719:         PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
    720:         for (p = pStart; p < pEnd; ++p) {
    721:           PetscSectionGetDof(sectionGlobal, p, &dof);
    722:           PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
    723:           if (dof-cdof) {
    724:             if (bs < 0) {
    725:               bs = dof-cdof;
    726:             } else if (bs != dof-cdof) {
    727:               /* Layout does not admit a pointwise block size */
    728:               bs = 1;
    729:               break;
    730:             }
    731:           }
    732:         }
    733:         /* Must have same blocksize on all procs (some might have no points) */
    734:         bsLocal = bs;
    735:         MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
    736:         bsLocal = bs < 0 ? bsMax : bs;
    737:         MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
    738:         if (bsMin != bsMax) {
    739:           bs = 1;
    740:         } else {
    741:           bs = bsMax;
    742:         }
    743:       } else {
    744:         bs = 1;
    745:       }
    746:     }
    747:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
    748:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
    749:     PetscFree4(dnz, onz, dnzu, onzu);

    751:     /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work */
    752:     DMGetLocalToGlobalMapping(dm,&ltog);
    753:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
    754:   }
    755:   return(0);
    756: }

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

    763:   Not collective

    765:   Input Parameter:
    766: . mesh - The DMPlex

    768:   Output Parameters:
    769: + pStart - The first mesh point
    770: - pEnd   - The upper bound for mesh points

    772:   Level: beginner

    774: .seealso: DMPlexCreate(), DMPlexSetChart()
    775: @*/
    776: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
    777: {
    778:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    783:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
    784:   return(0);
    785: }

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

    792:   Not collective

    794:   Input Parameters:
    795: + mesh - The DMPlex
    796: . pStart - The first mesh point
    797: - pEnd   - The upper bound for mesh points

    799:   Output Parameters:

    801:   Level: beginner

    803: .seealso: DMPlexCreate(), DMPlexGetChart()
    804: @*/
    805: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
    806: {
    807:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    812:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
    813:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
    814:   return(0);
    815: }

    819: /*@
    820:   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG

    822:   Not collective

    824:   Input Parameters:
    825: + mesh - The DMPlex
    826: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

    828:   Output Parameter:
    829: . size - The cone size for point p

    831:   Level: beginner

    833: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
    834: @*/
    835: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
    836: {
    837:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    843:   PetscSectionGetDof(mesh->coneSection, p, size);
    844:   return(0);
    845: }

    849: /*@
    850:   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG

    852:   Not collective

    854:   Input Parameters:
    855: + mesh - The DMPlex
    856: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
    857: - size - The cone size for point p

    859:   Output Parameter:

    861:   Note:
    862:   This should be called after DMPlexSetChart().

    864:   Level: beginner

    866: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
    867: @*/
    868: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
    869: {
    870:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

    877:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
    878:   return(0);
    879: }

    883: /*@
    884:   DMPlexAddConeSize - Add the given number of in-edges to this point in the Sieve DAG

    886:   Not collective

    888:   Input Parameters:
    889: + mesh - The DMPlex
    890: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
    891: - size - The additional cone size for point p

    893:   Output Parameter:

    895:   Note:
    896:   This should be called after DMPlexSetChart().

    898:   Level: beginner

    900: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
    901: @*/
    902: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
    903: {
    904:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    905:   PetscInt       csize;

    910:   PetscSectionAddDof(mesh->coneSection, p, size);
    911:   PetscSectionGetDof(mesh->coneSection, p, &csize);

    913:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
    914:   return(0);
    915: }

    919: /*@C
    920:   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG

    922:   Not collective

    924:   Input Parameters:
    925: + mesh - The DMPlex
    926: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

    931:   Level: beginner

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

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

    939: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
    940: @*/
    941: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
    942: {
    943:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    944:   PetscInt       off;

    950:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    951:   *cone = &mesh->cones[off];
    952:   return(0);
    953: }

    957: /*@
    958:   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG

    960:   Not collective

    962:   Input Parameters:
    963: + mesh - The DMPlex
    964: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
    965: - cone - An array of points which are on the in-edges for point p

    967:   Output Parameter:

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

    972:   Level: beginner

    974: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
    975: @*/
    976: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
    977: {
    978:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    979:   PetscInt       pStart, pEnd;
    980:   PetscInt       dof, off, c;

    985:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
    986:   PetscSectionGetDof(mesh->coneSection, p, &dof);
    988:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    989:   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);
    990:   for (c = 0; c < dof; ++c) {
    991:     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);
    992:     mesh->cones[off+c] = cone[c];
    993:   }
    994:   return(0);
    995: }

    999: /*@C
    1000:   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG

    1002:   Not collective

    1004:   Input Parameters:
    1005: + mesh - The DMPlex
    1006: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

    1014:   Level: beginner

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

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

    1022: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
    1023: @*/
    1024: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
    1025: {
    1026:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1027:   PetscInt       off;

    1032: #if defined(PETSC_USE_DEBUG)
    1033:   {
    1034:     PetscInt dof;
    1035:     PetscSectionGetDof(mesh->coneSection, p, &dof);
    1037:   }
    1038: #endif
    1039:   PetscSectionGetOffset(mesh->coneSection, p, &off);

    1041:   *coneOrientation = &mesh->coneOrientations[off];
    1042:   return(0);
    1043: }

    1047: /*@
    1048:   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG

    1050:   Not collective

    1052:   Input Parameters:
    1053: + mesh - The DMPlex
    1054: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
    1055: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
    1056:                     integer giving the prescription for cone traversal. If it is negative, the cone is
    1057:                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
    1058:                     the index of the cone point on which to start.

    1060:   Output Parameter:

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

    1065:   Level: beginner

    1067: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
    1068: @*/
    1069: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
    1070: {
    1071:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1072:   PetscInt       pStart, pEnd;
    1073:   PetscInt       dof, off, c;

    1078:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
    1079:   PetscSectionGetDof(mesh->coneSection, p, &dof);
    1081:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    1082:   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);
    1083:   for (c = 0; c < dof; ++c) {
    1084:     PetscInt cdof, o = coneOrientation[c];

    1086:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
    1087:     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);
    1088:     mesh->coneOrientations[off+c] = o;
    1089:   }
    1090:   return(0);
    1091: }

    1095: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
    1096: {
    1097:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1098:   PetscInt       pStart, pEnd;
    1099:   PetscInt       dof, off;

    1104:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
    1105:   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);
    1106:   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);
    1107:   PetscSectionGetDof(mesh->coneSection, p, &dof);
    1108:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    1109:   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);
    1110:   mesh->cones[off+conePos] = conePoint;
    1111:   return(0);
    1112: }

    1116: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
    1117: {
    1118:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1119:   PetscInt       pStart, pEnd;
    1120:   PetscInt       dof, off;

    1125:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
    1126:   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);
    1127:   PetscSectionGetDof(mesh->coneSection, p, &dof);
    1128:   PetscSectionGetOffset(mesh->coneSection, p, &off);
    1129:   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);
    1130:   mesh->coneOrientations[off+conePos] = coneOrientation;
    1131:   return(0);
    1132: }

    1136: /*@
    1137:   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG

    1139:   Not collective

    1141:   Input Parameters:
    1142: + mesh - The DMPlex
    1143: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

    1145:   Output Parameter:
    1146: . size - The support size for point p

    1148:   Level: beginner

    1150: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
    1151: @*/
    1152: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
    1153: {
    1154:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    1160:   PetscSectionGetDof(mesh->supportSection, p, size);
    1161:   return(0);
    1162: }

    1166: /*@
    1167:   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG

    1169:   Not collective

    1171:   Input Parameters:
    1172: + mesh - The DMPlex
    1173: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
    1174: - size - The support size for point p

    1176:   Output Parameter:

    1178:   Note:
    1179:   This should be called after DMPlexSetChart().

    1181:   Level: beginner

    1183: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
    1184: @*/
    1185: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
    1186: {
    1187:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

    1194:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
    1195:   return(0);
    1196: }

    1200: /*@C
    1201:   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG

    1203:   Not collective

    1205:   Input Parameters:
    1206: + mesh - The DMPlex
    1207: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

    1212:   Level: beginner

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

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

    1220: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
    1221: @*/
    1222: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
    1223: {
    1224:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1225:   PetscInt       off;

    1231:   PetscSectionGetOffset(mesh->supportSection, p, &off);
    1232:   *support = &mesh->supports[off];
    1233:   return(0);
    1234: }

    1238: /*@
    1239:   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG

    1241:   Not collective

    1243:   Input Parameters:
    1244: + mesh - The DMPlex
    1245: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
    1246: - support - An array of points which are on the in-edges for point p

    1248:   Output Parameter:

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

    1253:   Level: beginner

    1255: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
    1256: @*/
    1257: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
    1258: {
    1259:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1260:   PetscInt       pStart, pEnd;
    1261:   PetscInt       dof, off, c;

    1266:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
    1267:   PetscSectionGetDof(mesh->supportSection, p, &dof);
    1269:   PetscSectionGetOffset(mesh->supportSection, p, &off);
    1270:   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);
    1271:   for (c = 0; c < dof; ++c) {
    1272:     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);
    1273:     mesh->supports[off+c] = support[c];
    1274:   }
    1275:   return(0);
    1276: }

    1280: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
    1281: {
    1282:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1283:   PetscInt       pStart, pEnd;
    1284:   PetscInt       dof, off;

    1289:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
    1290:   PetscSectionGetDof(mesh->supportSection, p, &dof);
    1291:   PetscSectionGetOffset(mesh->supportSection, p, &off);
    1292:   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);
    1293:   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);
    1294:   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);
    1295:   mesh->supports[off+supportPos] = supportPoint;
    1296:   return(0);
    1297: }

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

    1304:   Not collective

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

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

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

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

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

    1325:   Level: beginner

    1327: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
    1328: @*/
    1329: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
    1330: {
    1331:   DM_Plex        *mesh = (DM_Plex*) dm->data;
    1332:   PetscInt       *closure, *fifo;
    1333:   const PetscInt *tmp = NULL, *tmpO = NULL;
    1334:   PetscInt        tmpSize, t;
    1335:   PetscInt        depth       = 0, maxSize;
    1336:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
    1337:   PetscErrorCode  ierr;

    1341:   DMPlexGetDepth(dm, &depth);
    1342:   /* This is only 1-level */
    1343:   if (useCone) {
    1344:     DMPlexGetConeSize(dm, p, &tmpSize);
    1345:     DMPlexGetCone(dm, p, &tmp);
    1346:     DMPlexGetConeOrientation(dm, p, &tmpO);
    1347:   } else {
    1348:     DMPlexGetSupportSize(dm, p, &tmpSize);
    1349:     DMPlexGetSupport(dm, p, &tmp);
    1350:   }
    1351:   if (depth == 1) {
    1352:     if (*points) {
    1353:       closure = *points;
    1354:     } else {
    1355:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
    1356:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
    1357:     }
    1358:     closure[0] = p; closure[1] = 0;
    1359:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
    1360:       closure[closureSize]   = tmp[t];
    1361:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
    1362:     }
    1363:     if (numPoints) *numPoints = closureSize/2;
    1364:     if (points)    *points    = closure;
    1365:     return(0);
    1366:   }
    1367:   {
    1368:     PetscInt c, coneSeries, s,supportSeries;

    1370:     c = mesh->maxConeSize;
    1371:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
    1372:     s = mesh->maxSupportSize;
    1373:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
    1374:     maxSize = 2*PetscMax(coneSeries,supportSeries);
    1375:   }
    1376:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
    1377:   if (*points) {
    1378:     closure = *points;
    1379:   } else {
    1380:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
    1381:   }
    1382:   closure[0] = p; closure[1] = 0;
    1383:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
    1384:     const PetscInt cp = tmp[t];
    1385:     const PetscInt co = tmpO ? tmpO[t] : 0;

    1387:     closure[closureSize]   = cp;
    1388:     closure[closureSize+1] = co;
    1389:     fifo[fifoSize]         = cp;
    1390:     fifo[fifoSize+1]       = co;
    1391:   }
    1392:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
    1393:   while (fifoSize - fifoStart) {
    1394:     const PetscInt q   = fifo[fifoStart];
    1395:     const PetscInt o   = fifo[fifoStart+1];
    1396:     const PetscInt rev = o >= 0 ? 0 : 1;
    1397:     const PetscInt off = rev ? -(o+1) : o;

    1399:     if (useCone) {
    1400:       DMPlexGetConeSize(dm, q, &tmpSize);
    1401:       DMPlexGetCone(dm, q, &tmp);
    1402:       DMPlexGetConeOrientation(dm, q, &tmpO);
    1403:     } else {
    1404:       DMPlexGetSupportSize(dm, q, &tmpSize);
    1405:       DMPlexGetSupport(dm, q, &tmp);
    1406:       tmpO = NULL;
    1407:     }
    1408:     for (t = 0; t < tmpSize; ++t) {
    1409:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
    1410:       const PetscInt cp = tmp[i];
    1411:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
    1412:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
    1413:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
    1414:       PetscInt       co = tmpO ? tmpO[i] : 0;
    1415:       PetscInt       c;

    1417:       if (rev) {
    1418:         PetscInt childSize, coff;
    1419:         DMPlexGetConeSize(dm, cp, &childSize);
    1420:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
    1421:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
    1422:       }
    1423:       /* Check for duplicate */
    1424:       for (c = 0; c < closureSize; c += 2) {
    1425:         if (closure[c] == cp) break;
    1426:       }
    1427:       if (c == closureSize) {
    1428:         closure[closureSize]   = cp;
    1429:         closure[closureSize+1] = co;
    1430:         fifo[fifoSize]         = cp;
    1431:         fifo[fifoSize+1]       = co;
    1432:         closureSize           += 2;
    1433:         fifoSize              += 2;
    1434:       }
    1435:     }
    1436:     fifoStart += 2;
    1437:   }
    1438:   if (numPoints) *numPoints = closureSize/2;
    1439:   if (points)    *points    = closure;
    1440:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
    1441:   return(0);
    1442: }

    1446: /*@C
    1447:   DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG with a specified initial orientation

    1449:   Not collective

    1451:   Input Parameters:
    1452: + mesh - The DMPlex
    1453: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
    1454: . orientation - The orientation of the point
    1455: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
    1456: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

    1471:   Level: beginner

    1473: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
    1474: @*/
    1475: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
    1476: {
    1477:   DM_Plex        *mesh = (DM_Plex*) dm->data;
    1478:   PetscInt       *closure, *fifo;
    1479:   const PetscInt *tmp = NULL, *tmpO = NULL;
    1480:   PetscInt        tmpSize, t;
    1481:   PetscInt        depth       = 0, maxSize;
    1482:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
    1483:   PetscErrorCode  ierr;

    1487:   DMPlexGetDepth(dm, &depth);
    1488:   /* This is only 1-level */
    1489:   if (useCone) {
    1490:     DMPlexGetConeSize(dm, p, &tmpSize);
    1491:     DMPlexGetCone(dm, p, &tmp);
    1492:     DMPlexGetConeOrientation(dm, p, &tmpO);
    1493:   } else {
    1494:     DMPlexGetSupportSize(dm, p, &tmpSize);
    1495:     DMPlexGetSupport(dm, p, &tmp);
    1496:   }
    1497:   if (depth == 1) {
    1498:     if (*points) {
    1499:       closure = *points;
    1500:     } else {
    1501:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
    1502:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
    1503:     }
    1504:     closure[0] = p; closure[1] = ornt;
    1505:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
    1506:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
    1507:       closure[closureSize]   = tmp[i];
    1508:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
    1509:     }
    1510:     if (numPoints) *numPoints = closureSize/2;
    1511:     if (points)    *points    = closure;
    1512:     return(0);
    1513:   }
    1514:   {
    1515:     PetscInt c, coneSeries, s,supportSeries;

    1517:     c = mesh->maxConeSize;
    1518:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
    1519:     s = mesh->maxSupportSize;
    1520:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
    1521:     maxSize = 2*PetscMax(coneSeries,supportSeries);
    1522:   }
    1523:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
    1524:   if (*points) {
    1525:     closure = *points;
    1526:   } else {
    1527:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
    1528:   }
    1529:   closure[0] = p; closure[1] = ornt;
    1530:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
    1531:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
    1532:     const PetscInt cp = tmp[i];
    1533:     PetscInt       co = tmpO ? tmpO[i] : 0;

    1535:     if (ornt < 0) {
    1536:       PetscInt childSize, coff;
    1537:       DMPlexGetConeSize(dm, cp, &childSize);
    1538:       coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
    1539:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
    1540:     }
    1541:     closure[closureSize]   = cp;
    1542:     closure[closureSize+1] = co;
    1543:     fifo[fifoSize]         = cp;
    1544:     fifo[fifoSize+1]       = co;
    1545:   }
    1546:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
    1547:   while (fifoSize - fifoStart) {
    1548:     const PetscInt q   = fifo[fifoStart];
    1549:     const PetscInt o   = fifo[fifoStart+1];
    1550:     const PetscInt rev = o >= 0 ? 0 : 1;
    1551:     const PetscInt off = rev ? -(o+1) : o;

    1553:     if (useCone) {
    1554:       DMPlexGetConeSize(dm, q, &tmpSize);
    1555:       DMPlexGetCone(dm, q, &tmp);
    1556:       DMPlexGetConeOrientation(dm, q, &tmpO);
    1557:     } else {
    1558:       DMPlexGetSupportSize(dm, q, &tmpSize);
    1559:       DMPlexGetSupport(dm, q, &tmp);
    1560:       tmpO = NULL;
    1561:     }
    1562:     for (t = 0; t < tmpSize; ++t) {
    1563:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
    1564:       const PetscInt cp = tmp[i];
    1565:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
    1566:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
    1567:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
    1568:       PetscInt       co = tmpO ? tmpO[i] : 0;
    1569:       PetscInt       c;

    1571:       if (rev) {
    1572:         PetscInt childSize, coff;
    1573:         DMPlexGetConeSize(dm, cp, &childSize);
    1574:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
    1575:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
    1576:       }
    1577:       /* Check for duplicate */
    1578:       for (c = 0; c < closureSize; c += 2) {
    1579:         if (closure[c] == cp) break;
    1580:       }
    1581:       if (c == closureSize) {
    1582:         closure[closureSize]   = cp;
    1583:         closure[closureSize+1] = co;
    1584:         fifo[fifoSize]         = cp;
    1585:         fifo[fifoSize+1]       = co;
    1586:         closureSize           += 2;
    1587:         fifoSize              += 2;
    1588:       }
    1589:     }
    1590:     fifoStart += 2;
    1591:   }
    1592:   if (numPoints) *numPoints = closureSize/2;
    1593:   if (points)    *points    = closure;
    1594:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
    1595:   return(0);
    1596: }

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

    1603:   Not collective

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

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

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

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

    1621:   Level: beginner

    1623: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
    1624: @*/
    1625: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
    1626: {

    1633:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
    1634:   if (numPoints) *numPoints = 0;
    1635:   return(0);
    1636: }

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

    1643:   Not collective

    1645:   Input Parameter:
    1646: . mesh - The DMPlex

    1648:   Output Parameters:
    1649: + maxConeSize - The maximum number of in-edges
    1650: - maxSupportSize - The maximum number of out-edges

    1652:   Level: beginner

    1654: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
    1655: @*/
    1656: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
    1657: {
    1658:   DM_Plex *mesh = (DM_Plex*) dm->data;

    1662:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
    1663:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
    1664:   return(0);
    1665: }

    1669: PetscErrorCode DMSetUp_Plex(DM dm)
    1670: {
    1671:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1672:   PetscInt       size;

    1677:   PetscSectionSetUp(mesh->coneSection);
    1678:   PetscSectionGetStorageSize(mesh->coneSection, &size);
    1679:   PetscMalloc1(size, &mesh->cones);
    1680:   PetscCalloc1(size, &mesh->coneOrientations);
    1681:   if (mesh->maxSupportSize) {
    1682:     PetscSectionSetUp(mesh->supportSection);
    1683:     PetscSectionGetStorageSize(mesh->supportSection, &size);
    1684:     PetscMalloc1(size, &mesh->supports);
    1685:   }
    1686:   return(0);
    1687: }

    1691: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
    1692: {

    1696:   if (subdm) {DMClone(dm, subdm);}
    1697:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
    1698:   return(0);
    1699: }

    1703: /*@
    1704:   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation

    1706:   Not collective

    1708:   Input Parameter:
    1709: . mesh - The DMPlex

    1711:   Output Parameter:

    1713:   Note:
    1714:   This should be called after all calls to DMPlexSetCone()

    1716:   Level: beginner

    1718: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
    1719: @*/
    1720: PetscErrorCode DMPlexSymmetrize(DM dm)
    1721: {
    1722:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1723:   PetscInt      *offsets;
    1724:   PetscInt       supportSize;
    1725:   PetscInt       pStart, pEnd, p;

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

    1736:     PetscSectionGetDof(mesh->coneSection, p, &dof);
    1737:     PetscSectionGetOffset(mesh->coneSection, p, &off);
    1738:     for (c = off; c < off+dof; ++c) {
    1739:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
    1740:     }
    1741:   }
    1742:   for (p = pStart; p < pEnd; ++p) {
    1743:     PetscInt dof;

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

    1747:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
    1748:   }
    1749:   PetscSectionSetUp(mesh->supportSection);
    1750:   /* Calculate supports */
    1751:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
    1752:   PetscMalloc1(supportSize, &mesh->supports);
    1753:   PetscCalloc1(pEnd - pStart, &offsets);
    1754:   for (p = pStart; p < pEnd; ++p) {
    1755:     PetscInt dof, off, c;

    1757:     PetscSectionGetDof(mesh->coneSection, p, &dof);
    1758:     PetscSectionGetOffset(mesh->coneSection, p, &off);
    1759:     for (c = off; c < off+dof; ++c) {
    1760:       const PetscInt q = mesh->cones[c];
    1761:       PetscInt       offS;

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

    1765:       mesh->supports[offS+offsets[q]] = p;
    1766:       ++offsets[q];
    1767:     }
    1768:   }
    1769:   PetscFree(offsets);
    1770:   return(0);
    1771: }

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

    1781:   Not collective

    1783:   Input Parameter:
    1784: . mesh - The DMPlex

    1786:   Output Parameter:

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

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

    1796:   Level: beginner

    1798: .seealso: DMPlexCreate(), DMPlexSymmetrize()
    1799: @*/
    1800: PetscErrorCode DMPlexStratify(DM dm)
    1801: {
    1802:   DMLabel        label;
    1803:   PetscInt       pStart, pEnd, p;
    1804:   PetscInt       numRoots = 0, numLeaves = 0;

    1809:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
    1810:   /* Calculate depth */
    1811:   DMPlexGetChart(dm, &pStart, &pEnd);
    1812:   DMPlexCreateLabel(dm, "depth");
    1813:   DMPlexGetDepthLabel(dm, &label);
    1814:   /* Initialize roots and count leaves */
    1815:   for (p = pStart; p < pEnd; ++p) {
    1816:     PetscInt coneSize, supportSize;

    1818:     DMPlexGetConeSize(dm, p, &coneSize);
    1819:     DMPlexGetSupportSize(dm, p, &supportSize);
    1820:     if (!coneSize && supportSize) {
    1821:       ++numRoots;
    1822:       DMLabelSetValue(label, p, 0);
    1823:     } else if (!supportSize && coneSize) {
    1824:       ++numLeaves;
    1825:     } else if (!supportSize && !coneSize) {
    1826:       /* Isolated points */
    1827:       DMLabelSetValue(label, p, 0);
    1828:     }
    1829:   }
    1830:   if (numRoots + numLeaves == (pEnd - pStart)) {
    1831:     for (p = pStart; p < pEnd; ++p) {
    1832:       PetscInt coneSize, supportSize;

    1834:       DMPlexGetConeSize(dm, p, &coneSize);
    1835:       DMPlexGetSupportSize(dm, p, &supportSize);
    1836:       if (!supportSize && coneSize) {
    1837:         DMLabelSetValue(label, p, 1);
    1838:       }
    1839:     }
    1840:   } else {
    1841:     IS       pointIS;
    1842:     PetscInt numPoints = 0, level = 0;

    1844:     DMLabelGetStratumIS(label, level, &pointIS);
    1845:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
    1846:     while (numPoints) {
    1847:       const PetscInt *points;
    1848:       const PetscInt  newLevel = level+1;

    1850:       ISGetIndices(pointIS, &points);
    1851:       for (p = 0; p < numPoints; ++p) {
    1852:         const PetscInt  point = points[p];
    1853:         const PetscInt *support;
    1854:         PetscInt        supportSize, s;

    1856:         DMPlexGetSupportSize(dm, point, &supportSize);
    1857:         DMPlexGetSupport(dm, point, &support);
    1858:         for (s = 0; s < supportSize; ++s) {
    1859:           DMLabelSetValue(label, support[s], newLevel);
    1860:         }
    1861:       }
    1862:       ISRestoreIndices(pointIS, &points);
    1863:       ++level;
    1864:       ISDestroy(&pointIS);
    1865:       DMLabelGetStratumIS(label, level, &pointIS);
    1866:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
    1867:       else         {numPoints = 0;}
    1868:     }
    1869:     ISDestroy(&pointIS);
    1870:   }
    1871:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
    1872:   return(0);
    1873: }

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

    1880:   Not Collective

    1882:   Input Parameters:
    1883: + dm - The DMPlex object
    1884: . numPoints - The number of input points for the join
    1885: - points - The input points

    1887:   Output Parameters:
    1888: + numCoveredPoints - The number of points in the join
    1889: - coveredPoints - The points in the join

    1891:   Level: intermediate

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

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

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

    1901: .keywords: mesh
    1902: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
    1903: @*/
    1904: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    1905: {
    1906:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    1907:   PetscInt      *join[2];
    1908:   PetscInt       joinSize, i = 0;
    1909:   PetscInt       dof, off, p, c, m;

    1917:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
    1918:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
    1919:   /* Copy in support of first point */
    1920:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
    1921:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
    1922:   for (joinSize = 0; joinSize < dof; ++joinSize) {
    1923:     join[i][joinSize] = mesh->supports[off+joinSize];
    1924:   }
    1925:   /* Check each successive support */
    1926:   for (p = 1; p < numPoints; ++p) {
    1927:     PetscInt newJoinSize = 0;

    1929:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
    1930:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
    1931:     for (c = 0; c < dof; ++c) {
    1932:       const PetscInt point = mesh->supports[off+c];

    1934:       for (m = 0; m < joinSize; ++m) {
    1935:         if (point == join[i][m]) {
    1936:           join[1-i][newJoinSize++] = point;
    1937:           break;
    1938:         }
    1939:       }
    1940:     }
    1941:     joinSize = newJoinSize;
    1942:     i        = 1-i;
    1943:   }
    1944:   *numCoveredPoints = joinSize;
    1945:   *coveredPoints    = join[i];
    1946:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
    1947:   return(0);
    1948: }

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

    1955:   Not Collective

    1957:   Input Parameters:
    1958: + dm - The DMPlex object
    1959: . numPoints - The number of input points for the join
    1960: - points - The input points

    1962:   Output Parameters:
    1963: + numCoveredPoints - The number of points in the join
    1964: - coveredPoints - The points in the join

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

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

    1972:   Level: intermediate

    1974: .keywords: mesh
    1975: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
    1976: @*/
    1977: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    1978: {

    1986:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
    1987:   if (numCoveredPoints) *numCoveredPoints = 0;
    1988:   return(0);
    1989: }

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

    1996:   Not Collective

    1998:   Input Parameters:
    1999: + dm - The DMPlex object
    2000: . numPoints - The number of input points for the join
    2001: - points - The input points

    2003:   Output Parameters:
    2004: + numCoveredPoints - The number of points in the join
    2005: - coveredPoints - The points in the join

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

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

    2013:   Level: intermediate

    2015: .keywords: mesh
    2016: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
    2017: @*/
    2018: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    2019: {
    2020:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2021:   PetscInt      *offsets, **closures;
    2022:   PetscInt      *join[2];
    2023:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
    2024:   PetscInt       p, d, c, m, ms;

    2033:   DMPlexGetDepth(dm, &depth);
    2034:   PetscCalloc1(numPoints, &closures);
    2035:   DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
    2036:   ms      = mesh->maxSupportSize;
    2037:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
    2038:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
    2039:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);

    2041:   for (p = 0; p < numPoints; ++p) {
    2042:     PetscInt closureSize;

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

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

    2050:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
    2051:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
    2052:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
    2053:           offsets[p*(depth+2)+d+1] = i;
    2054:           break;
    2055:         }
    2056:       }
    2057:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
    2058:     }
    2059:     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);
    2060:   }
    2061:   for (d = 0; d < depth+1; ++d) {
    2062:     PetscInt dof;

    2064:     /* Copy in support of first point */
    2065:     dof = offsets[d+1] - offsets[d];
    2066:     for (joinSize = 0; joinSize < dof; ++joinSize) {
    2067:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
    2068:     }
    2069:     /* Check each successive cone */
    2070:     for (p = 1; p < numPoints && joinSize; ++p) {
    2071:       PetscInt newJoinSize = 0;

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

    2077:         for (m = 0; m < joinSize; ++m) {
    2078:           if (point == join[i][m]) {
    2079:             join[1-i][newJoinSize++] = point;
    2080:             break;
    2081:           }
    2082:         }
    2083:       }
    2084:       joinSize = newJoinSize;
    2085:       i        = 1-i;
    2086:     }
    2087:     if (joinSize) break;
    2088:   }
    2089:   *numCoveredPoints = joinSize;
    2090:   *coveredPoints    = join[i];
    2091:   for (p = 0; p < numPoints; ++p) {
    2092:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
    2093:   }
    2094:   PetscFree(closures);
    2095:   DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
    2096:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
    2097:   return(0);
    2098: }

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

    2105:   Not Collective

    2107:   Input Parameters:
    2108: + dm - The DMPlex object
    2109: . numPoints - The number of input points for the meet
    2110: - points - The input points

    2112:   Output Parameters:
    2113: + numCoveredPoints - The number of points in the meet
    2114: - coveredPoints - The points in the meet

    2116:   Level: intermediate

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

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

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

    2126: .keywords: mesh
    2127: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
    2128: @*/
    2129: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
    2130: {
    2131:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2132:   PetscInt      *meet[2];
    2133:   PetscInt       meetSize, i = 0;
    2134:   PetscInt       dof, off, p, c, m;

    2142:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
    2143:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
    2144:   /* Copy in cone of first point */
    2145:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
    2146:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
    2147:   for (meetSize = 0; meetSize < dof; ++meetSize) {
    2148:     meet[i][meetSize] = mesh->cones[off+meetSize];
    2149:   }
    2150:   /* Check each successive cone */
    2151:   for (p = 1; p < numPoints; ++p) {
    2152:     PetscInt newMeetSize = 0;

    2154:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
    2155:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
    2156:     for (c = 0; c < dof; ++c) {
    2157:       const PetscInt point = mesh->cones[off+c];

    2159:       for (m = 0; m < meetSize; ++m) {
    2160:         if (point == meet[i][m]) {
    2161:           meet[1-i][newMeetSize++] = point;
    2162:           break;
    2163:         }
    2164:       }
    2165:     }
    2166:     meetSize = newMeetSize;
    2167:     i        = 1-i;
    2168:   }
    2169:   *numCoveringPoints = meetSize;
    2170:   *coveringPoints    = meet[i];
    2171:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
    2172:   return(0);
    2173: }

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

    2180:   Not Collective

    2182:   Input Parameters:
    2183: + dm - The DMPlex object
    2184: . numPoints - The number of input points for the meet
    2185: - points - The input points

    2187:   Output Parameters:
    2188: + numCoveredPoints - The number of points in the meet
    2189: - coveredPoints - The points in the meet

    2191:   Level: intermediate

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

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

    2199: .keywords: mesh
    2200: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
    2201: @*/
    2202: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    2203: {

    2211:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
    2212:   if (numCoveredPoints) *numCoveredPoints = 0;
    2213:   return(0);
    2214: }

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

    2221:   Not Collective

    2223:   Input Parameters:
    2224: + dm - The DMPlex object
    2225: . numPoints - The number of input points for the meet
    2226: - points - The input points

    2228:   Output Parameters:
    2229: + numCoveredPoints - The number of points in the meet
    2230: - coveredPoints - The points in the meet

    2232:   Level: intermediate

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

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

    2240: .keywords: mesh
    2241: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
    2242: @*/
    2243: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
    2244: {
    2245:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    2246:   PetscInt      *offsets, **closures;
    2247:   PetscInt      *meet[2];
    2248:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
    2249:   PetscInt       p, h, c, m, mc;

    2258:   DMPlexGetDepth(dm, &height);
    2259:   PetscMalloc1(numPoints, &closures);
    2260:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
    2261:   mc      = mesh->maxConeSize;
    2262:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
    2263:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
    2264:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

    2266:   for (p = 0; p < numPoints; ++p) {
    2267:     PetscInt closureSize;

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

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

    2275:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
    2276:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
    2277:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
    2278:           offsets[p*(height+2)+h+1] = i;
    2279:           break;
    2280:         }
    2281:       }
    2282:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
    2283:     }
    2284:     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);
    2285:   }
    2286:   for (h = 0; h < height+1; ++h) {
    2287:     PetscInt dof;

    2289:     /* Copy in cone of first point */
    2290:     dof = offsets[h+1] - offsets[h];
    2291:     for (meetSize = 0; meetSize < dof; ++meetSize) {
    2292:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
    2293:     }
    2294:     /* Check each successive cone */
    2295:     for (p = 1; p < numPoints && meetSize; ++p) {
    2296:       PetscInt newMeetSize = 0;

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

    2302:         for (m = 0; m < meetSize; ++m) {
    2303:           if (point == meet[i][m]) {
    2304:             meet[1-i][newMeetSize++] = point;
    2305:             break;
    2306:           }
    2307:         }
    2308:       }
    2309:       meetSize = newMeetSize;
    2310:       i        = 1-i;
    2311:     }
    2312:     if (meetSize) break;
    2313:   }
    2314:   *numCoveredPoints = meetSize;
    2315:   *coveredPoints    = meet[i];
    2316:   for (p = 0; p < numPoints; ++p) {
    2317:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
    2318:   }
    2319:   PetscFree(closures);
    2320:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
    2321:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
    2322:   return(0);
    2323: }

    2327: /*@C
    2328:   DMPlexEqual - Determine if two DMs have the same topology

    2330:   Not Collective

    2332:   Input Parameters:
    2333: + dmA - A DMPlex object
    2334: - dmB - A DMPlex object

    2336:   Output Parameters:
    2337: . equal - PETSC_TRUE if the topologies are identical

    2339:   Level: intermediate

    2341:   Notes:
    2342:   We are not solving graph isomorphism, so we do not permutation.

    2344: .keywords: mesh
    2345: .seealso: DMPlexGetCone()
    2346: @*/
    2347: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
    2348: {
    2349:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;

    2357:   *equal = PETSC_FALSE;
    2358:   DMPlexGetDepth(dmA, &depth);
    2359:   DMPlexGetDepth(dmB, &depthB);
    2360:   if (depth != depthB) return(0);
    2361:   DMPlexGetChart(dmA, &pStart,  &pEnd);
    2362:   DMPlexGetChart(dmB, &pStartB, &pEndB);
    2363:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
    2364:   for (p = pStart; p < pEnd; ++p) {
    2365:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
    2366:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

    2368:     DMPlexGetConeSize(dmA, p, &coneSize);
    2369:     DMPlexGetCone(dmA, p, &cone);
    2370:     DMPlexGetConeOrientation(dmA, p, &ornt);
    2371:     DMPlexGetConeSize(dmB, p, &coneSizeB);
    2372:     DMPlexGetCone(dmB, p, &coneB);
    2373:     DMPlexGetConeOrientation(dmB, p, &orntB);
    2374:     if (coneSize != coneSizeB) return(0);
    2375:     for (c = 0; c < coneSize; ++c) {
    2376:       if (cone[c] != coneB[c]) return(0);
    2377:       if (ornt[c] != orntB[c]) return(0);
    2378:     }
    2379:     DMPlexGetSupportSize(dmA, p, &supportSize);
    2380:     DMPlexGetSupport(dmA, p, &support);
    2381:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
    2382:     DMPlexGetSupport(dmB, p, &supportB);
    2383:     if (supportSize != supportSizeB) return(0);
    2384:     for (s = 0; s < supportSize; ++s) {
    2385:       if (support[s] != supportB[s]) return(0);
    2386:     }
    2387:   }
    2388:   *equal = PETSC_TRUE;
    2389:   return(0);
    2390: }

    2394: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
    2395: {
    2396:   MPI_Comm       comm;

    2400:   PetscObjectGetComm((PetscObject)dm,&comm);
    2402:   switch (cellDim) {
    2403:   case 0:
    2404:     *numFaceVertices = 0;
    2405:     break;
    2406:   case 1:
    2407:     *numFaceVertices = 1;
    2408:     break;
    2409:   case 2:
    2410:     switch (numCorners) {
    2411:     case 3: /* triangle */
    2412:       *numFaceVertices = 2; /* Edge has 2 vertices */
    2413:       break;
    2414:     case 4: /* quadrilateral */
    2415:       *numFaceVertices = 2; /* Edge has 2 vertices */
    2416:       break;
    2417:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
    2418:       *numFaceVertices = 3; /* Edge has 3 vertices */
    2419:       break;
    2420:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
    2421:       *numFaceVertices = 3; /* Edge has 3 vertices */
    2422:       break;
    2423:     default:
    2424:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
    2425:     }
    2426:     break;
    2427:   case 3:
    2428:     switch (numCorners) {
    2429:     case 4: /* tetradehdron */
    2430:       *numFaceVertices = 3; /* Face has 3 vertices */
    2431:       break;
    2432:     case 6: /* tet cohesive cells */
    2433:       *numFaceVertices = 4; /* Face has 4 vertices */
    2434:       break;
    2435:     case 8: /* hexahedron */
    2436:       *numFaceVertices = 4; /* Face has 4 vertices */
    2437:       break;
    2438:     case 9: /* tet cohesive Lagrange cells */
    2439:       *numFaceVertices = 6; /* Face has 6 vertices */
    2440:       break;
    2441:     case 10: /* quadratic tetrahedron */
    2442:       *numFaceVertices = 6; /* Face has 6 vertices */
    2443:       break;
    2444:     case 12: /* hex cohesive Lagrange cells */
    2445:       *numFaceVertices = 6; /* Face has 6 vertices */
    2446:       break;
    2447:     case 18: /* quadratic tet cohesive Lagrange cells */
    2448:       *numFaceVertices = 6; /* Face has 6 vertices */
    2449:       break;
    2450:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
    2451:       *numFaceVertices = 9; /* Face has 9 vertices */
    2452:       break;
    2453:     default:
    2454:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
    2455:     }
    2456:     break;
    2457:   default:
    2458:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
    2459:   }
    2460:   return(0);
    2461: }

    2465: /*@
    2466:   DMPlexLocalizeCoordinate - If a mesh is periodic (a torus with lengths L_i, some of which can be infinite), project the coordinate onto [0, L_i) in each dimension.

    2468:   Input Parameters:
    2469: + dm     - The DM
    2470: - in     - The input coordinate point (dim numbers)

    2472:   Output Parameter:
    2473: . out - The localized coordinate point

    2475:   Level: developer

    2477: .seealso: DMPlexLocalizeCoordinates(), DMPlexLocalizeAddCoordinate()
    2478: @*/
    2479: PetscErrorCode DMPlexLocalizeCoordinate(DM dm, const PetscScalar in[], PetscScalar out[])
    2480: {
    2481:   PetscInt       dim, d;

    2485:   DMGetCoordinateDim(dm, &dim);
    2486:   if (!dm->maxCell) {
    2487:     for (d = 0; d < dim; ++d) out[d] = in[d];
    2488:   } else {
    2489:     for (d = 0; d < dim; ++d) {
    2490:       out[d] = in[d] - dm->L[d]*floor(PetscRealPart(in[d])/dm->L[d]);
    2491:     }
    2492:   }
    2493:   return(0);
    2494: }

    2498: /*
    2499:   DMPlexLocalizeCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.

    2501:   Input Parameters:
    2502: + dm     - The DM
    2503: . dim    - The spatial dimension
    2504: . anchor - The anchor point, the input point can be no more than maxCell away from it
    2505: - in     - The input coordinate point (dim numbers)

    2507:   Output Parameter:
    2508: . out - The localized coordinate point

    2510:   Level: developer

    2512:   Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell

    2514: .seealso: DMPlexLocalizeCoordinates(), DMPlexLocalizeAddCoordinate()
    2515: */
    2516: PetscErrorCode DMPlexLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    2517: {
    2518:   PetscInt d;

    2521:   if (!dm->maxCell) {
    2522:     for (d = 0; d < dim; ++d) out[d] = in[d];
    2523:   } else {
    2524:     for (d = 0; d < dim; ++d) {
    2525:       if (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d]) {
    2526:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
    2527:       } else {
    2528:         out[d] = in[d];
    2529:       }
    2530:     }
    2531:   }
    2532:   return(0);
    2533: }
    2536: PetscErrorCode DMPlexLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
    2537: {
    2538:   PetscInt d;

    2541:   if (!dm->maxCell) {
    2542:     for (d = 0; d < dim; ++d) out[d] = in[d];
    2543:   } else {
    2544:     for (d = 0; d < dim; ++d) {
    2545:       if (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d]) {
    2546:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
    2547:       } else {
    2548:         out[d] = in[d];
    2549:       }
    2550:     }
    2551:   }
    2552:   return(0);
    2553: }

    2557: /*
    2558:   DMPlexLocalizeAddCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.

    2560:   Input Parameters:
    2561: + dm     - The DM
    2562: . dim    - The spatial dimension
    2563: . anchor - The anchor point, the input point can be no more than maxCell away from it
    2564: . in     - The input coordinate delta (dim numbers)
    2565: - out    - The input coordinate point (dim numbers)

    2567:   Output Parameter:
    2568: . out    - The localized coordinate in + out

    2570:   Level: developer

    2572:   Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell

    2574: .seealso: DMPlexLocalizeCoordinates(), DMPlexLocalizeCoordinate()
    2575: */
    2576: PetscErrorCode DMPlexLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    2577: {
    2578:   PetscInt d;

    2581:   if (!dm->maxCell) {
    2582:     for (d = 0; d < dim; ++d) out[d] += in[d];
    2583:   } else {
    2584:     for (d = 0; d < dim; ++d) {
    2585:       if (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d]) {
    2586:         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
    2587:       } else {
    2588:         out[d] += in[d];
    2589:       }
    2590:     }
    2591:   }
    2592:   return(0);
    2593: }

    2597: /*@
    2598:   DMPlexLocalizeCoordinates - If a mesh is periodic, create local coordinates for each cell

    2600:   Input Parameter:
    2601: . dm - The DM

    2603:   Level: developer

    2605: .seealso: DMPlexLocalizeCoordinate(), DMPlexLocalizeAddCoordinate()
    2606: @*/
    2607: PetscErrorCode DMPlexLocalizeCoordinates(DM dm)
    2608: {
    2609:   PetscSection   coordSection, cSection;
    2610:   Vec            coordinates,  cVec;
    2611:   PetscScalar   *coords, *coords2, *anchor;
    2612:   PetscInt       Nc, cStart, cEnd, c, vStart, vEnd, v, dof, d, off, off2, bs, coordSize;

    2617:   if (!dm->maxCell) return(0);
    2618:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    2619:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    2620:   DMGetCoordinatesLocal(dm, &coordinates);
    2621:   DMGetCoordinateSection(dm, &coordSection);
    2622:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
    2623:   PetscSectionSetNumFields(cSection, 1);
    2624:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
    2625:   PetscSectionSetFieldComponents(cSection, 0, Nc);
    2626:   PetscSectionSetChart(cSection, cStart, vEnd);
    2627:   for (v = vStart; v < vEnd; ++v) {
    2628:     PetscSectionGetDof(coordSection, v, &dof);
    2629:     PetscSectionSetDof(cSection,     v,  dof);
    2630:     PetscSectionSetFieldDof(cSection, v, 0, dof);
    2631:   }
    2632:   for (c = cStart; c < cEnd; ++c) {
    2633:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &dof, NULL);
    2634:     PetscSectionSetDof(cSection, c, dof);
    2635:     PetscSectionSetFieldDof(cSection, c, 0, dof);
    2636:   }
    2637:   PetscSectionSetUp(cSection);
    2638:   PetscSectionGetStorageSize(cSection, &coordSize);
    2639:   VecCreate(PetscObjectComm((PetscObject) dm), &cVec);
    2640:   VecGetBlockSize(coordinates, &bs);
    2641:   VecSetBlockSize(cVec,         bs);
    2642:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
    2643:   VecSetType(cVec,VECSTANDARD);
    2644:   VecGetArray(coordinates, &coords);
    2645:   VecGetArray(cVec,        &coords2);
    2646:   for (v = vStart; v < vEnd; ++v) {
    2647:     PetscSectionGetDof(coordSection, v, &dof);
    2648:     PetscSectionGetOffset(coordSection, v, &off);
    2649:     PetscSectionGetOffset(cSection,     v, &off2);
    2650:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
    2651:   }
    2652:   DMGetWorkArray(dm, 3, PETSC_SCALAR, &anchor);
    2653:   for (c = cStart; c < cEnd; ++c) {
    2654:     PetscScalar *cellCoords = NULL;
    2655:     PetscInt     b;

    2657:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &dof, &cellCoords);
    2658:     PetscSectionGetOffset(cSection, c, &off2);
    2659:     for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
    2660:     for (d = 0; d < dof/bs; ++d) {DMPlexLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
    2661:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &dof, &cellCoords);
    2662:   }
    2663:   DMRestoreWorkArray(dm, 3, PETSC_SCALAR, &anchor);
    2664:   VecRestoreArray(coordinates, &coords);
    2665:   VecRestoreArray(cVec,        &coords2);
    2666:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
    2667:   DMSetCoordinatesLocal(dm, cVec);
    2668:   VecDestroy(&cVec);
    2669:   PetscSectionDestroy(&cSection);
    2670:   return(0);
    2671: }

    2675: /*@
    2676:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

    2678:   Not Collective

    2680:   Input Parameter:
    2681: . dm    - The DMPlex object

    2683:   Output Parameter:
    2684: . depthLabel - The DMLabel recording point depth

    2686:   Level: developer

    2688: .keywords: mesh, points
    2689: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
    2690: @*/
    2691: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
    2692: {
    2693:   DM_Plex       *mesh = (DM_Plex*) dm->data;

    2699:   if (!mesh->depthLabel) {DMPlexGetLabel(dm, "depth", &mesh->depthLabel);}
    2700:   *depthLabel = mesh->depthLabel;
    2701:   return(0);
    2702: }

    2706: /*@
    2707:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

    2709:   Not Collective

    2711:   Input Parameter:
    2712: . dm    - The DMPlex object

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

    2717:   Level: developer

    2719: .keywords: mesh, points
    2720: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
    2721: @*/
    2722: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
    2723: {
    2724:   DMLabel        label;
    2725:   PetscInt       d = 0;

    2731:   DMPlexGetDepthLabel(dm, &label);
    2732:   if (label) {DMLabelGetNumValues(label, &d);}
    2733:   *depth = d-1;
    2734:   return(0);
    2735: }

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

    2742:   Not Collective

    2744:   Input Parameters:
    2745: + dm           - The DMPlex object
    2746: - stratumValue - The requested depth

    2748:   Output Parameters:
    2749: + start - The first point at this depth
    2750: - end   - One beyond the last point at this depth

    2752:   Level: developer

    2754: .keywords: mesh, points
    2755: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
    2756: @*/
    2757: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
    2758: {
    2759:   DMLabel        label;
    2760:   PetscInt       pStart, pEnd;

    2767:   DMPlexGetChart(dm, &pStart, &pEnd);
    2768:   if (pStart == pEnd) return(0);
    2769:   if (stratumValue < 0) {
    2770:     if (start) *start = pStart;
    2771:     if (end)   *end   = pEnd;
    2772:     return(0);
    2773:   }
    2774:   DMPlexGetDepthLabel(dm, &label);
    2775:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
    2776:   DMLabelGetStratumBounds(label, stratumValue, start, end);
    2777:   return(0);
    2778: }

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

    2785:   Not Collective

    2787:   Input Parameters:
    2788: + dm           - The DMPlex object
    2789: - stratumValue - The requested height

    2791:   Output Parameters:
    2792: + start - The first point at this height
    2793: - end   - One beyond the last point at this height

    2795:   Level: developer

    2797: .keywords: mesh, points
    2798: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
    2799: @*/
    2800: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
    2801: {
    2802:   DMLabel        label;
    2803:   PetscInt       depth, pStart, pEnd;

    2810:   DMPlexGetChart(dm, &pStart, &pEnd);
    2811:   if (pStart == pEnd) return(0);
    2812:   if (stratumValue < 0) {
    2813:     if (start) *start = pStart;
    2814:     if (end)   *end   = pEnd;
    2815:     return(0);
    2816:   }
    2817:   DMPlexGetDepthLabel(dm, &label);
    2818:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
    2819:   DMLabelGetNumValues(label, &depth);
    2820:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
    2821:   return(0);
    2822: }

    2826: /* Set the number of dof on each point and separate by fields */
    2827: PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
    2828: {
    2829:   PetscInt      *pMax;
    2830:   PetscInt       depth, pStart = 0, pEnd = 0;
    2831:   PetscInt       Nf, p, d, dep, f;
    2832:   PetscBool     *isFE;

    2836:   PetscMalloc1(numFields, &isFE);
    2837:   DMGetNumFields(dm, &Nf);
    2838:   for (f = 0; f < numFields; ++f) {
    2839:     PetscObject  obj;
    2840:     PetscClassId id;

    2842:     isFE[f] = PETSC_FALSE;
    2843:     if (f >= Nf) continue;
    2844:     DMGetField(dm, f, &obj);
    2845:     PetscObjectGetClassId(obj, &id);
    2846:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
    2847:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
    2848:   }
    2849:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
    2850:   if (numFields > 0) {
    2851:     PetscSectionSetNumFields(*section, numFields);
    2852:     if (numComp) {
    2853:       for (f = 0; f < numFields; ++f) {
    2854:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
    2855:       }
    2856:     }
    2857:   }
    2858:   DMPlexGetChart(dm, &pStart, &pEnd);
    2859:   PetscSectionSetChart(*section, pStart, pEnd);
    2860:   DMPlexGetDepth(dm, &depth);
    2861:   PetscMalloc1(depth+1,&pMax);
    2862:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
    2863:   for (dep = 0; dep <= depth; ++dep) {
    2864:     d    = dim == depth ? dep : (!dep ? 0 : dim);
    2865:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
    2866:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
    2867:     for (p = pStart; p < pEnd; ++p) {
    2868:       PetscInt tot = 0;

    2870:       for (f = 0; f < numFields; ++f) {
    2871:         if (isFE[f] && p >= pMax[dep]) continue;
    2872:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
    2873:         tot += numDof[f*(dim+1)+d];
    2874:       }
    2875:       PetscSectionSetDof(*section, p, tot);
    2876:     }
    2877:   }
    2878:   PetscFree(pMax);
    2879:   PetscFree(isFE);
    2880:   return(0);
    2881: }

    2885: /* Set the number of dof on each point and separate by fields
    2886:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
    2887: */
    2888: PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
    2889: {
    2890:   PetscInt       numFields;
    2891:   PetscInt       bc;
    2892:   PetscSection   aSec;

    2896:   PetscSectionGetNumFields(section, &numFields);
    2897:   for (bc = 0; bc < numBC; ++bc) {
    2898:     PetscInt        field = 0;
    2899:     const PetscInt *comp;
    2900:     const PetscInt *idx;
    2901:     PetscInt        Nc = -1, n, i;

    2903:     if (numFields) field = bcField[bc];
    2904:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
    2905:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
    2906:     ISGetLocalSize(bcPoints[bc], &n);
    2907:     ISGetIndices(bcPoints[bc], &idx);
    2908:     for (i = 0; i < n; ++i) {
    2909:       const PetscInt p = idx[i];
    2910:       PetscInt       numConst;

    2912:       if (numFields) {
    2913:         PetscSectionGetFieldDof(section, p, field, &numConst);
    2914:       } else {
    2915:         PetscSectionGetDof(section, p, &numConst);
    2916:       }
    2917:       /* If Nc < 0, constrain every dof on the point */
    2918:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
    2919:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
    2920:       PetscSectionAddConstraintDof(section, p, numConst);
    2921:     }
    2922:     ISRestoreIndices(bcPoints[bc], &idx);
    2923:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
    2924:   }
    2925:   DMPlexGetAnchors(dm, &aSec, NULL);
    2926:   if (aSec) {
    2927:     PetscInt aStart, aEnd, a;

    2929:     PetscSectionGetChart(aSec, &aStart, &aEnd);
    2930:     for (a = aStart; a < aEnd; a++) {
    2931:       PetscInt dof, f;

    2933:       PetscSectionGetDof(aSec, a, &dof);
    2934:       if (dof) {
    2935:         /* if there are point-to-point constraints, then all dofs are constrained */
    2936:         PetscSectionGetDof(section, a, &dof);
    2937:         PetscSectionSetConstraintDof(section, a, dof);
    2938:         for (f = 0; f < numFields; f++) {
    2939:           PetscSectionGetFieldDof(section, a, f, &dof);
    2940:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
    2941:         }
    2942:       }
    2943:     }
    2944:   }
    2945:   return(0);
    2946: }

    2950: /* Set the constrained field indices on each point
    2951:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
    2952: */
    2953: PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
    2954: {
    2955:   PetscSection   aSec;
    2956:   PetscInt      *indices;
    2957:   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;

    2961:   PetscSectionGetNumFields(section, &numFields);
    2962:   if (!numFields) return(0);
    2963:   /* Initialize all field indices to -1 */
    2964:   PetscSectionGetChart(section, &pStart, &pEnd);
    2965:   PetscSectionGetMaxDof(section, &maxDof);
    2966:   PetscMalloc1(maxDof, &indices);
    2967:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
    2968:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
    2969:   /* Handle BC constraints */
    2970:   for (bc = 0; bc < numBC; ++bc) {
    2971:     const PetscInt  field = bcField[bc];
    2972:     const PetscInt *comp, *idx;
    2973:     PetscInt        Nc = -1, n, i;

    2975:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
    2976:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
    2977:     ISGetLocalSize(bcPoints[bc], &n);
    2978:     ISGetIndices(bcPoints[bc], &idx);
    2979:     for (i = 0; i < n; ++i) {
    2980:       const PetscInt  p = idx[i];
    2981:       const PetscInt *find;
    2982:       PetscInt        fcdof, c;

    2984:       PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
    2985:       if (Nc < 0) {
    2986:         for (d = 0; d < fcdof; ++d) indices[d] = d;
    2987:       } else {
    2988:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
    2989:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
    2990:         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
    2991:         PetscSortInt(d+Nc, indices);
    2992:         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
    2993:       }
    2994:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
    2995:     }
    2996:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
    2997:     ISRestoreIndices(bcPoints[bc], &idx);
    2998:   }
    2999:   /* Handle anchors */
    3000:   DMPlexGetAnchors(dm, &aSec, NULL);
    3001:   if (aSec) {
    3002:     PetscInt aStart, aEnd, a;

    3004:     for (d = 0; d < maxDof; ++d) indices[d] = d;
    3005:     PetscSectionGetChart(aSec, &aStart, &aEnd);
    3006:     for (a = aStart; a < aEnd; a++) {
    3007:       PetscInt dof, fdof, f;

    3009:       PetscSectionGetDof(aSec, a, &dof);
    3010:       if (dof) {
    3011:         /* if there are point-to-point constraints, then all dofs are constrained */
    3012:         for (f = 0; f < numFields; f++) {
    3013:           PetscSectionGetFieldDof(section, a, f, &fdof);
    3014:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
    3015:         }
    3016:       }
    3017:     }
    3018:   }
    3019:   PetscFree(indices);
    3020:   return(0);
    3021: }

    3025: /* Set the constrained indices on each point */
    3026: PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
    3027: {
    3028:   PetscInt      *indices;
    3029:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

    3033:   PetscSectionGetNumFields(section, &numFields);
    3034:   PetscSectionGetMaxDof(section, &maxDof);
    3035:   PetscSectionGetChart(section, &pStart, &pEnd);
    3036:   PetscMalloc1(maxDof, &indices);
    3037:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
    3038:   for (p = pStart; p < pEnd; ++p) {
    3039:     PetscInt cdof, d;

    3041:     PetscSectionGetConstraintDof(section, p, &cdof);
    3042:     if (cdof) {
    3043:       if (numFields) {
    3044:         PetscInt numConst = 0, foff = 0;

    3046:         for (f = 0; f < numFields; ++f) {
    3047:           const PetscInt *find;
    3048:           PetscInt        fcdof, fdof;

    3050:           PetscSectionGetFieldDof(section, p, f, &fdof);
    3051:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
    3052:           /* Change constraint numbering from field component to local dof number */
    3053:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
    3054:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
    3055:           numConst += fcdof;
    3056:           foff     += fdof;
    3057:         }
    3058:         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
    3059:       } else {
    3060:         for (d = 0; d < cdof; ++d) indices[d] = d;
    3061:       }
    3062:       PetscSectionSetConstraintIndices(section, p, indices);
    3063:     }
    3064:   }
    3065:   PetscFree(indices);
    3066:   return(0);
    3067: }

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

    3074:   Not Collective

    3076:   Input Parameters:
    3077: + dm        - The DMPlex object
    3078: . dim       - The spatial dimension of the problem
    3079: . numFields - The number of fields in the problem
    3080: . numComp   - An array of size numFields that holds the number of components for each field
    3081: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
    3082: . numBC     - The number of boundary conditions
    3083: . bcField   - An array of size numBC giving the field number for each boundry condition
    3084: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
    3085: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
    3086: - perm      - Optional permutation of the chart, or NULL

    3088:   Output Parameter:
    3089: . section - The PetscSection object

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

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

    3096:   Level: developer

    3098:   Fortran Notes:
    3099:   A Fortran 90 version is available as DMPlexCreateSectionF90()

    3101: .keywords: mesh, elements
    3102: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
    3103: @*/
    3104: 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)
    3105: {
    3106:   PetscSection   aSec;

    3110:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
    3111:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
    3112:   if (perm) {PetscSectionSetPermutation(*section, perm);}
    3113:   PetscSectionSetUp(*section);
    3114:   DMPlexGetAnchors(dm,&aSec,NULL);
    3115:   if (numBC || aSec) {
    3116:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
    3117:     DMPlexCreateSectionBCIndices(dm, *section);
    3118:   }
    3119:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
    3120:   return(0);
    3121: }

    3125: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
    3126: {
    3127:   PetscSection   section;

    3131:   DMClone(dm, cdm);
    3132:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
    3133:   DMSetDefaultSection(*cdm, section);
    3134:   PetscSectionDestroy(&section);
    3135:   return(0);
    3136: }

    3140: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
    3141: {
    3142:   DM_Plex *mesh = (DM_Plex*) dm->data;

    3146:   if (section) *section = mesh->coneSection;
    3147:   return(0);
    3148: }

    3152: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
    3153: {
    3154:   DM_Plex *mesh = (DM_Plex*) dm->data;

    3158:   if (section) *section = mesh->supportSection;
    3159:   return(0);
    3160: }

    3164: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
    3165: {
    3166:   DM_Plex *mesh = (DM_Plex*) dm->data;

    3170:   if (cones) *cones = mesh->cones;
    3171:   return(0);
    3172: }

    3176: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
    3177: {
    3178:   DM_Plex *mesh = (DM_Plex*) dm->data;

    3182:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
    3183:   return(0);
    3184: }

    3186: /******************************** FEM Support **********************************/

    3190: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
    3191: {
    3192:   PetscScalar    *array, *vArray;
    3193:   const PetscInt *cone, *coneO;
    3194:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
    3195:   PetscErrorCode  ierr;

    3198:   PetscSectionGetChart(section, &pStart, &pEnd);
    3199:   DMPlexGetConeSize(dm, point, &numPoints);
    3200:   DMPlexGetCone(dm, point, &cone);
    3201:   DMPlexGetConeOrientation(dm, point, &coneO);
    3202:   if (!values || !*values) {
    3203:     if ((point >= pStart) && (point < pEnd)) {
    3204:       PetscInt dof;

    3206:       PetscSectionGetDof(section, point, &dof);
    3207:       size += dof;
    3208:     }
    3209:     for (p = 0; p < numPoints; ++p) {
    3210:       const PetscInt cp = cone[p];
    3211:       PetscInt       dof;

    3213:       if ((cp < pStart) || (cp >= pEnd)) continue;
    3214:       PetscSectionGetDof(section, cp, &dof);
    3215:       size += dof;
    3216:     }
    3217:     if (!values) {
    3218:       if (csize) *csize = size;
    3219:       return(0);
    3220:     }
    3221:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
    3222:   } else {
    3223:     array = *values;
    3224:   }
    3225:   size = 0;
    3226:   VecGetArray(v, &vArray);
    3227:   if ((point >= pStart) && (point < pEnd)) {
    3228:     PetscInt     dof, off, d;
    3229:     PetscScalar *varr;

    3231:     PetscSectionGetDof(section, point, &dof);
    3232:     PetscSectionGetOffset(section, point, &off);
    3233:     varr = &vArray[off];
    3234:     for (d = 0; d < dof; ++d, ++offset) {
    3235:       array[offset] = varr[d];
    3236:     }
    3237:     size += dof;
    3238:   }
    3239:   for (p = 0; p < numPoints; ++p) {
    3240:     const PetscInt cp = cone[p];
    3241:     PetscInt       o  = coneO[p];
    3242:     PetscInt       dof, off, d;
    3243:     PetscScalar   *varr;

    3245:     if ((cp < pStart) || (cp >= pEnd)) continue;
    3246:     PetscSectionGetDof(section, cp, &dof);
    3247:     PetscSectionGetOffset(section, cp, &off);
    3248:     varr = &vArray[off];
    3249:     if (o >= 0) {
    3250:       for (d = 0; d < dof; ++d, ++offset) {
    3251:         array[offset] = varr[d];
    3252:       }
    3253:     } else {
    3254:       for (d = dof-1; d >= 0; --d, ++offset) {
    3255:         array[offset] = varr[d];
    3256:       }
    3257:     }
    3258:     size += dof;
    3259:   }
    3260:   VecRestoreArray(v, &vArray);
    3261:   if (!*values) {
    3262:     if (csize) *csize = size;
    3263:     *values = array;
    3264:   } else {
    3265:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
    3266:     *csize = size;
    3267:   }
    3268:   return(0);
    3269: }

    3273: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
    3274: {
    3275:   PetscInt       offset = 0, p;

    3279:   *size = 0;
    3280:   for (p = 0; p < numPoints*2; p += 2) {
    3281:     const PetscInt point = points[p];
    3282:     const PetscInt o     = points[p+1];
    3283:     PetscInt       dof, off, d;
    3284:     const PetscScalar *varr;

    3286:     PetscSectionGetDof(section, point, &dof);
    3287:     PetscSectionGetOffset(section, point, &off);
    3288:     varr = &vArray[off];
    3289:     if (o >= 0) {
    3290:       for (d = 0; d < dof; ++d, ++offset)    array[offset] = varr[d];
    3291:     } else {
    3292:       for (d = dof-1; d >= 0; --d, ++offset) array[offset] = varr[d];
    3293:     }
    3294:   }
    3295:   *size = offset;
    3296:   return(0);
    3297: }

    3301: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
    3302: {
    3303:   PetscInt       offset = 0, f;

    3307:   *size = 0;
    3308:   for (f = 0; f < numFields; ++f) {
    3309:     PetscInt fcomp, p;

    3311:     PetscSectionGetFieldComponents(section, f, &fcomp);
    3312:     for (p = 0; p < numPoints*2; p += 2) {
    3313:       const PetscInt point = points[p];
    3314:       const PetscInt o     = points[p+1];
    3315:       PetscInt       fdof, foff, d, c;
    3316:       const PetscScalar *varr;

    3318:       PetscSectionGetFieldDof(section, point, f, &fdof);
    3319:       PetscSectionGetFieldOffset(section, point, f, &foff);
    3320:       varr = &vArray[foff];
    3321:       if (o >= 0) {
    3322:         for (d = 0; d < fdof; ++d, ++offset) array[offset] = varr[d];
    3323:       } else {
    3324:         for (d = fdof/fcomp-1; d >= 0; --d) {
    3325:           for (c = 0; c < fcomp; ++c, ++offset) {
    3326:             array[offset] = varr[d*fcomp+c];
    3327:           }
    3328:         }
    3329:       }
    3330:     }
    3331:   }
    3332:   *size = offset;
    3333:   return(0);
    3334: }

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

    3341:   Not collective

    3343:   Input Parameters:
    3344: + dm - The DM
    3345: . section - The section describing the layout in v, or NULL to use the default section
    3346: . v - The local vector
    3347: - point - The sieve point in the DM

    3349:   Output Parameters:
    3350: + csize - The number of values in the closure, or NULL
    3351: - values - The array of values, which is a borrowed array and should not be freed

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

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

    3359:   Level: intermediate

    3361: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
    3362: @*/
    3363: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
    3364: {
    3365:   PetscSection    clSection;
    3366:   IS              clPoints;
    3367:   PetscScalar    *array, *vArray;
    3368:   PetscInt       *points = NULL;
    3369:   const PetscInt *clp;
    3370:   PetscInt        depth, numFields, numPoints, size;
    3371:   PetscErrorCode  ierr;

    3375:   if (!section) {DMGetDefaultSection(dm, &section);}
    3378:   DMPlexGetDepth(dm, &depth);
    3379:   PetscSectionGetNumFields(section, &numFields);
    3380:   if (depth == 1 && numFields < 2) {
    3381:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
    3382:     return(0);
    3383:   }
    3384:   /* Get points */
    3385:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
    3386:   if (!clPoints) {
    3387:     PetscInt pStart, pEnd, p, q;

    3389:     PetscSectionGetChart(section, &pStart, &pEnd);
    3390:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
    3391:     /* Compress out points not in the section */
    3392:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
    3393:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
    3394:         points[q*2]   = points[p];
    3395:         points[q*2+1] = points[p+1];
    3396:         ++q;
    3397:       }
    3398:     }
    3399:     numPoints = q;
    3400:   } else {
    3401:     PetscInt dof, off;

    3403:     PetscSectionGetDof(clSection, point, &dof);
    3404:     PetscSectionGetOffset(clSection, point, &off);
    3405:     ISGetIndices(clPoints, &clp);
    3406:     numPoints = dof/2;
    3407:     points    = (PetscInt *) &clp[off];
    3408:   }
    3409:   /* Get array */
    3410:   if (!values || !*values) {
    3411:     PetscInt asize = 0, dof, p;

    3413:     for (p = 0; p < numPoints*2; p += 2) {
    3414:       PetscSectionGetDof(section, points[p], &dof);
    3415:       asize += dof;
    3416:     }
    3417:     if (!values) {
    3418:       if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
    3419:       else           {ISRestoreIndices(clPoints, &clp);}
    3420:       if (csize) *csize = asize;
    3421:       return(0);
    3422:     }
    3423:     DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
    3424:   } else {
    3425:     array = *values;
    3426:   }
    3427:   VecGetArray(v, &vArray);
    3428:   /* Get values */
    3429:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, vArray, &size, array);}
    3430:   else               {DMPlexVecGetClosure_Static(section, numPoints, points, vArray, &size, array);}
    3431:   /* Cleanup points */
    3432:   if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
    3433:   else           {ISRestoreIndices(clPoints, &clp);}
    3434:   /* Cleanup array */
    3435:   VecRestoreArray(v, &vArray);
    3436:   if (!*values) {
    3437:     if (csize) *csize = size;
    3438:     *values = array;
    3439:   } else {
    3440:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
    3441:     *csize = size;
    3442:   }
    3443:   return(0);
    3444: }

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

    3451:   Not collective

    3453:   Input Parameters:
    3454: + dm - The DM
    3455: . section - The section describing the layout in v, or NULL to use the default section
    3456: . v - The local vector
    3457: . point - The sieve point in the DM
    3458: . csize - The number of values in the closure, or NULL
    3459: - values - The array of values, which is a borrowed array and should not be freed

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

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

    3467:   Level: intermediate

    3469: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
    3470: @*/
    3471: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
    3472: {
    3473:   PetscInt       size = 0;

    3477:   /* Should work without recalculating size */
    3478:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
    3479:   return(0);
    3480: }

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

    3487: PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
    3488: {
    3489:   PetscInt        cdof;   /* The number of constraints on this point */
    3490:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
    3491:   PetscScalar    *a;
    3492:   PetscInt        off, cind = 0, k;
    3493:   PetscErrorCode  ierr;

    3496:   PetscSectionGetConstraintDof(section, point, &cdof);
    3497:   PetscSectionGetOffset(section, point, &off);
    3498:   a    = &array[off];
    3499:   if (!cdof || setBC) {
    3500:     if (orientation >= 0) {
    3501:       for (k = 0; k < dof; ++k) {
    3502:         fuse(&a[k], values[k]);
    3503:       }
    3504:     } else {
    3505:       for (k = 0; k < dof; ++k) {
    3506:         fuse(&a[k], values[dof-k-1]);
    3507:       }
    3508:     }
    3509:   } else {
    3510:     PetscSectionGetConstraintIndices(section, point, &cdofs);
    3511:     if (orientation >= 0) {
    3512:       for (k = 0; k < dof; ++k) {
    3513:         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    3514:         fuse(&a[k], values[k]);
    3515:       }
    3516:     } else {
    3517:       for (k = 0; k < dof; ++k) {
    3518:         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    3519:         fuse(&a[k], values[dof-k-1]);
    3520:       }
    3521:     }
    3522:   }
    3523:   return(0);
    3524: }

    3528: PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
    3529: {
    3530:   PetscInt        cdof;   /* The number of constraints on this point */
    3531:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
    3532:   PetscScalar    *a;
    3533:   PetscInt        off, cind = 0, k;
    3534:   PetscErrorCode  ierr;

    3537:   PetscSectionGetConstraintDof(section, point, &cdof);
    3538:   PetscSectionGetOffset(section, point, &off);
    3539:   a    = &array[off];
    3540:   if (cdof) {
    3541:     PetscSectionGetConstraintIndices(section, point, &cdofs);
    3542:     if (orientation >= 0) {
    3543:       for (k = 0; k < dof; ++k) {
    3544:         if ((cind < cdof) && (k == cdofs[cind])) {
    3545:           fuse(&a[k], values[k]);
    3546:           ++cind;
    3547:         }
    3548:       }
    3549:     } else {
    3550:       for (k = 0; k < dof; ++k) {
    3551:         if ((cind < cdof) && (k == cdofs[cind])) {
    3552:           fuse(&a[k], values[dof-k-1]);
    3553:           ++cind;
    3554:         }
    3555:       }
    3556:     }
    3557:   }
    3558:   return(0);
    3559: }

    3563: PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscScalar values[], PetscInt *offset, PetscScalar array[])
    3564: {
    3565:   PetscScalar    *a;
    3566:   PetscInt        fdof, foff, fcdof, foffset = *offset;
    3567:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
    3568:   PetscInt        cind = 0, k, c;
    3569:   PetscErrorCode  ierr;

    3572:   PetscSectionGetFieldDof(section, point, f, &fdof);
    3573:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
    3574:   PetscSectionGetFieldOffset(section, point, f, &foff);
    3575:   a    = &array[foff];
    3576:   if (!fcdof || setBC) {
    3577:     if (o >= 0) {
    3578:       for (k = 0; k < fdof; ++k) fuse(&a[k], values[foffset+k]);
    3579:     } else {
    3580:       for (k = fdof/fcomp-1; k >= 0; --k) {
    3581:         for (c = 0; c < fcomp; ++c) {
    3582:           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
    3583:         }
    3584:       }
    3585:     }
    3586:   } else {
    3587:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
    3588:     if (o >= 0) {
    3589:       for (k = 0; k < fdof; ++k) {
    3590:         if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
    3591:         fuse(&a[k], values[foffset+k]);
    3592:       }
    3593:     } else {
    3594:       for (k = fdof/fcomp-1; k >= 0; --k) {
    3595:         for (c = 0; c < fcomp; ++c) {
    3596:           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
    3597:           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
    3598:         }
    3599:       }
    3600:     }
    3601:   }
    3602:   *offset += fdof;
    3603:   return(0);
    3604: }

    3608: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), const PetscScalar values[], PetscInt *offset, PetscScalar array[])
    3609: {
    3610:   PetscScalar    *a;
    3611:   PetscInt        fdof, foff, fcdof, foffset = *offset;
    3612:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
    3613:   PetscInt        cind = 0, k, c;
    3614:   PetscErrorCode  ierr;

    3617:   PetscSectionGetFieldDof(section, point, f, &fdof);
    3618:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
    3619:   PetscSectionGetFieldOffset(section, point, f, &foff);
    3620:   a    = &array[foff];
    3621:   if (fcdof) {
    3622:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
    3623:     if (o >= 0) {
    3624:       for (k = 0; k < fdof; ++k) {
    3625:         if ((cind < fcdof) && (k == fcdofs[cind])) {
    3626:           fuse(&a[k], values[foffset+k]);
    3627:           ++cind;
    3628:         }
    3629:       }
    3630:     } else {
    3631:       for (k = fdof/fcomp-1; k >= 0; --k) {
    3632:         for (c = 0; c < fcomp; ++c) {
    3633:           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
    3634:             fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
    3635:             ++cind;
    3636:           }
    3637:         }
    3638:       }
    3639:     }
    3640:   }
    3641:   *offset += fdof;
    3642:   return(0);
    3643: }

    3647: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
    3648: {
    3649:   PetscScalar    *array;
    3650:   const PetscInt *cone, *coneO;
    3651:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
    3652:   PetscErrorCode  ierr;

    3655:   PetscSectionGetChart(section, &pStart, &pEnd);
    3656:   DMPlexGetConeSize(dm, point, &numPoints);
    3657:   DMPlexGetCone(dm, point, &cone);
    3658:   DMPlexGetConeOrientation(dm, point, &coneO);
    3659:   VecGetArray(v, &array);
    3660:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
    3661:     const PetscInt cp = !p ? point : cone[p-1];
    3662:     const PetscInt o  = !p ? 0     : coneO[p-1];

    3664:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
    3665:     PetscSectionGetDof(section, cp, &dof);
    3666:     /* ADD_VALUES */
    3667:     {
    3668:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
    3669:       PetscScalar    *a;
    3670:       PetscInt        cdof, coff, cind = 0, k;

    3672:       PetscSectionGetConstraintDof(section, cp, &cdof);
    3673:       PetscSectionGetOffset(section, cp, &coff);
    3674:       a    = &array[coff];
    3675:       if (!cdof) {
    3676:         if (o >= 0) {
    3677:           for (k = 0; k < dof; ++k) {
    3678:             a[k] += values[off+k];
    3679:           }
    3680:         } else {
    3681:           for (k = 0; k < dof; ++k) {
    3682:             a[k] += values[off+dof-k-1];
    3683:           }
    3684:         }
    3685:       } else {
    3686:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
    3687:         if (o >= 0) {
    3688:           for (k = 0; k < dof; ++k) {
    3689:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    3690:             a[k] += values[off+k];
    3691:           }
    3692:         } else {
    3693:           for (k = 0; k < dof; ++k) {
    3694:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
    3695:             a[k] += values[off+dof-k-1];
    3696:           }
    3697:         }
    3698:       }
    3699:     }
    3700:   }
    3701:   VecRestoreArray(v, &array);
    3702:   return(0);
    3703: }

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

    3710:   Not collective

    3712:   Input Parameters:
    3713: + dm - The DM
    3714: . section - The section describing the layout in v, or NULL to use the default section
    3715: . v - The local vector
    3716: . point - The sieve point in the DM
    3717: . values - The array of values
    3718: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

    3723:   Level: intermediate

    3725: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
    3726: @*/
    3727: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
    3728: {
    3729:   PetscSection    clSection;
    3730:   IS              clPoints;
    3731:   PetscScalar    *array;
    3732:   PetscInt       *points = NULL;
    3733:   const PetscInt *clp;
    3734:   PetscInt        depth, numFields, numPoints, p;
    3735:   PetscErrorCode  ierr;

    3739:   if (!section) {DMGetDefaultSection(dm, &section);}
    3742:   DMPlexGetDepth(dm, &depth);
    3743:   PetscSectionGetNumFields(section, &numFields);
    3744:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
    3745:     DMPlexVecSetClosure_Static(dm, section, v, point, values, mode);
    3746:     return(0);
    3747:   }
    3748:   /* Get points */
    3749:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
    3750:   if (!clPoints) {
    3751:     PetscInt pStart, pEnd, q;

    3753:     PetscSectionGetChart(section, &pStart, &pEnd);
    3754:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
    3755:     /* Compress out points not in the section */
    3756:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
    3757:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
    3758:         points[q*2]   = points[p];
    3759:         points[q*2+1] = points[p+1];
    3760:         ++q;
    3761:       }
    3762:     }
    3763:     numPoints = q;
    3764:   } else {
    3765:     PetscInt dof, off;

    3767:     PetscSectionGetDof(clSection, point, &dof);
    3768:     PetscSectionGetOffset(clSection, point, &off);
    3769:     ISGetIndices(clPoints, &clp);
    3770:     numPoints = dof/2;
    3771:     points    = (PetscInt *) &clp[off];
    3772:   }
    3773:   /* Get array */
    3774:   VecGetArray(v, &array);
    3775:   /* Get values */
    3776:   if (numFields > 0) {
    3777:     PetscInt offset = 0, fcomp, f;
    3778:     for (f = 0; f < numFields; ++f) {
    3779:       PetscSectionGetFieldComponents(section, f, &fcomp);
    3780:       switch (mode) {
    3781:       case INSERT_VALUES:
    3782:         for (p = 0; p < numPoints*2; p += 2) {
    3783:           const PetscInt point = points[p];
    3784:           const PetscInt o     = points[p+1];
    3785:           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array);
    3786:         } break;
    3787:       case INSERT_ALL_VALUES:
    3788:         for (p = 0; p < numPoints*2; p += 2) {
    3789:           const PetscInt point = points[p];
    3790:           const PetscInt o     = points[p+1];
    3791:           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array);
    3792:         } break;
    3793:       case INSERT_BC_VALUES:
    3794:         for (p = 0; p < numPoints*2; p += 2) {
    3795:           const PetscInt point = points[p];
    3796:           const PetscInt o     = points[p+1];
    3797:           updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array);
    3798:         } break;
    3799:       case ADD_VALUES:
    3800:         for (p = 0; p < numPoints*2; p += 2) {
    3801:           const PetscInt point = points[p];
    3802:           const PetscInt o     = points[p+1];
    3803:           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array);
    3804:         } break;
    3805:       case ADD_ALL_VALUES:
    3806:         for (p = 0; p < numPoints*2; p += 2) {
    3807:           const PetscInt point = points[p];
    3808:           const PetscInt o     = points[p+1];
    3809:           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array);
    3810:         } break;
    3811:       default:
    3812:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
    3813:       }
    3814:     }
    3815:   } else {
    3816:     PetscInt dof, off;

    3818:     switch (mode) {
    3819:     case INSERT_VALUES:
    3820:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
    3821:         PetscInt o = points[p+1];
    3822:         PetscSectionGetDof(section, points[p], &dof);
    3823:         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
    3824:       } break;
    3825:     case INSERT_ALL_VALUES:
    3826:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
    3827:         PetscInt o = points[p+1];
    3828:         PetscSectionGetDof(section, points[p], &dof);
    3829:         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
    3830:       } break;
    3831:     case INSERT_BC_VALUES:
    3832:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
    3833:         PetscInt o = points[p+1];
    3834:         PetscSectionGetDof(section, points[p], &dof);
    3835:         updatePointBC_private(section, points[p], dof, insert,  o, &values[off], array);
    3836:       } break;
    3837:     case ADD_VALUES:
    3838:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
    3839:         PetscInt o = points[p+1];
    3840:         PetscSectionGetDof(section, points[p], &dof);
    3841:         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
    3842:       } break;
    3843:     case ADD_ALL_VALUES:
    3844:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
    3845:         PetscInt o = points[p+1];
    3846:         PetscSectionGetDof(section, points[p], &dof);
    3847:         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
    3848:       } break;
    3849:     default:
    3850:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
    3851:     }
    3852:   }
    3853:   /* Cleanup points */
    3854:   if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
    3855:   else           {ISRestoreIndices(clPoints, &clp);}
    3856:   /* Cleanup array */
    3857:   VecRestoreArray(v, &array);
    3858:   return(0);
    3859: }

    3863: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
    3864: {
    3865:   PetscSection    clSection;
    3866:   IS              clPoints;
    3867:   PetscScalar    *array;
    3868:   PetscInt       *points = NULL;
    3869:   const PetscInt *clp;
    3870:   PetscInt        numFields, numPoints, p;
    3871:   PetscInt        offset = 0, fcomp, f;
    3872:   PetscErrorCode  ierr;

    3876:   if (!section) {DMGetDefaultSection(dm, &section);}
    3879:   PetscSectionGetNumFields(section, &numFields);
    3880:   /* Get points */
    3881:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
    3882:   if (!clPoints) {
    3883:     PetscInt pStart, pEnd, q;

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

    3899:     PetscSectionGetDof(clSection, point, &dof);
    3900:     PetscSectionGetOffset(clSection, point, &off);
    3901:     ISGetIndices(clPoints, &clp);
    3902:     numPoints = dof/2;
    3903:     points    = (PetscInt *) &clp[off];
    3904:   }
    3905:   /* Get array */
    3906:   VecGetArray(v, &array);
    3907:   /* Get values */
    3908:   for (f = 0; f < numFields; ++f) {
    3909:     PetscSectionGetFieldComponents(section, f, &fcomp);
    3910:     if (!fieldActive[f]) {
    3911:       for (p = 0; p < numPoints*2; p += 2) {
    3912:         PetscInt fdof;
    3913:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
    3914:         offset += fdof;
    3915:       }
    3916:       continue;
    3917:     }
    3918:     switch (mode) {
    3919:     case INSERT_VALUES:
    3920:       for (p = 0; p < numPoints*2; p += 2) {
    3921:         const PetscInt point = points[p];
    3922:         const PetscInt o     = points[p+1];
    3923:         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array);
    3924:       } break;
    3925:     case INSERT_ALL_VALUES:
    3926:       for (p = 0; p < numPoints*2; p += 2) {
    3927:         const PetscInt point = points[p];
    3928:         const PetscInt o     = points[p+1];
    3929:         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array);
    3930:         } break;
    3931:     case INSERT_BC_VALUES:
    3932:       for (p = 0; p < numPoints*2; p += 2) {
    3933:         const PetscInt point = points[p];
    3934:         const PetscInt o     = points[p+1];
    3935:         updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array);
    3936:       } break;
    3937:     case ADD_VALUES:
    3938:       for (p = 0; p < numPoints*2; p += 2) {
    3939:         const PetscInt point = points[p];
    3940:         const PetscInt o     = points[p+1];
    3941:         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array);
    3942:       } break;
    3943:     case ADD_ALL_VALUES:
    3944:       for (p = 0; p < numPoints*2; p += 2) {
    3945:         const PetscInt point = points[p];
    3946:         const PetscInt o     = points[p+1];
    3947:         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array);
    3948:       } break;
    3949:     default:
    3950:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
    3951:     }
    3952:   }
    3953:   /* Cleanup points */
    3954:   if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
    3955:   else           {ISRestoreIndices(clPoints, &clp);}
    3956:   /* Cleanup array */
    3957:   VecRestoreArray(v, &array);
    3958:   return(0);
    3959: }

    3963: PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
    3964: {
    3965:   PetscMPIInt    rank;
    3966:   PetscInt       i, j;

    3970:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
    3971:   PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);
    3972:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
    3973:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
    3974:   numCIndices = numCIndices ? numCIndices : numRIndices;
    3975:   for (i = 0; i < numRIndices; i++) {
    3976:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
    3977:     for (j = 0; j < numCIndices; j++) {
    3978: #if defined(PETSC_USE_COMPLEX)
    3979:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
    3980: #else
    3981:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
    3982: #endif
    3983:     }
    3984:     PetscViewerASCIIPrintf(viewer, "\n");
    3985:   }
    3986:   return(0);
    3987: }

    3991: /* . off - The global offset of this point */
    3992: PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
    3993: {
    3994:   PetscInt        dof;    /* The number of unknowns on this point */
    3995:   PetscInt        cdof;   /* The number of constraints on this point */
    3996:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
    3997:   PetscInt        cind = 0, k;
    3998:   PetscErrorCode  ierr;

    4001:   PetscSectionGetDof(section, point, &dof);
    4002:   PetscSectionGetConstraintDof(section, point, &cdof);
    4003:   if (!cdof || setBC) {
    4004:     if (orientation >= 0) {
    4005:       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
    4006:     } else {
    4007:       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
    4008:     }
    4009:   } else {
    4010:     PetscSectionGetConstraintIndices(section, point, &cdofs);
    4011:     if (orientation >= 0) {
    4012:       for (k = 0; k < dof; ++k) {
    4013:         if ((cind < cdof) && (k == cdofs[cind])) {
    4014:           /* Insert check for returning constrained indices */
    4015:           indices[*loff+k] = -(off+k+1);
    4016:           ++cind;
    4017:         } else {
    4018:           indices[*loff+k] = off+k-cind;
    4019:         }
    4020:       }
    4021:     } else {
    4022:       for (k = 0; k < dof; ++k) {
    4023:         if ((cind < cdof) && (k == cdofs[cind])) {
    4024:           /* Insert check for returning constrained indices */
    4025:           indices[*loff+dof-k-1] = -(off+k+1);
    4026:           ++cind;
    4027:         } else {
    4028:           indices[*loff+dof-k-1] = off+k-cind;
    4029:         }
    4030:       }
    4031:     }
    4032:   }
    4033:   *loff += dof;
    4034:   return(0);
    4035: }

    4039: /* . off - The global offset of this point */
    4040: PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
    4041: {
    4042:   PetscInt       numFields, foff, f;

    4046:   PetscSectionGetNumFields(section, &numFields);
    4047:   for (f = 0, foff = 0; f < numFields; ++f) {
    4048:     PetscInt        fdof, fcomp, cfdof;
    4049:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
    4050:     PetscInt        cind = 0, k, c;

    4052:     PetscSectionGetFieldComponents(section, f, &fcomp);
    4053:     PetscSectionGetFieldDof(section, point, f, &fdof);
    4054:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
    4055:     if (!cfdof || setBC) {
    4056:       if (orientation >= 0) {
    4057:         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
    4058:       } else {
    4059:         for (k = fdof/fcomp-1; k >= 0; --k) {
    4060:           for (c = 0; c < fcomp; ++c) {
    4061:             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
    4062:           }
    4063:         }
    4064:       }
    4065:     } else {
    4066:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
    4067:       if (orientation >= 0) {
    4068:         for (k = 0; k < fdof; ++k) {
    4069:           if ((cind < cfdof) && (k == fcdofs[cind])) {
    4070:             indices[foffs[f]+k] = -(off+foff+k+1);
    4071:             ++cind;
    4072:           } else {
    4073:             indices[foffs[f]+k] = off+foff+k-cind;
    4074:           }
    4075:         }
    4076:       } else {
    4077:         for (k = fdof/fcomp-1; k >= 0; --k) {
    4078:           for (c = 0; c < fcomp; ++c) {
    4079:             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
    4080:               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
    4081:               ++cind;
    4082:             } else {
    4083:               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
    4084:             }
    4085:           }
    4086:         }
    4087:       }
    4088:     }
    4089:     foff     += fdof - cfdof;
    4090:     foffs[f] += fdof;
    4091:   }
    4092:   return(0);
    4093: }

    4097: static PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[])
    4098: {
    4099:   Mat             cMat;
    4100:   PetscSection    aSec, cSec;
    4101:   IS              aIS;
    4102:   PetscInt        aStart = -1, aEnd = -1;
    4103:   const PetscInt  *anchors;
    4104:   PetscInt        numFields, f, p, q, newP = 0;
    4105:   PetscInt        newNumPoints = 0, newNumIndices = 0;
    4106:   PetscInt        *newPoints, *indices, *newIndices;
    4107:   PetscInt        maxAnchor, maxDof;
    4108:   PetscInt        newOffsets[32];
    4109:   PetscInt        *pointMatOffsets[32];
    4110:   PetscInt        *newPointOffsets[32];
    4111:   PetscScalar     *pointMat[32];
    4112:   PetscScalar     *newValues,*tmpValues;
    4113:   PetscBool       anyConstrained = PETSC_FALSE;
    4114:   PetscErrorCode  ierr;

    4119:   PetscSectionGetNumFields(section, &numFields);

    4121:   DMPlexGetAnchors(dm,&aSec,&aIS);
    4122:   /* if there are point-to-point constraints */
    4123:   if (aSec) {
    4124:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
    4125:     ISGetIndices(aIS,&anchors);
    4126:     PetscSectionGetChart(aSec,&aStart,&aEnd);
    4127:     /* figure out how many points are going to be in the new element matrix
    4128:      * (we allow double counting, because it's all just going to be summed
    4129:      * into the global matrix anyway) */
    4130:     for (p = 0; p < 2*numPoints; p+=2) {
    4131:       PetscInt b    = points[p];
    4132:       PetscInt bDof = 0;

    4134:       if (b >= aStart && b < aEnd) {
    4135:         PetscSectionGetDof(aSec,b,&bDof);
    4136:       }
    4137:       if (bDof) {
    4138:         /* this point is constrained */
    4139:         /* it is going to be replaced by its anchors */
    4140:         PetscInt bOff, q;

    4142:         anyConstrained = PETSC_TRUE;
    4143:         newNumPoints  += bDof;
    4144:         PetscSectionGetOffset(aSec,b,&bOff);
    4145:         for (q = 0; q < bDof; q++) {
    4146:           PetscInt a = anchors[bOff + q];
    4147:           PetscInt aDof;

    4149:           PetscSectionGetDof(section,a,&aDof);
    4150:           newNumIndices += aDof;
    4151:           for (f = 0; f < numFields; ++f) {
    4152:             PetscInt fDof;

    4154:             PetscSectionGetFieldDof(section, a, f, &fDof);
    4155:             newOffsets[f+1] += fDof;
    4156:           }
    4157:         }
    4158:       }
    4159:       else {
    4160:         /* this point is not constrained */
    4161:         newNumPoints++;
    4162:         PetscSectionGetDof(section,b,&bDof);
    4163:         newNumIndices += bDof;
    4164:         for (f = 0; f < numFields; ++f) {
    4165:           PetscInt fDof;

    4167:           PetscSectionGetFieldDof(section, b, f, &fDof);
    4168:           newOffsets[f+1] += fDof;
    4169:         }
    4170:       }
    4171:     }
    4172:   }
    4173:   if (!anyConstrained) {
    4174:     *outNumPoints  = 0;
    4175:     *outNumIndices = 0;
    4176:     *outPoints     = NULL;
    4177:     *outValues     = NULL;
    4178:     if (aSec) {
    4179:       ISRestoreIndices(aIS,&anchors);
    4180:     }
    4181:     return(0);
    4182:   }

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

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

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

    4190:   /* output arrays */
    4191:   DMGetWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
    4192:   DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);

    4194:   /* workspaces */
    4195:   DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
    4196:   if (numFields) {
    4197:     for (f = 0; f < numFields; f++) {
    4198:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
    4199:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
    4200:     }
    4201:   }
    4202:   else {
    4203:     DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
    4204:     DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
    4205:   }

    4207:   /* get workspaces for the point-to-point matrices */
    4208:   if (numFields) {
    4209:     for (p = 0; p < numPoints; p++) {
    4210:       PetscInt b    = points[2*p];
    4211:       PetscInt bDof = 0;

    4213:       if (b >= aStart && b < aEnd) {
    4214:         PetscSectionGetDof(aSec, b, &bDof);
    4215:       }
    4216:       if (bDof) {
    4217:         for (f = 0; f < numFields; f++) {
    4218:           PetscInt fDof, q, bOff, allFDof = 0;

    4220:           PetscSectionGetFieldDof(section, b, f, &fDof);
    4221:           PetscSectionGetOffset(aSec, b, &bOff);
    4222:           for (q = 0; q < bDof; q++) {
    4223:             PetscInt a = anchors[bOff + q];
    4224:             PetscInt aFDof;

    4226:             PetscSectionGetFieldDof(section, a, f, &aFDof);
    4227:             allFDof += aFDof;
    4228:           }
    4229:           newPointOffsets[f][p+1] = allFDof;
    4230:           pointMatOffsets[f][p+1] = fDof * allFDof;
    4231:         }
    4232:       }
    4233:       else {
    4234:         for (f = 0; f < numFields; f++) {
    4235:           PetscInt fDof;

    4237:           PetscSectionGetFieldDof(section, b, f, &fDof);
    4238:           newPointOffsets[f][p+1] = fDof;
    4239:           pointMatOffsets[f][p+1] = 0;
    4240:         }
    4241:       }
    4242:     }
    4243:     for (f = 0; f < numFields; f++) {
    4244:       newPointOffsets[f][0] = 0;
    4245:       pointMatOffsets[f][0] = 0;
    4246:       for (p = 0; p < numPoints; p++) {
    4247:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
    4248:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
    4249:       }
    4250:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
    4251:     }
    4252:   }
    4253:   else {
    4254:     for (p = 0; p < numPoints; p++) {
    4255:       PetscInt b    = points[2*p];
    4256:       PetscInt bDof = 0;

    4258:       if (b >= aStart && b < aEnd) {
    4259:         PetscSectionGetDof(aSec, b, &bDof);
    4260:       }
    4261:       if (bDof) {
    4262:         PetscInt dof, bOff, q, allDof = 0;

    4264:         PetscSectionGetDof(section, b, &dof);
    4265:         PetscSectionGetOffset(aSec, b, &bOff);
    4266:         for (q = 0; q < bDof; q++) {
    4267:           PetscInt a = anchors[bOff + q], aDof;

    4269:           PetscSectionGetDof(section, a, &aDof);
    4270:           allDof += aDof;
    4271:         }
    4272:         newPointOffsets[0][p+1] = allDof;
    4273:         pointMatOffsets[0][p+1] = dof * allDof;
    4274:       }
    4275:       else {
    4276:         PetscInt dof;

    4278:         PetscSectionGetDof(section, b, &dof);
    4279:         newPointOffsets[0][p+1] = dof;
    4280:         pointMatOffsets[0][p+1] = 0;
    4281:       }
    4282:     }
    4283:     newPointOffsets[0][0] = 0;
    4284:     pointMatOffsets[0][0] = 0;
    4285:     for (p = 0; p < numPoints; p++) {
    4286:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
    4287:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
    4288:     }
    4289:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
    4290:   }

    4292:   /* get the point-to-point matrices; construct newPoints */
    4293:   PetscSectionGetMaxDof(aSec, &maxAnchor);
    4294:   PetscSectionGetMaxDof(section, &maxDof);
    4295:   DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
    4296:   DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
    4297:   if (numFields) {
    4298:     for (p = 0, newP = 0; p < numPoints; p++) {
    4299:       PetscInt b    = points[2*p];
    4300:       PetscInt o    = points[2*p+1];
    4301:       PetscInt bDof = 0;

    4303:       if (b >= aStart && b < aEnd) {
    4304:         PetscSectionGetDof(aSec, b, &bDof);
    4305:       }
    4306:       if (bDof) {
    4307:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

    4309:         fStart[0] = 0;
    4310:         fEnd[0]   = 0;
    4311:         for (f = 0; f < numFields; f++) {
    4312:           PetscInt fDof;

    4314:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
    4315:           fStart[f+1] = fStart[f] + fDof;
    4316:           fEnd[f+1]   = fStart[f+1];
    4317:         }
    4318:         PetscSectionGetOffset(cSec, b, &bOff);
    4319:         indicesPointFields_private(cSec, b, bOff, fEnd, PETSC_TRUE, o, indices);

    4321:         fAnchorStart[0] = 0;
    4322:         fAnchorEnd[0]   = 0;
    4323:         for (f = 0; f < numFields; f++) {
    4324:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

    4326:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
    4327:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
    4328:         }
    4329:         PetscSectionGetOffset (aSec, b, &bOff);
    4330:         for (q = 0; q < bDof; q++) {
    4331:           PetscInt a = anchors[bOff + q], aOff;

    4333:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
    4334:           newPoints[2*(newP + q)]     = a;
    4335:           newPoints[2*(newP + q) + 1] = 0;
    4336:           PetscSectionGetOffset(section, a, &aOff);
    4337:           indicesPointFields_private(section, a, aOff, fAnchorEnd, PETSC_TRUE, 0, newIndices);
    4338:         }
    4339:         newP += bDof;

    4341:         /* get the point-to-point submatrix */
    4342:         for (f = 0; f < numFields; f++) {
    4343:           MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
    4344:         }
    4345:       }
    4346:       else {
    4347:         newPoints[2 * newP]     = b;
    4348:         newPoints[2 * newP + 1] = o;
    4349:         newP++;
    4350:       }
    4351:     }
    4352:   } else {
    4353:     for (p = 0; p < numPoints; p++) {
    4354:       PetscInt b    = points[2*p];
    4355:       PetscInt o    = points[2*p+1];
    4356:       PetscInt bDof = 0;

    4358:       if (b >= aStart && b < aEnd) {
    4359:         PetscSectionGetDof(aSec, b, &bDof);
    4360:       }
    4361:       if (bDof) {
    4362:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

    4364:         PetscSectionGetOffset(cSec, b, &bOff);
    4365:         indicesPoint_private(cSec, b, bOff, &bEnd, PETSC_TRUE, o, indices);

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

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

    4373:           newPoints[2*(newP + q)]     = a;
    4374:           newPoints[2*(newP + q) + 1] = 0;
    4375:           PetscSectionGetOffset(section, a, &aOff);
    4376:           indicesPoint_private(section, a, aOff, &bAnchorEnd, PETSC_TRUE, 0, newIndices);
    4377:         }
    4378:         newP += bDof;

    4380:         /* get the point-to-point submatrix */
    4381:         MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
    4382:       }
    4383:       else {
    4384:         newPoints[2 * newP]     = b;
    4385:         newPoints[2 * newP + 1] = o;
    4386:         newP++;
    4387:       }
    4388:     }
    4389:   }

    4391:   PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
    4392:   /* multiply constraints on the right */
    4393:   if (numFields) {
    4394:     for (f = 0; f < numFields; f++) {
    4395:       PetscInt oldOff = offsets[f];

    4397:       for (p = 0; p < numPoints; p++) {
    4398:         PetscInt cStart = newPointOffsets[f][p];
    4399:         PetscInt b      = points[2 * p];
    4400:         PetscInt c, r, k;
    4401:         PetscInt dof;

    4403:         PetscSectionGetFieldDof(section,b,f,&dof);
    4404:         if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
    4405:           PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
    4406:           const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

    4408:           for (r = 0; r < numIndices; r++) {
    4409:             for (c = 0; c < nCols; c++) {
    4410:               for (k = 0; k < dof; k++) {
    4411:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
    4412:               }
    4413:             }
    4414:           }
    4415:         }
    4416:         else {
    4417:           /* copy this column as is */
    4418:           for (r = 0; r < numIndices; r++) {
    4419:             for (c = 0; c < dof; c++) {
    4420:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
    4421:             }
    4422:           }
    4423:         }
    4424:         oldOff += dof;
    4425:       }
    4426:     }
    4427:   }
    4428:   else {
    4429:     PetscInt oldOff = 0;
    4430:     for (p = 0; p < numPoints; p++) {
    4431:       PetscInt cStart = newPointOffsets[0][p];
    4432:       PetscInt b      = points[2 * p];
    4433:       PetscInt c, r, k;
    4434:       PetscInt dof;

    4436:       PetscSectionGetDof(section,b,&dof);
    4437:       if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
    4438:         PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
    4439:         const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

    4441:         for (r = 0; r < numIndices; r++) {
    4442:           for (c = 0; c < nCols; c++) {
    4443:             for (k = 0; k < dof; k++) {
    4444:               tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
    4445:             }
    4446:           }
    4447:         }
    4448:       }
    4449:       else {
    4450:         /* copy this column as is */
    4451:         for (r = 0; r < numIndices; r++) {
    4452:           for (c = 0; c < dof; c++) {
    4453:             tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
    4454:           }
    4455:         }
    4456:       }
    4457:       oldOff += dof;
    4458:     }
    4459:   }

    4461:   PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
    4462:   /* multiply constraints transpose on the left */
    4463:   if (numFields) {
    4464:     for (f = 0; f < numFields; f++) {
    4465:       PetscInt oldOff = offsets[f];

    4467:       for (p = 0; p < numPoints; p++) {
    4468:         PetscInt rStart = newPointOffsets[f][p];
    4469:         PetscInt b      = points[2 * p];
    4470:         PetscInt c, r, k;
    4471:         PetscInt dof;

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

    4478:           for (r = 0; r < nRows; r++) {
    4479:             for (c = 0; c < newNumIndices; c++) {
    4480:               for (k = 0; k < dof; k++) {
    4481:                 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
    4482:               }
    4483:             }
    4484:           }
    4485:         }
    4486:         else {
    4487:           /* copy this row as is */
    4488:           for (r = 0; r < dof; r++) {
    4489:             for (c = 0; c < newNumIndices; c++) {
    4490:               newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
    4491:             }
    4492:           }
    4493:         }
    4494:         oldOff += dof;
    4495:       }
    4496:     }
    4497:   }
    4498:   else {
    4499:     PetscInt oldOff = 0;

    4501:     for (p = 0; p < numPoints; p++) {
    4502:       PetscInt rStart = newPointOffsets[0][p];
    4503:       PetscInt b      = points[2 * p];
    4504:       PetscInt c, r, k;
    4505:       PetscInt dof;

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

    4512:         for (r = 0; r < nRows; r++) {
    4513:           for (c = 0; c < newNumIndices; c++) {
    4514:             for (k = 0; k < dof; k++) {
    4515:               newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
    4516:             }
    4517:           }
    4518:         }
    4519:       }
    4520:       else {
    4521:         /* copy this row as is */
    4522:         for (r = 0; r < dof; c++) {
    4523:           for (c = 0; c < newNumIndices; c++) {
    4524:             newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
    4525:           }
    4526:         }
    4527:       }
    4528:       oldOff += dof;
    4529:     }
    4530:   }

    4532:   /* clean up */
    4533:   DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
    4534:   DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
    4535:   if (numFields) {
    4536:     for (f = 0; f < numFields; f++) {
    4537:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
    4538:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
    4539:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
    4540:     }
    4541:   }
    4542:   else {
    4543:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
    4544:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
    4545:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
    4546:   }
    4547:   DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
    4548:   ISRestoreIndices(aIS,&anchors);

    4550:   /* output */
    4551:   *outNumPoints  = newNumPoints;
    4552:   *outNumIndices = newNumIndices;
    4553:   *outPoints     = newPoints;
    4554:   *outValues     = newValues;
    4555:   for (f = 0; f < numFields; f++) {
    4556:     offsets[f] = newOffsets[f];
    4557:   }
    4558:   return(0);
    4559: }

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

    4566:   Not collective

    4568:   Input Parameters:
    4569: + dm - The DM
    4570: . section - The section describing the layout in v, or NULL to use the default section
    4571: . globalSection - The section describing the layout in v, or NULL to use the default global section
    4572: . A - The matrix
    4573: . point - The sieve point in the DM
    4574: . values - The array of values
    4575: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

    4580:   Level: intermediate

    4582: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
    4583: @*/
    4584: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
    4585: {
    4586:   DM_Plex        *mesh   = (DM_Plex*) dm->data;
    4587:   PetscSection    clSection;
    4588:   IS              clPoints;
    4589:   PetscInt       *points = NULL, *newPoints;
    4590:   const PetscInt *clp;
    4591:   PetscInt       *indices;
    4592:   PetscInt        offsets[32];
    4593:   PetscInt        numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
    4594:   PetscScalar    *newValues;
    4595:   PetscErrorCode  ierr;

    4599:   if (!section) {DMGetDefaultSection(dm, &section);}
    4601:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
    4604:   PetscSectionGetNumFields(section, &numFields);
    4605:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
    4606:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
    4607:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
    4608:   if (!clPoints) {
    4609:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
    4610:     /* Compress out points not in the section */
    4611:     PetscSectionGetChart(section, &pStart, &pEnd);
    4612:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
    4613:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
    4614:         points[q*2]   = points[p];
    4615:         points[q*2+1] = points[p+1];
    4616:         ++q;
    4617:       }
    4618:     }
    4619:     numPoints = q;
    4620:   } else {
    4621:     PetscInt dof, off;

    4623:     PetscSectionGetDof(clSection, point, &dof);
    4624:     numPoints = dof/2;
    4625:     PetscSectionGetOffset(clSection, point, &off);
    4626:     ISGetIndices(clPoints, &clp);
    4627:     points = (PetscInt *) &clp[off];
    4628:   }
    4629:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
    4630:     PetscInt fdof;

    4632:     PetscSectionGetDof(section, points[p], &dof);
    4633:     for (f = 0; f < numFields; ++f) {
    4634:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
    4635:       offsets[f+1] += fdof;
    4636:     }
    4637:     numIndices += dof;
    4638:   }
    4639:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

    4641:   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
    4642:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets);
    4643:   if (newNumPoints) {
    4644:     if (!clPoints) {
    4645:       DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
    4646:     } else {
    4647:       ISRestoreIndices(clPoints, &clp);
    4648:     }
    4649:     numPoints  = newNumPoints;
    4650:     numIndices = newNumIndices;
    4651:     points     = newPoints;
    4652:     values     = newValues;
    4653:   }
    4654:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
    4655:   if (numFields) {
    4656:     for (p = 0; p < numPoints*2; p += 2) {
    4657:       PetscInt o = points[p+1];
    4658:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
    4659:       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
    4660:     }
    4661:   } else {
    4662:     for (p = 0, off = 0; p < numPoints*2; p += 2) {
    4663:       PetscInt o = points[p+1];
    4664:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
    4665:       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
    4666:     }
    4667:   }
    4668:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
    4669:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
    4670:   if (mesh->printFEM > 1) {
    4671:     PetscInt i;
    4672:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
    4673:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %d", indices[i]);}
    4674:     PetscPrintf(PETSC_COMM_SELF, "\n");
    4675:   }
    4676:   if (ierr) {
    4677:     PetscMPIInt    rank;
    4678:     PetscErrorCode ierr2;

    4680:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
    4681:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
    4682:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
    4683:     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
    4684:
    4685:   }
    4686:   if (newNumPoints) {
    4687:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
    4688:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
    4689:   }
    4690:   else {
    4691:     if (!clPoints) {
    4692:       DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
    4693:     } else {
    4694:       ISRestoreIndices(clPoints, &clp);
    4695:     }
    4696:   }
    4697:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
    4698:   return(0);
    4699: }

    4703: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
    4704: {
    4705:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
    4706:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
    4707:   PetscInt       *cpoints = NULL;
    4708:   PetscInt       *findices, *cindices;
    4709:   PetscInt        foffsets[32], coffsets[32];
    4710:   CellRefiner     cellRefiner;
    4711:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
    4712:   PetscErrorCode  ierr;

    4717:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
    4719:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
    4721:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
    4723:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
    4726:   PetscSectionGetNumFields(fsection, &numFields);
    4727:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
    4728:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
    4729:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
    4730:   /* Column indices */
    4731:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
    4732:   maxFPoints = numCPoints;
    4733:   /* Compress out points not in the section */
    4734:   /*   TODO: Squeeze out points with 0 dof as well */
    4735:   PetscSectionGetChart(csection, &pStart, &pEnd);
    4736:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
    4737:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
    4738:       cpoints[q*2]   = cpoints[p];
    4739:       cpoints[q*2+1] = cpoints[p+1];
    4740:       ++q;
    4741:     }
    4742:   }
    4743:   numCPoints = q;
    4744:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
    4745:     PetscInt fdof;

    4747:     PetscSectionGetDof(csection, cpoints[p], &dof);
    4748:     if (!dof) continue;
    4749:     for (f = 0; f < numFields; ++f) {
    4750:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
    4751:       coffsets[f+1] += fdof;
    4752:     }
    4753:     numCIndices += dof;
    4754:   }
    4755:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
    4756:   /* Row indices */
    4757:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
    4758:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
    4759:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
    4760:   for (r = 0, q = 0; r < numSubcells; ++r) {
    4761:     /* TODO Map from coarse to fine cells */
    4762:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
    4763:     /* Compress out points not in the section */
    4764:     PetscSectionGetChart(fsection, &pStart, &pEnd);
    4765:     for (p = 0; p < numFPoints*2; p += 2) {
    4766:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
    4767:         PetscSectionGetDof(fsection, fpoints[p], &dof);
    4768:         if (!dof) continue;
    4769:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
    4770:         if (s < q) continue;
    4771:         ftotpoints[q*2]   = fpoints[p];
    4772:         ftotpoints[q*2+1] = fpoints[p+1];
    4773:         ++q;
    4774:       }
    4775:     }
    4776:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
    4777:   }
    4778:   numFPoints = q;
    4779:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
    4780:     PetscInt fdof;

    4782:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
    4783:     if (!dof) continue;
    4784:     for (f = 0; f < numFields; ++f) {
    4785:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
    4786:       foffsets[f+1] += fdof;
    4787:     }
    4788:     numFIndices += dof;
    4789:   }
    4790:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

    4792:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
    4793:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
    4794:   DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
    4795:   DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
    4796:   if (numFields) {
    4797:     for (p = 0; p < numFPoints*2; p += 2) {
    4798:       PetscInt o = ftotpoints[p+1];
    4799:       PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);
    4800:       indicesPointFields_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
    4801:     }
    4802:     for (p = 0; p < numCPoints*2; p += 2) {
    4803:       PetscInt o = cpoints[p+1];
    4804:       PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);
    4805:       indicesPointFields_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
    4806:     }
    4807:   } else {
    4808:     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
    4809:       PetscInt o = ftotpoints[p+1];
    4810:       PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);
    4811:       indicesPoint_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
    4812:     }
    4813:     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
    4814:       PetscInt o = cpoints[p+1];
    4815:       PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);
    4816:       indicesPoint_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
    4817:     }
    4818:   }
    4819:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
    4820:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
    4821:   if (ierr) {
    4822:     PetscMPIInt    rank;
    4823:     PetscErrorCode ierr2;

    4825:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
    4826:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
    4827:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
    4828:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
    4829:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
    4830:
    4831:   }
    4832:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
    4833:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
    4834:   DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
    4835:   DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
    4836:   return(0);
    4837: }

    4841: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
    4842: {
    4843:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
    4844:   PetscInt      *cpoints = NULL;
    4845:   PetscInt       foffsets[32], coffsets[32];
    4846:   CellRefiner    cellRefiner;
    4847:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

    4853:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
    4855:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
    4857:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
    4859:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
    4861:   PetscSectionGetNumFields(fsection, &numFields);
    4862:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
    4863:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
    4864:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
    4865:   /* Column indices */
    4866:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
    4867:   maxFPoints = numCPoints;
    4868:   /* Compress out points not in the section */
    4869:   /*   TODO: Squeeze out points with 0 dof as well */
    4870:   PetscSectionGetChart(csection, &pStart, &pEnd);
    4871:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
    4872:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
    4873:       cpoints[q*2]   = cpoints[p];
    4874:       cpoints[q*2+1] = cpoints[p+1];
    4875:       ++q;
    4876:     }
    4877:   }
    4878:   numCPoints = q;
    4879:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
    4880:     PetscInt fdof;

    4882:     PetscSectionGetDof(csection, cpoints[p], &dof);
    4883:     if (!dof) continue;
    4884:     for (f = 0; f < numFields; ++f) {
    4885:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
    4886:       coffsets[f+1] += fdof;
    4887:     }
    4888:     numCIndices += dof;
    4889:   }
    4890:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
    4891:   /* Row indices */
    4892:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
    4893:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
    4894:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
    4895:   for (r = 0, q = 0; r < numSubcells; ++r) {
    4896:     /* TODO Map from coarse to fine cells */
    4897:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
    4898:     /* Compress out points not in the section */
    4899:     PetscSectionGetChart(fsection, &pStart, &pEnd);
    4900:     for (p = 0; p < numFPoints*2; p += 2) {
    4901:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
    4902:         PetscSectionGetDof(fsection, fpoints[p], &dof);
    4903:         if (!dof) continue;
    4904:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
    4905:         if (s < q) continue;
    4906:         ftotpoints[q*2]   = fpoints[p];
    4907:         ftotpoints[q*2+1] = fpoints[p+1];
    4908:         ++q;
    4909:       }
    4910:     }
    4911:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
    4912:   }
    4913:   numFPoints = q;
    4914:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
    4915:     PetscInt fdof;

    4917:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
    4918:     if (!dof) continue;
    4919:     for (f = 0; f < numFields; ++f) {
    4920:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
    4921:       foffsets[f+1] += fdof;
    4922:     }
    4923:     numFIndices += dof;
    4924:   }
    4925:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

    4927:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
    4928:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
    4929:   if (numFields) {
    4930:     for (p = 0; p < numFPoints*2; p += 2) {
    4931:       PetscInt o = ftotpoints[p+1];
    4932:       PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);
    4933:       indicesPointFields_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
    4934:     }
    4935:     for (p = 0; p < numCPoints*2; p += 2) {
    4936:       PetscInt o = cpoints[p+1];
    4937:       PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);
    4938:       indicesPointFields_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
    4939:     }
    4940:   } else {
    4941:     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
    4942:       PetscInt o = ftotpoints[p+1];
    4943:       PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);
    4944:       indicesPoint_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
    4945:     }
    4946:     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
    4947:       PetscInt o = cpoints[p+1];
    4948:       PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);
    4949:       indicesPoint_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
    4950:     }
    4951:   }
    4952:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
    4953:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
    4954:   return(0);
    4955: }

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

    4962:   Input Parameter:
    4963: . dm - The DMPlex object

    4965:   Output Parameters:
    4966: + cMax - The first hybrid cell
    4967: . fMax - The first hybrid face
    4968: . eMax - The first hybrid edge
    4969: - vMax - The first hybrid vertex

    4971:   Level: developer

    4973: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
    4974: @*/
    4975: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
    4976: {
    4977:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    4978:   PetscInt       dim;

    4983:   DMGetDimension(dm, &dim);
    4984:   if (cMax) *cMax = mesh->hybridPointMax[dim];
    4985:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
    4986:   if (eMax) *eMax = mesh->hybridPointMax[1];
    4987:   if (vMax) *vMax = mesh->hybridPointMax[0];
    4988:   return(0);
    4989: }

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

    4996:   Input Parameters:
    4997: . dm   - The DMPlex object
    4998: . cMax - The first hybrid cell
    4999: . fMax - The first hybrid face
    5000: . eMax - The first hybrid edge
    5001: - vMax - The first hybrid vertex

    5003:   Level: developer

    5005: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
    5006: @*/
    5007: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
    5008: {
    5009:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    5010:   PetscInt       dim;

    5015:   DMGetDimension(dm, &dim);
    5016:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
    5017:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
    5018:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
    5019:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
    5020:   return(0);
    5021: }

    5025: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
    5026: {
    5027:   DM_Plex *mesh = (DM_Plex*) dm->data;

    5032:   *cellHeight = mesh->vtkCellHeight;
    5033:   return(0);
    5034: }

    5038: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
    5039: {
    5040:   DM_Plex *mesh = (DM_Plex*) dm->data;

    5044:   mesh->vtkCellHeight = cellHeight;
    5045:   return(0);
    5046: }

    5050: /* We can easily have a form that takes an IS instead */
    5051: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
    5052: {
    5053:   PetscSection   section, globalSection;
    5054:   PetscInt      *numbers, p;

    5058:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
    5059:   PetscSectionSetChart(section, pStart, pEnd);
    5060:   for (p = pStart; p < pEnd; ++p) {
    5061:     PetscSectionSetDof(section, p, 1);
    5062:   }
    5063:   PetscSectionSetUp(section);
    5064:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);
    5065:   PetscMalloc1(pEnd - pStart, &numbers);
    5066:   for (p = pStart; p < pEnd; ++p) {
    5067:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
    5068:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
    5069:     else                       numbers[p-pStart] += shift;
    5070:   }
    5071:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
    5072:   if (globalSize) {
    5073:     PetscLayout layout;
    5074:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
    5075:     PetscLayoutGetSize(layout, globalSize);
    5076:     PetscLayoutDestroy(&layout);
    5077:   }
    5078:   PetscSectionDestroy(&section);
    5079:   PetscSectionDestroy(&globalSection);
    5080:   return(0);
    5081: }

    5085: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
    5086: {
    5087:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    5088:   PetscInt       cellHeight, cStart, cEnd, cMax;

    5093:   if (!mesh->globalCellNumbers) {
    5094:     DMPlexGetVTKCellHeight(dm, &cellHeight);
    5095:     DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
    5096:     DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
    5097:     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
    5098:     DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, &mesh->globalCellNumbers);
    5099:   }
    5100:   *globalCellNumbers = mesh->globalCellNumbers;
    5101:   return(0);
    5102: }

    5106: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
    5107: {
    5108:   DM_Plex       *mesh = (DM_Plex*) dm->data;
    5109:   PetscInt       vStart, vEnd, vMax;

    5114:   if (!mesh->globalVertexNumbers) {
    5115:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    5116:     DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
    5117:     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
    5118:     DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, &mesh->globalVertexNumbers);
    5119:   }
    5120:   *globalVertexNumbers = mesh->globalVertexNumbers;
    5121:   return(0);
    5122: }

    5126: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
    5127: {
    5128:   IS             nums[4];
    5129:   PetscInt       depths[4];
    5130:   PetscInt       depth, d, shift = 0;

    5135:   DMPlexGetDepth(dm, &depth);
    5136:   /* For unstratified meshes use dim instead of depth */
    5137:   if (depth < 0) {DMGetDimension(dm, &depth);}
    5138:   depths[0] = depth; depths[1] = 0;
    5139:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
    5140:   for (d = 0; d <= depth; ++d) {
    5141:     PetscInt pStart, pEnd, gsize;

    5143:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
    5144:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
    5145:     shift += gsize;
    5146:   }
    5147:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
    5148:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
    5149:   return(0);
    5150: }

    5155: /*@C
    5156:   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
    5157:   the local section and an SF describing the section point overlap.

    5159:   Input Parameters:
    5160:   + s - The PetscSection for the local field layout
    5161:   . sf - The SF describing parallel layout of the section points
    5162:   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
    5163:   . label - The label specifying the points
    5164:   - labelValue - The label stratum specifying the points

    5166:   Output Parameter:
    5167:   . gsection - The PetscSection for the global field layout

    5169:   Note: This gives negative sizes and offsets to points not owned by this process

    5171:   Level: developer

    5173: .seealso: PetscSectionCreate()
    5174: @*/
    5175: PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
    5176: {
    5177:   PetscInt      *neg = NULL, *tmpOff = NULL;
    5178:   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;

    5182:   PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);
    5183:   PetscSectionGetChart(s, &pStart, &pEnd);
    5184:   PetscSectionSetChart(*gsection, pStart, pEnd);
    5185:   PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);
    5186:   if (nroots >= 0) {
    5187:     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
    5188:     PetscCalloc1(nroots, &neg);
    5189:     if (nroots > pEnd-pStart) {
    5190:       PetscCalloc1(nroots, &tmpOff);
    5191:     } else {
    5192:       tmpOff = &(*gsection)->atlasDof[-pStart];
    5193:     }
    5194:   }
    5195:   /* Mark ghost points with negative dof */
    5196:   for (p = pStart; p < pEnd; ++p) {
    5197:     PetscInt value;

    5199:     DMLabelGetValue(label, p, &value);
    5200:     if (value != labelValue) continue;
    5201:     PetscSectionGetDof(s, p, &dof);
    5202:     PetscSectionSetDof(*gsection, p, dof);
    5203:     PetscSectionGetConstraintDof(s, p, &cdof);
    5204:     if (!includeConstraints && cdof > 0) {PetscSectionSetConstraintDof(*gsection, p, cdof);}
    5205:     if (neg) neg[p] = -(dof+1);
    5206:   }
    5207:   PetscSectionSetUpBC(*gsection);
    5208:   if (nroots >= 0) {
    5209:     PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);
    5210:     PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);
    5211:     if (nroots > pEnd-pStart) {
    5212:       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
    5213:     }
    5214:   }
    5215:   /* Calculate new sizes, get proccess offset, and calculate point offsets */
    5216:   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
    5217:     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
    5218:     (*gsection)->atlasOff[p] = off;
    5219:     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
    5220:   }
    5221:   MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));
    5222:   globalOff -= off;
    5223:   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
    5224:     (*gsection)->atlasOff[p] += globalOff;
    5225:     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
    5226:   }
    5227:   /* Put in negative offsets for ghost points */
    5228:   if (nroots >= 0) {
    5229:     PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);
    5230:     PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);
    5231:     if (nroots > pEnd-pStart) {
    5232:       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
    5233:     }
    5234:   }
    5235:   if (nroots >= 0 && nroots > pEnd-pStart) {PetscFree(tmpOff);}
    5236:   PetscFree(neg);
    5237:   return(0);
    5238: }

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

    5245:   Input Parameters:
    5246:   + dm - The DMPlex object

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

    5250:   Level: developer

    5252: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
    5253: @*/
    5254: PetscErrorCode DMPlexCheckSymmetry(DM dm)
    5255: {
    5256:   PetscSection    coneSection, supportSection;
    5257:   const PetscInt *cone, *support;
    5258:   PetscInt        coneSize, c, supportSize, s;
    5259:   PetscInt        pStart, pEnd, p, csize, ssize;
    5260:   PetscErrorCode  ierr;

    5264:   DMPlexGetConeSection(dm, &coneSection);
    5265:   DMPlexGetSupportSection(dm, &supportSection);
    5266:   /* Check that point p is found in the support of its cone points, and vice versa */
    5267:   DMPlexGetChart(dm, &pStart, &pEnd);
    5268:   for (p = pStart; p < pEnd; ++p) {
    5269:     DMPlexGetConeSize(dm, p, &coneSize);
    5270:     DMPlexGetCone(dm, p, &cone);
    5271:     for (c = 0; c < coneSize; ++c) {
    5272:       PetscBool dup = PETSC_FALSE;
    5273:       PetscInt  d;
    5274:       for (d = c-1; d >= 0; --d) {
    5275:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
    5276:       }
    5277:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
    5278:       DMPlexGetSupport(dm, cone[c], &support);
    5279:       for (s = 0; s < supportSize; ++s) {
    5280:         if (support[s] == p) break;
    5281:       }
    5282:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
    5283:         PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);
    5284:         for (s = 0; s < coneSize; ++s) {
    5285:           PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);
    5286:         }
    5287:         PetscPrintf(PETSC_COMM_SELF, "\n");
    5288:         PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);
    5289:         for (s = 0; s < supportSize; ++s) {
    5290:           PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);
    5291:         }
    5292:         PetscPrintf(PETSC_COMM_SELF, "\n");
    5293:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]);
    5294:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
    5295:       }
    5296:     }
    5297:     DMPlexGetSupportSize(dm, p, &supportSize);
    5298:     DMPlexGetSupport(dm, p, &support);
    5299:     for (s = 0; s < supportSize; ++s) {
    5300:       DMPlexGetConeSize(dm, support[s], &coneSize);
    5301:       DMPlexGetCone(dm, support[s], &cone);
    5302:       for (c = 0; c < coneSize; ++c) {
    5303:         if (cone[c] == p) break;
    5304:       }
    5305:       if (c >= coneSize) {
    5306:         PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);
    5307:         for (c = 0; c < supportSize; ++c) {
    5308:           PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);
    5309:         }
    5310:         PetscPrintf(PETSC_COMM_SELF, "\n");
    5311:         PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);
    5312:         for (c = 0; c < coneSize; ++c) {
    5313:           PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);
    5314:         }
    5315:         PetscPrintf(PETSC_COMM_SELF, "\n");
    5316:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
    5317:       }
    5318:     }
    5319:   }
    5320:   PetscSectionGetStorageSize(coneSection, &csize);
    5321:   PetscSectionGetStorageSize(supportSection, &ssize);
    5322:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
    5323:   return(0);
    5324: }

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

    5331:   Input Parameters:
    5332: + dm - The DMPlex object
    5333: . isSimplex - Are the cells simplices or tensor products
    5334: - cellHeight - Normally 0

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

    5338:   Level: developer

    5340: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
    5341: @*/
    5342: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
    5343: {
    5344:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

    5349:   DMGetDimension(dm, &dim);
    5350:   switch (dim) {
    5351:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
    5352:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
    5353:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
    5354:   default:
    5355:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
    5356:   }
    5357:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    5358:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
    5359:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
    5360:   cMax = cMax >= 0 ? cMax : cEnd;
    5361:   for (c = cStart; c < cMax; ++c) {
    5362:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

    5364:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    5365:     for (cl = 0; cl < closureSize*2; cl += 2) {
    5366:       const PetscInt p = closure[cl];
    5367:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
    5368:     }
    5369:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    5370:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
    5371:   }
    5372:   for (c = cMax; c < cEnd; ++c) {
    5373:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

    5375:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    5376:     for (cl = 0; cl < closureSize*2; cl += 2) {
    5377:       const PetscInt p = closure[cl];
    5378:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
    5379:     }
    5380:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    5381:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has  %d vertices > %d", c, coneSize, numHybridCorners);
    5382:   }
    5383:   return(0);
    5384: }

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

    5391:   Input Parameters:
    5392: + dm - The DMPlex object
    5393: . isSimplex - Are the cells simplices or tensor products
    5394: - cellHeight - Normally 0

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

    5398:   Level: developer

    5400: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
    5401: @*/
    5402: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
    5403: {
    5404:   PetscInt       pMax[4];
    5405:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

    5410:   DMGetDimension(dm, &dim);
    5411:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    5412:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
    5413:   for (h = cellHeight; h < dim; ++h) {
    5414:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
    5415:     for (c = cStart; c < cEnd; ++c) {
    5416:       const PetscInt *cone, *ornt, *faces;
    5417:       PetscInt        numFaces, faceSize, coneSize,f;
    5418:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

    5420:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
    5421:       DMPlexGetConeSize(dm, c, &coneSize);
    5422:       DMPlexGetCone(dm, c, &cone);
    5423:       DMPlexGetConeOrientation(dm, c, &ornt);
    5424:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    5425:       for (cl = 0; cl < closureSize*2; cl += 2) {
    5426:         const PetscInt p = closure[cl];
    5427:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
    5428:       }
    5429:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
    5430:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
    5431:       for (f = 0; f < numFaces; ++f) {
    5432:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

    5434:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
    5435:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
    5436:           const PetscInt p = fclosure[cl];
    5437:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
    5438:         }
    5439:         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);
    5440:         for (v = 0; v < fnumCorners; ++v) {
    5441:           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]);
    5442:         }
    5443:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
    5444:       }
    5445:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
    5446:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
    5447:     }
    5448:   }
    5449:   return(0);
    5450: }

    5454: /* Pointwise interpolation
    5455:      Just code FEM for now
    5456:      u^f = I u^c
    5457:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
    5458:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
    5459:      I_{ij} = psi^f_i phi^c_j
    5460: */
    5461: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
    5462: {
    5463:   PetscSection   gsc, gsf;
    5464:   PetscInt       m, n;
    5465:   void          *ctx;

    5469:   /*
    5470:   Loop over coarse cells
    5471:     Loop over coarse basis functions
    5472:       Loop over fine cells in coarse cell
    5473:         Loop over fine dual basis functions
    5474:           Evaluate coarse basis on fine dual basis quad points
    5475:           Sum
    5476:           Update local element matrix
    5477:     Accumulate to interpolation matrix

    5479:    Can extend PetscFEIntegrateJacobian_Basic() to do a specialized cell loop
    5480:   */
    5481:   DMGetDefaultGlobalSection(dmFine, &gsf);
    5482:   PetscSectionGetConstrainedStorageSize(gsf, &m);
    5483:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
    5484:   PetscSectionGetConstrainedStorageSize(gsc, &n);
    5485:   /* We need to preallocate properly */
    5486:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
    5487:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
    5488:   MatSetType(*interpolation, dmCoarse->mattype);
    5489:   DMGetApplicationContext(dmFine, &ctx);
    5490:   DMPlexComputeInterpolatorFEM(dmCoarse, dmFine, *interpolation, ctx);
    5491:   /* Use naive scaling */
    5492:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
    5493:   return(0);
    5494: }

    5498: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
    5499: {
    5501:   VecScatter     ctx;

    5504:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
    5505:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
    5506:   VecScatterDestroy(&ctx);
    5507:   return(0);
    5508: }

    5512: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
    5513: {
    5514:   PetscSection   section;
    5515:   IS            *bcPoints, *bcComps;
    5516:   PetscBool     *isFE;
    5517:   PetscInt      *bcFields, *numComp, *numDof;
    5518:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
    5519:   PetscInt       cStart, cEnd, cEndInterior;

    5523:   DMGetNumFields(dm, &numFields);
    5524:   /* FE and FV boundary conditions are handled slightly differently */
    5525:   PetscMalloc1(numFields, &isFE);
    5526:   for (f = 0; f < numFields; ++f) {
    5527:     PetscObject  obj;
    5528:     PetscClassId id;

    5530:     DMGetField(dm, f, &obj);
    5531:     PetscObjectGetClassId(obj, &id);
    5532:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
    5533:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
    5534:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
    5535:   }
    5536:   /* Allocate boundary point storage for FEM boundaries */
    5537:   DMPlexGetDepth(dm, &depth);
    5538:   DMGetDimension(dm, &dim);
    5539:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    5540:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
    5541:   DMPlexGetNumBoundary(dm, &numBd);
    5542:   for (bd = 0; bd < numBd; ++bd) {
    5543:     PetscInt  field;
    5544:     PetscBool isEssential;

    5546:     DMPlexGetBoundary(dm, bd, &isEssential, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL, NULL);
    5547:     if (isFE[field] && isEssential) ++numBC;
    5548:   }
    5549:   /* Add ghost cell boundaries for FVM */
    5550:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
    5551:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
    5552:   /* Constrain ghost cells for FV */
    5553:   for (f = 0; f < numFields; ++f) {
    5554:     PetscInt *newidx, c;

    5556:     if (isFE[f] || cEndInterior < 0) continue;
    5557:     PetscMalloc1(cEnd-cEndInterior,&newidx);
    5558:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
    5559:     bcFields[bc] = f;
    5560:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
    5561:   }
    5562:   /* Handle FEM Dirichlet boundaries */
    5563:   for (bd = 0; bd < numBd; ++bd) {
    5564:     const char     *bdLabel;
    5565:     DMLabel         label;
    5566:     const PetscInt *comps;
    5567:     const PetscInt *values;
    5568:     PetscInt        bd2, field, numComps, numValues;
    5569:     PetscBool       isEssential, duplicate = PETSC_FALSE;

    5571:     DMPlexGetBoundary(dm, bd, &isEssential, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
    5572:     if (!isFE[field]) continue;
    5573:     DMPlexGetLabel(dm, bdLabel, &label);
    5574:     /* Only want to modify label once */
    5575:     for (bd2 = 0; bd2 < bd; ++bd2) {
    5576:       const char *bdname;
    5577:       DMPlexGetBoundary(dm, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    5578:       PetscStrcmp(bdname, bdLabel, &duplicate);
    5579:       if (duplicate) break;
    5580:     }
    5581:     if (!duplicate && (isFE[field])) {
    5582:       DMPlexLabelComplete(dm, label);
    5583:       DMPlexLabelAddCells(dm, label);
    5584:     }
    5585:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
    5586:     if (isEssential) {
    5587:       PetscInt       *newidx;
    5588:       PetscInt        n, newn = 0, p, v;

    5590:       bcFields[bc] = field;
    5591:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
    5592:       for (v = 0; v < numValues; ++v) {
    5593:         IS              tmp;
    5594:         const PetscInt *idx;

    5596:         DMPlexGetStratumIS(dm, bdLabel, values[v], &tmp);
    5597:         if (!tmp) continue;
    5598:         ISGetLocalSize(tmp, &n);
    5599:         ISGetIndices(tmp, &idx);
    5600:         if (isFE[field]) {
    5601:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
    5602:         } else {
    5603:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
    5604:         }
    5605:         ISRestoreIndices(tmp, &idx);
    5606:         ISDestroy(&tmp);
    5607:       }
    5608:       PetscMalloc1(newn,&newidx);
    5609:       newn = 0;
    5610:       for (v = 0; v < numValues; ++v) {
    5611:         IS              tmp;
    5612:         const PetscInt *idx;

    5614:         DMPlexGetStratumIS(dm, bdLabel, values[v], &tmp);
    5615:         if (!tmp) continue;
    5616:         ISGetLocalSize(tmp, &n);
    5617:         ISGetIndices(tmp, &idx);
    5618:         if (isFE[field]) {
    5619:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
    5620:         } else {
    5621:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
    5622:         }
    5623:         ISRestoreIndices(tmp, &idx);
    5624:         ISDestroy(&tmp);
    5625:       }
    5626:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
    5627:     }
    5628:   }
    5629:   /* Handle discretization */
    5630:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
    5631:   for (f = 0; f < numFields; ++f) {
    5632:     PetscObject obj;

    5634:     DMGetField(dm, f, &obj);
    5635:     if (isFE[f]) {
    5636:       PetscFE         fe = (PetscFE) obj;
    5637:       const PetscInt *numFieldDof;
    5638:       PetscInt        d;

    5640:       PetscFEGetNumComponents(fe, &numComp[f]);
    5641:       PetscFEGetNumDof(fe, &numFieldDof);
    5642:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
    5643:     } else {
    5644:       PetscFV fv = (PetscFV) obj;

    5646:       PetscFVGetNumComponents(fv, &numComp[f]);
    5647:       numDof[f*(dim+1)+dim] = numComp[f];
    5648:     }
    5649:   }
    5650:   for (f = 0; f < numFields; ++f) {
    5651:     PetscInt d;
    5652:     for (d = 1; d < dim; ++d) {
    5653:       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.");
    5654:     }
    5655:   }
    5656:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
    5657:   for (f = 0; f < numFields; ++f) {
    5658:     PetscFE     fe;
    5659:     const char *name;

    5661:     DMGetField(dm, f, (PetscObject *) &fe);
    5662:     PetscObjectGetName((PetscObject) fe, &name);
    5663:     PetscSectionSetFieldName(section, f, name);
    5664:   }
    5665:   DMSetDefaultSection(dm, section);
    5666:   PetscSectionDestroy(&section);
    5667:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
    5668:   PetscFree3(bcFields,bcPoints,bcComps);
    5669:   PetscFree2(numComp,numDof);
    5670:   PetscFree(isFE);
    5671:   return(0);
    5672: }

    5676: /*@
    5677:   DMPlexGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

    5679:   Input Parameter:
    5680: . dm - The DMPlex object

    5682:   Output Parameter:
    5683: . cdm - The coarse DM

    5685:   Level: intermediate

    5687: .seealso: DMPlexSetCoarseDM()
    5688: @*/
    5689: PetscErrorCode DMPlexGetCoarseDM(DM dm, DM *cdm)
    5690: {
    5694:   *cdm = ((DM_Plex *) dm->data)->coarseMesh;
    5695:   return(0);
    5696: }

    5700: /*@
    5701:   DMPlexSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

    5703:   Input Parameters:
    5704: + dm - The DMPlex object
    5705: - cdm - The coarse DM

    5707:   Level: intermediate

    5709: .seealso: DMPlexGetCoarseDM()
    5710: @*/
    5711: PetscErrorCode DMPlexSetCoarseDM(DM dm, DM cdm)
    5712: {
    5713:   DM_Plex       *mesh;

    5719:   mesh = (DM_Plex *) dm->data;
    5720:   DMDestroy(&mesh->coarseMesh);
    5721:   mesh->coarseMesh = cdm;
    5722:   PetscObjectReference((PetscObject) mesh->coarseMesh);
    5723:   return(0);
    5724: }

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

    5733:   not collective

    5735:   Input Parameters:
    5736: . dm - The DMPlex object

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

    5743:   Level: intermediate

    5745: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
    5746: @*/
    5747: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
    5748: {
    5749:   DM_Plex *plex = (DM_Plex *)dm->data;

    5754:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
    5755:   if (anchorSection) *anchorSection = plex->anchorSection;
    5756:   if (anchorIS) *anchorIS = plex->anchorIS;
    5757:   return(0);
    5758: }

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

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

    5770:   collective on dm

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

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

    5779:   Level: intermediate

    5781: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
    5782: @*/
    5783: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
    5784: {
    5785:   DM_Plex        *plex = (DM_Plex *)dm->data;
    5786:   PetscMPIInt    result;

    5791:   if (anchorSection) {
    5793:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
    5794:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
    5795:   }
    5796:   if (anchorIS) {
    5798:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
    5799:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
    5800:   }

    5802:   PetscObjectReference((PetscObject)anchorSection);
    5803:   PetscSectionDestroy(&plex->anchorSection);
    5804:   plex->anchorSection = anchorSection;

    5806:   PetscObjectReference((PetscObject)anchorIS);
    5807:   ISDestroy(&plex->anchorIS);
    5808:   plex->anchorIS = anchorIS;

    5810: #if defined(PETSC_USE_DEBUG)
    5811:   if (anchorIS && anchorSection) {
    5812:     PetscInt size, a, pStart, pEnd;
    5813:     const PetscInt *anchors;

    5815:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
    5816:     ISGetLocalSize(anchorIS,&size);
    5817:     ISGetIndices(anchorIS,&anchors);
    5818:     for (a = 0; a < size; a++) {
    5819:       PetscInt p;

    5821:       p = anchors[a];
    5822:       if (p >= pStart && p < pEnd) {
    5823:         PetscInt dof;

    5825:         PetscSectionGetDof(anchorSection,p,&dof);
    5826:         if (dof) {
    5827:           PetscErrorCode ierr2;

    5829:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
    5830:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %d cannot be constrained and an anchor",p);
    5831:         }
    5832:       }
    5833:     }
    5834:     ISRestoreIndices(anchorIS,&anchors);
    5835:   }
    5836: #endif
    5837:   /* reset the generic constraints */
    5838:   DMSetDefaultConstraints(dm,NULL,NULL);
    5839:   return(0);
    5840: }

    5844: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
    5845: {
    5846:   PetscSection anchorSection;
    5847:   PetscInt pStart, pEnd, p, dof, numFields, f;

    5852:   DMPlexGetAnchors(dm,&anchorSection,NULL);
    5853:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
    5854:   PetscSectionGetNumFields(section,&numFields);
    5855:   PetscSectionSetNumFields(*cSec,numFields);
    5856:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
    5857:   PetscSectionSetChart(*cSec,pStart,pEnd);
    5858:   for (p = pStart; p < pEnd; p++) {
    5859:     PetscSectionGetDof(anchorSection,p,&dof);
    5860:     if (dof) {
    5861:       PetscSectionGetDof(section,p,&dof);
    5862:       PetscSectionSetDof(*cSec,p,dof);
    5863:       for (f = 0; f < numFields; f++) {
    5864:         PetscSectionGetFieldDof(section,p,f,&dof);
    5865:         PetscSectionSetFieldDof(*cSec,p,f,dof);
    5866:       }
    5867:     }
    5868:   }
    5869:   PetscSectionSetUp(*cSec);
    5870:   return(0);
    5871: }

    5875: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
    5876: {
    5877:   PetscSection aSec;
    5878:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
    5879:   const PetscInt *anchors;
    5880:   PetscInt numFields, f;
    5881:   IS aIS;

    5886:   PetscSectionGetStorageSize(cSec, &m);
    5887:   PetscSectionGetStorageSize(section, &n);
    5888:   MatCreate(PETSC_COMM_SELF,cMat);
    5889:   MatSetSizes(*cMat,m,n,m,n);
    5890:   MatSetType(*cMat,MATSEQAIJ);
    5891:   DMPlexGetAnchors(dm,&aSec,&aIS);
    5892:   ISGetIndices(aIS,&anchors);
    5893:   PetscSectionGetChart(aSec,&pStart,&pEnd);
    5894:   PetscMalloc1(m+1,&i);
    5895:   i[0] = 0;
    5896:   PetscSectionGetNumFields(section,&numFields);
    5897:   for (p = pStart; p < pEnd; p++) {
    5898:     PetscSectionGetDof(aSec,p,&dof);
    5899:     if (!dof) continue;
    5900:     PetscSectionGetOffset(aSec,p,&off);
    5901:     if (numFields) {
    5902:       for (f = 0; f < numFields; f++) {
    5903:         annz = 0;
    5904:         for (q = 0; q < dof; q++) {
    5905:           a = anchors[off + q];
    5906:           PetscSectionGetFieldDof(section,a,f,&aDof);
    5907:           annz += aDof;
    5908:         }
    5909:         PetscSectionGetFieldDof(cSec,p,f,&dof);
    5910:         PetscSectionGetFieldOffset(cSec,p,f,&off);
    5911:         for (q = 0; q < dof; q++) {
    5912:           i[off + q + 1] = i[off + q] + annz;
    5913:         }
    5914:       }
    5915:     }
    5916:     else {
    5917:       annz = 0;
    5918:       for (q = 0; q < dof; q++) {
    5919:         a = anchors[off + q];
    5920:         PetscSectionGetDof(section,a,&aDof);
    5921:         annz += aDof;
    5922:       }
    5923:       PetscSectionGetDof(cSec,p,&dof);
    5924:       PetscSectionGetOffset(cSec,p,&off);
    5925:       for (q = 0; q < dof; q++) {
    5926:         i[off + q + 1] = i[off + q] + annz;
    5927:       }
    5928:     }
    5929:   }
    5930:   nnz = i[m];
    5931:   PetscMalloc1(nnz,&j);
    5932:   offset = 0;
    5933:   for (p = pStart; p < pEnd; p++) {
    5934:     if (numFields) {
    5935:       for (f = 0; f < numFields; f++) {
    5936:         PetscSectionGetFieldDof(cSec,p,f,&dof);
    5937:         for (q = 0; q < dof; q++) {
    5938:           PetscInt rDof, rOff, r;
    5939:           PetscSectionGetDof(aSec,p,&rDof);
    5940:           PetscSectionGetOffset(aSec,p,&rOff);
    5941:           for (r = 0; r < rDof; r++) {
    5942:             PetscInt s;

    5944:             a = anchors[rOff + r];

    5946:             PetscSectionGetFieldDof(section,a,f,&aDof);
    5947:             PetscSectionGetFieldOffset(section,a,f,&aOff);
    5948:             for (s = 0; s < aDof; s++) {
    5949:               j[offset++] = aOff + s;
    5950:             }
    5951:           }
    5952:         }
    5953:       }
    5954:     }
    5955:     else {
    5956:       PetscSectionGetDof(cSec,p,&dof);
    5957:       for (q = 0; q < dof; q++) {
    5958:         PetscInt rDof, rOff, r;
    5959:         PetscSectionGetDof(aSec,p,&rDof);
    5960:         PetscSectionGetOffset(aSec,p,&rOff);
    5961:         for (r = 0; r < rDof; r++) {
    5962:           PetscInt s;

    5964:           a = anchors[rOff + r];

    5966:           PetscSectionGetDof(section,a,&aDof);
    5967:           PetscSectionGetOffset(section,a,&aOff);
    5968:           for (s = 0; s < aDof; s++) {
    5969:             j[offset++] = aOff + s;
    5970:           }
    5971:         }
    5972:       }
    5973:     }
    5974:   }
    5975:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
    5976:   PetscFree(i);
    5977:   PetscFree(j);
    5978:   ISRestoreIndices(aIS,&anchors);
    5979:   return(0);
    5980: }

    5984: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
    5985: {
    5986:   DM_Plex        *plex = (DM_Plex *)dm->data;
    5987:   PetscSection   anchorSection, section, cSec;
    5988:   Mat            cMat;

    5993:   DMPlexGetAnchors(dm,&anchorSection,NULL);
    5994:   if (anchorSection) {
    5995:     PetscDS  ds;
    5996:     PetscInt nf;

    5998:     DMGetDefaultSection(dm,&section);
    5999:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
    6000:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
    6001:     DMGetDS(dm,&ds);
    6002:     PetscDSGetNumFields(ds,&nf);
    6003:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
    6004:     DMSetDefaultConstraints(dm,cSec,cMat);
    6005:     PetscSectionDestroy(&cSec);
    6006:     MatDestroy(&cMat);
    6007:   }
    6008:   return(0);
    6009: }