Actual source code: stag2d.c

      1: /* Functions specific to the 2-dimensional implementation of DMStag */
      2: #include <petsc/private/dmstagimpl.h>

      4: /*@C
      5:   DMStagCreate2d - Create an object to manage data living on the elements, edges, and vertices of a parallelized regular 2D grid.

      7:   Collective

      9:   Input Parameters:
     10: + comm - MPI communicator
     11: . bndx,bndy - boundary type: DM_BOUNDARY_NONE, DM_BOUNDARY_PERIODIC, or DM_BOUNDARY_GHOSTED
     12: . M,N - global number of elements in x,y directions
     13: . m,n - number of ranks in the x,y directions (may be PETSC_DECIDE)
     14: . dof0 - number of degrees of freedom per vertex/0-cell
     15: . dof1 - number of degrees of freedom per face/1-cell
     16: . dof2 - number of degrees of freedom per element/2-cell
     17: . stencilType - ghost/halo region type: DMSTAG_STENCIL_NONE, DMSTAG_STENCIL_BOX, or DMSTAG_STENCIL_STAR
     18: . stencilWidth - width, in elements, of halo/ghost region
     19: - lx,ly - arrays of local x,y element counts, of length equal to m,n, summing to M,N

     21:   Output Parameter:
     22: . dm - the new DMStag object

     24:   Options Database Keys:
     25: + -dm_view - calls DMViewFromOptions() a the conclusion of DMSetUp()
     26: . -stag_grid_x <nx> - number of elements in the x direction
     27: . -stag_grid_y <ny> - number of elements in the y direction
     28: . -stag_ranks_x <rx> - number of ranks in the x direction
     29: . -stag_ranks_y <ry> - number of ranks in the y direction
     30: . -stag_ghost_stencil_width - width of ghost region, in elements
     31: . -stag_boundary_type_x <none,ghosted,periodic> - DMBoundaryType value
     32: - -stag_boundary_type_y <none,ghosted,periodic> - DMBoundaryType value

     34:   Notes:
     35:   You must call DMSetUp() after this call, before using the DM.
     36:   If you wish to use the options database (see the keys above) to change values in the DMStag, you must call
     37:   DMSetFromOptions() after this function but before DMSetUp().

     39:   Level: beginner

     41: .seealso: DMSTAG, DMStagCreate1d(), DMStagCreate3d(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateLocalVector(), DMLocalToGlobalBegin(), DMDACreate2d()
     42: @*/
     43: PETSC_EXTERN PetscErrorCode DMStagCreate2d(MPI_Comm comm, DMBoundaryType bndx,DMBoundaryType bndy, PetscInt M,PetscInt N, PetscInt m,PetscInt n, PetscInt dof0, PetscInt dof1, PetscInt dof2, DMStagStencilType stencilType, PetscInt stencilWidth, const PetscInt lx[], const PetscInt ly[],DM* dm)
     44: {
     45:   DMCreate(comm,dm);
     46:   DMSetDimension(*dm,2);
     47:   DMStagInitialize(bndx,bndy,DM_BOUNDARY_NONE,M,N,0,m,n,0,dof0,dof1,dof2,0,stencilType,stencilWidth,lx,ly,NULL,*dm);
     48:   return 0;
     49: }

     51: PETSC_INTERN PetscErrorCode DMStagSetUniformCoordinatesExplicit_2d(DM dm,PetscReal xmin,PetscReal xmax,PetscReal ymin,PetscReal ymax)
     52: {
     53:   DM_Stag        *stagCoord;
     54:   DM             dmCoord;
     55:   Vec            coordLocal;
     56:   PetscReal      h[2],min[2];
     57:   PetscScalar    ***arr;
     58:   PetscInt       ind[2],start_ghost[2],n_ghost[2],s,c;
     59:   PetscInt       idownleft,idown,ileft,ielement;

     61:   DMGetCoordinateDM(dm, &dmCoord);
     62:   stagCoord = (DM_Stag*) dmCoord->data;
     63:   for (s=0; s<3; ++s) {
     65:   }
     66:   DMCreateLocalVector(dmCoord,&coordLocal);

     68:   DMStagVecGetArray(dmCoord,coordLocal,&arr);
     69:   if (stagCoord->dof[0]) {
     70:     DMStagGetLocationSlot(dmCoord,DMSTAG_DOWN_LEFT,0,&idownleft);
     71:   }
     72:   if (stagCoord->dof[1]) {
     73:     DMStagGetLocationSlot(dmCoord,DMSTAG_DOWN     ,0,&idown);
     74:     DMStagGetLocationSlot(dmCoord,DMSTAG_LEFT     ,0,&ileft);
     75:   }
     76:   if (stagCoord->dof[2]) {
     77:     DMStagGetLocationSlot(dmCoord,DMSTAG_ELEMENT  ,0,&ielement);
     78:   }
     79:   DMStagGetGhostCorners(dmCoord,&start_ghost[0],&start_ghost[1],NULL,&n_ghost[0],&n_ghost[1],NULL);

     81:   min[0] = xmin; min[1]= ymin;
     82:   h[0] = (xmax-xmin)/stagCoord->N[0];
     83:   h[1] = (ymax-ymin)/stagCoord->N[1];

     85:   for (ind[1]=start_ghost[1]; ind[1]<start_ghost[1] + n_ghost[1]; ++ind[1]) {
     86:     for (ind[0]=start_ghost[0]; ind[0]<start_ghost[0] + n_ghost[0]; ++ind[0]) {
     87:       if (stagCoord->dof[0]) {
     88:         const PetscReal offs[2] = {0.0,0.0};
     89:         for (c=0; c<2; ++c) {
     90:           arr[ind[1]][ind[0]][idownleft + c] = min[c] + ((PetscReal)ind[c] + offs[c]) * h[c];
     91:         }
     92:       }
     93:       if (stagCoord->dof[1]) {
     94:         const PetscReal offs[2] = {0.5,0.0};
     95:         for (c=0; c<2; ++c) {
     96:           arr[ind[1]][ind[0]][idown + c] = min[c] + ((PetscReal)ind[c] + offs[c]) * h[c];
     97:         }
     98:       }
     99:       if (stagCoord->dof[1]) {
    100:         const PetscReal offs[2] = {0.0,0.5};
    101:         for (c=0; c<2; ++c) {
    102:           arr[ind[1]][ind[0]][ileft + c] = min[c] + ((PetscReal)ind[c] + offs[c]) * h[c];
    103:         }
    104:       }
    105:       if (stagCoord->dof[2]) {
    106:         const PetscReal offs[2] = {0.5,0.5};
    107:         for (c=0; c<2; ++c) {
    108:           arr[ind[1]][ind[0]][ielement + c] = min[c] + ((PetscReal)ind[c] + offs[c]) * h[c];
    109:         }
    110:       }
    111:     }
    112:   }
    113:   DMStagVecRestoreArray(dmCoord,coordLocal,&arr);
    114:   DMSetCoordinatesLocal(dm,coordLocal);
    115:   PetscLogObjectParent((PetscObject)dm,(PetscObject)coordLocal);
    116:   VecDestroy(&coordLocal);
    117:   return 0;
    118: }

    120: /* Helper functions used in DMSetUp_Stag() */
    121: static PetscErrorCode DMStagSetUpBuildRankGrid_2d(DM);
    122: static PetscErrorCode DMStagSetUpBuildNeighbors_2d(DM);
    123: static PetscErrorCode DMStagSetUpBuildGlobalOffsets_2d(DM,PetscInt**);
    124: static PetscErrorCode DMStagComputeLocationOffsets_2d(DM);

    126: PETSC_INTERN PetscErrorCode DMSetUp_Stag_2d(DM dm)
    127: {
    128:   DM_Stag * const stag = (DM_Stag*)dm->data;
    129:   PetscMPIInt     size,rank;
    130:   PetscInt        i,j,d,entriesPerElementRowGhost,entriesPerCorner,entriesPerFace,entriesPerElementRow;
    131:   MPI_Comm        comm;
    132:   PetscInt        *globalOffsets;
    133:   PetscBool       star,dummyStart[2],dummyEnd[2];
    134:   const PetscInt  dim = 2;

    136:   PetscObjectGetComm((PetscObject)dm,&comm);
    137:   MPI_Comm_size(comm,&size);
    138:   MPI_Comm_rank(comm,&rank);

    140:   /* Rank grid sizes (populates stag->nRanks) */
    141:   DMStagSetUpBuildRankGrid_2d(dm);

    143:   /* Determine location of rank in grid (these get extra boundary points on the last element)
    144:      Order is x-fast, as usual */
    145:     stag->rank[0] = rank % stag->nRanks[0];
    146:     stag->rank[1] = rank / stag->nRanks[0];
    147:     for (i=0; i<dim; ++i) {
    148:       stag->firstRank[i] = PetscNot(stag->rank[i]);
    149:       stag->lastRank[i]  = (PetscBool)(stag->rank[i] == stag->nRanks[i]-1);
    150:     }

    152:   /* Determine Locally owned region

    154:    Divide equally, giving lower ranks in each dimension and extra element if needbe.

    156:    Note that this uses O(P) storage. If this ever becomes an issue, this could
    157:    be refactored to not keep this data around.  */
    158:   for (i=0; i<dim; ++i) {
    159:     if (!stag->l[i]) {
    160:       const PetscInt Ni = stag->N[i], nRanksi = stag->nRanks[i];
    161:       PetscMalloc1(stag->nRanks[i],&stag->l[i]);
    162:       for (j=0; j<stag->nRanks[i]; ++j) {
    163:         stag->l[i][j] = Ni/nRanksi + ((Ni % nRanksi) > j);
    164:       }
    165:     }
    166:   }

    168:   /* Retrieve local size in stag->n */
    169:   for (i=0; i<dim; ++i) stag->n[i] = stag->l[i][stag->rank[i]];
    170:   if (PetscDefined(USE_DEBUG)) {
    171:     for (i=0; i<dim; ++i) {
    172:       PetscInt Ncheck,j;
    173:       Ncheck = 0;
    174:       for (j=0; j<stag->nRanks[i]; ++j) Ncheck += stag->l[i][j];
    176:     }
    177:   }

    179:   /* Compute starting elements */
    180:   for (i=0; i<dim; ++i) {
    181:     stag->start[i] = 0;
    182:     for (j=0;j<stag->rank[i];++j) {
    183:       stag->start[i] += stag->l[i][j];
    184:     }
    185:   }

    187:   /* Determine ranks of neighbors, using DMDA's convention

    189:      n6 n7 n8
    190:      n3    n5
    191:      n0 n1 n2                                               */
    192:   DMStagSetUpBuildNeighbors_2d(dm);

    194:     /* Determine whether the ghost region includes dummies or not. This is currently
    195:        equivalent to having a non-periodic boundary. If not, then
    196:        ghostOffset{Start,End}[d] elements correspond to elements on the neighbor.
    197:        If true, then
    198:        - at the start, there are ghostOffsetStart[d] ghost elements
    199:        - at the end, there is a layer of extra "physical" points inside a layer of
    200:          ghostOffsetEnd[d] ghost elements
    201:        Note that this computation should be updated if any boundary types besides
    202:        NONE, GHOSTED, and PERIODIC are supported.  */
    203:     for (d=0; d<2; ++d) dummyStart[d] = (PetscBool)(stag->firstRank[d] && stag->boundaryType[d] != DM_BOUNDARY_PERIODIC);
    204:     for (d=0; d<2; ++d) dummyEnd[d]   = (PetscBool)(stag->lastRank[d]  && stag->boundaryType[d] != DM_BOUNDARY_PERIODIC);

    206:   /* Define useful sizes */
    207:   stag->entriesPerElement = stag->dof[0] + 2*stag->dof[1] + stag->dof[2];
    208:   entriesPerFace          = stag->dof[0] + stag->dof[1];
    209:   entriesPerCorner        = stag->dof[0];
    210:   entriesPerElementRow    = stag->n[0]*stag->entriesPerElement + (dummyEnd[0] ? entriesPerFace : 0);
    211:   stag->entries           = stag->n[1]*entriesPerElementRow +  (dummyEnd[1] ? stag->n[0]*entriesPerFace : 0) + (dummyEnd[0] && dummyEnd[1] ? entriesPerCorner: 0);

    213:   /* Compute offsets for each rank into global vectors
    214:      This again requires O(P) storage, which could be replaced with some global
    215:      communication.  */
    216:   DMStagSetUpBuildGlobalOffsets_2d(dm,&globalOffsets);

    220:   /* Define ghosted/local sizes */
    221:   if (stag->stencilType != DMSTAG_STENCIL_NONE && (stag->n[0] < stag->stencilWidth || stag->n[1] < stag->stencilWidth)) {
    222:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMStag 2d setup does not support local sizes (%D x %D) smaller than the elementwise stencil width (%D)",stag->n[0],stag->n[1],stag->stencilWidth);
    223:   }
    224:   for (d=0; d<dim; ++d) {
    225:     switch (stag->boundaryType[d]) {
    226:       case DM_BOUNDARY_NONE:
    227:         /* Note: for a elements-only DMStag, the extra elements on the edges aren't necessary but we include them anyway */
    228:         switch (stag->stencilType) {
    229:           case DMSTAG_STENCIL_NONE : /* only the extra one on the right/top edges */
    230:             stag->nGhost[d] = stag->n[d];
    231:             stag->startGhost[d] = stag->start[d];
    232:             if (stag->lastRank[d]) stag->nGhost[d] += 1;
    233:             break;
    234:           case DMSTAG_STENCIL_STAR : /* allocate the corners but don't use them */
    235:           case DMSTAG_STENCIL_BOX :
    236:             stag->nGhost[d] = stag->n[d];
    237:             stag->startGhost[d] = stag->start[d];
    238:             if (!stag->firstRank[d]) {
    239:               stag->nGhost[d]     += stag->stencilWidth; /* add interior ghost elements */
    240:               stag->startGhost[d] -= stag->stencilWidth;
    241:             }
    242:             if (!stag->lastRank[d]) {
    243:               stag->nGhost[d] += stag->stencilWidth; /* add interior ghost elements */
    244:             } else {
    245:               stag->nGhost[d] += 1; /* one element on the boundary to complete blocking */
    246:             }
    247:             break;
    248:           default :
    249:             SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unrecognized ghost stencil type %d",stag->stencilType);
    250:         }
    251:         break;
    252:       case DM_BOUNDARY_GHOSTED:
    253:         switch (stag->stencilType) {
    254:           case DMSTAG_STENCIL_NONE :
    255:             stag->startGhost[d] = stag->start[d];
    256:             stag->nGhost[d]     = stag->n[d] + (stag->lastRank[d] ? 1 : 0);
    257:             break;
    258:           case DMSTAG_STENCIL_STAR :
    259:           case DMSTAG_STENCIL_BOX :
    260:             stag->startGhost[d] = stag->start[d] - stag->stencilWidth; /* This value may be negative */
    261:             stag->nGhost[d]     = stag->n[d] + 2*stag->stencilWidth + (stag->lastRank[d] && stag->stencilWidth == 0 ? 1 : 0);
    262:             break;
    263:           default :
    264:             SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unrecognized ghost stencil type %d",stag->stencilType);
    265:         }
    266:         break;
    267:       case DM_BOUNDARY_PERIODIC:
    268:         switch (stag->stencilType) {
    269:           case DMSTAG_STENCIL_NONE : /* only the extra one on the right/top edges */
    270:             stag->nGhost[d] = stag->n[d];
    271:             stag->startGhost[d] = stag->start[d];
    272:             break;
    273:           case DMSTAG_STENCIL_STAR :
    274:           case DMSTAG_STENCIL_BOX :
    275:             stag->nGhost[d] = stag->n[d] + 2*stag->stencilWidth;
    276:             stag->startGhost[d] = stag->start[d] - stag->stencilWidth;
    277:             break;
    278:           default :
    279:             SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unrecognized ghost stencil type %d",stag->stencilType);
    280:         }
    281:         break;
    282:       default: SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Unsupported boundary type in dimension %D",d);
    283:     }
    284:   }
    285:   stag->entriesGhost = stag->nGhost[0]*stag->nGhost[1]*stag->entriesPerElement;
    286:   entriesPerElementRowGhost = stag->nGhost[0]*stag->entriesPerElement;

    288:   /* Create global-->local VecScatter and local->global ISLocalToGlobalMapping

    290:      We iterate over all local points twice. First, we iterate over each neighbor, populating
    291:      1. idxLocal[] : the subset of points, in local numbering ("S" from 0 on all points including ghosts), which correspond to global points. That is, the set of all non-dummy points in the ghosted representation
    292:      2. idxGlobal[]: the corresponding global points, in global numbering (Nested "S"s - ranks then non-ghost points in each rank)

    294:      Next, we iterate over all points in the local ordering, populating
    295:      3. idxGlobalAll[] : entry i is the global point corresponding to local point i, or -1 if local point i is a dummy.

    297:      Note further here that the local/ghosted vectors:
    298:      - Are always an integral number of elements-worth of points, in all directions.
    299:      - Contain three flavors of points:
    300:      1. Points which "live here" in the global representation
    301:      2. Ghost points which correspond to points on other ranks in the global representation
    302:      3. Ghost points, which we call "dummy points," which do not correspond to any point in the global representation

    304:      Dummy ghost points arise in at least three ways:
    305:      1. As padding for the right, top, and front physical boundaries, to complete partial elements
    306:      2. As unused space in the "corners" on interior ranks when using a star stencil
    307:      3. As additional work space on all physical boundaries, when DM_BOUNDARY_GHOSTED is used

    309:      Note that, because of the boundary dummies,
    310:      with a stencil width of zero, on 1 rank, local and global vectors
    311:      are still different!

    313:      We assume that the size on each rank is greater than or equal to the
    314:      stencil width.
    315:      */

    317:   /* Check stencil type */
    319:   star = (PetscBool)(stag->stencilType == DMSTAG_STENCIL_STAR || stag->stencilType == DMSTAG_STENCIL_NONE);

    321:   {
    322:     PetscInt *idxLocal,*idxGlobal,*idxGlobalAll;
    323:     PetscInt  count,countAll,entriesToTransferTotal,i,j,d,ghostOffsetStart[2],ghostOffsetEnd[2];
    324:     IS        isLocal,isGlobal;
    325:     PetscInt  jghost,ighost;
    326:     PetscInt  nNeighbors[9][2];
    327:     PetscBool nextToDummyEnd[2];

    329:     /* Compute numbers of elements on each neighbor */
    330:     for (i=0; i<9; ++i) {
    331:       const PetscInt neighborRank = stag->neighbors[i];
    332:       if (neighborRank >= 0) { /* note we copy the values for our own rank (neighbor 4) */
    333:         nNeighbors[i][0] =  stag->l[0][neighborRank % stag->nRanks[0]];
    334:         nNeighbors[i][1] =  stag->l[1][neighborRank / stag->nRanks[0]];
    335:       } /* else leave uninitialized - error if accessed */
    336:     }

    338:     /* These offsets should always be non-negative, and describe how many
    339:        ghost elements exist at each boundary. These are not always equal to the stencil width,
    340:        because we may have different numbers of ghost elements at the boundaries. In particular,
    341:        we always have at least one ghost (dummy) element at the right/top/front. */
    342:     for (d=0; d<2; ++d) ghostOffsetStart[d] = stag->start[d] - stag->startGhost[d];
    343:     for (d=0; d<2; ++d) ghostOffsetEnd[d]   = stag->startGhost[d]+stag->nGhost[d] - (stag->start[d]+stag->n[d]);

    345:     /* Compute whether the next rank has an extra point (only used in x direction) */
    346:     for (d=0;d<2;++d) nextToDummyEnd[d] = (PetscBool)(stag->boundaryType[d] != DM_BOUNDARY_PERIODIC && stag->rank[d] == stag->nRanks[d]-2);

    348:     /* Compute the number of local entries which correspond to any global entry */
    349:     {
    350:       PetscInt nNonDummyGhost[2];
    351:       for (d=0; d<2; ++d) nNonDummyGhost[d] = stag->nGhost[d] - (dummyStart[d] ? ghostOffsetStart[d] : 0) - (dummyEnd[d] ? ghostOffsetEnd[d] : 0);
    352:       if (star) {
    353:         entriesToTransferTotal = (nNonDummyGhost[0] * stag->n[1] + stag->n[0] * nNonDummyGhost[1] - stag->n[0] * stag->n[1]) * stag->entriesPerElement
    354:           + (dummyEnd[0]                ? nNonDummyGhost[1] * entriesPerFace   : 0)
    355:           + (dummyEnd[1]                ? nNonDummyGhost[0] * entriesPerFace   : 0)
    356:           + (dummyEnd[0] && dummyEnd[1] ?                     entriesPerCorner : 0);
    357:       } else {
    358:         entriesToTransferTotal = nNonDummyGhost[0] * nNonDummyGhost[1] * stag->entriesPerElement
    359:           + (dummyEnd[0]                ? nNonDummyGhost[1] * entriesPerFace   : 0)
    360:           + (dummyEnd[1]                ? nNonDummyGhost[0] * entriesPerFace   : 0)
    361:           + (dummyEnd[0] && dummyEnd[1] ?                     entriesPerCorner : 0);
    362:       }
    363:     }

    365:     /* Allocate arrays to populate */
    366:     PetscMalloc1(entriesToTransferTotal,&idxLocal);
    367:     PetscMalloc1(entriesToTransferTotal,&idxGlobal);

    369:     /* Counts into idxLocal/idxGlobal */
    370:     count = 0;

    372:     /* Here and below, we work with (i,j) describing element numbers within a neighboring rank's global ordering,
    373:        to be offset by that rank's global offset,
    374:        and (ighost,jghost) referring to element numbers within this ranks local (ghosted) ordering */

    376:     /* Neighbor 0 (down left) */
    377:     if (!star && !dummyStart[0] && !dummyStart[1]) {
    378:       const PetscInt         neighbor             = 0;
    379:       const PetscInt         globalOffset         = globalOffsets[stag->neighbors[neighbor]];
    380:       const PetscInt * const nNeighbor            = nNeighbors[neighbor];
    381:       const PetscInt entriesPerElementRowNeighbor = stag->entriesPerElement * nNeighbor[0];
    382:       for (jghost = 0; jghost<ghostOffsetStart[1]; ++jghost) {
    383:         const PetscInt j = nNeighbor[1] - ghostOffsetStart[1] + jghost;
    384:         for (ighost = 0; ighost<ghostOffsetStart[0]; ++ighost) {
    385:           const PetscInt i = nNeighbor[0] - ghostOffsetStart[0] + ighost;
    386:           for (d=0; d<stag->entriesPerElement; ++d,++count) {
    387:             idxGlobal[count] = globalOffset + j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    388:             idxLocal[count]  =                jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    389:           }
    390:         }
    391:       }
    392:     }

    394:     /* Neighbor 1 (down) */
    395:     if (!dummyStart[1]) {
    396:       /* We may be a ghosted boundary in x, in which case the neighbor is also */
    397:       const PetscInt         neighbor                     = 1;
    398:       const PetscInt         globalOffset                 = globalOffsets[stag->neighbors[neighbor]];
    399:       const PetscInt * const nNeighbor                    = nNeighbors[neighbor];
    400:       const PetscInt         entriesPerElementRowNeighbor = entriesPerElementRow; /* same as here */
    401:       for (jghost = 0; jghost<ghostOffsetStart[1]; ++jghost) {
    402:         const PetscInt j = nNeighbor[1] - ghostOffsetStart[1] + jghost;
    403:         for (ighost = ghostOffsetStart[0]; ighost<stag->nGhost[0]-ghostOffsetEnd[0]; ++ighost) {
    404:           const PetscInt i = ighost - ghostOffsetStart[0];
    405:           for (d=0; d<stag->entriesPerElement; ++d, ++count) {
    406:             idxGlobal[count] = globalOffset+ j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    407:             idxLocal[count]  =               jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    408:           }
    409:         }
    410:         if (dummyEnd[0]) {
    411:           const PetscInt ighost = stag->nGhost[0]-ghostOffsetEnd[0];
    412:           const PetscInt i = stag->n[0];
    413:           for (d=0; d<stag->dof[0]; ++d, ++count) { /* Vertex */
    414:             idxGlobal[count] = globalOffset + j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    415:             idxLocal[count]  =                jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    416:           }
    417:           for (d=0; d<stag->dof[1]; ++d,++count) { /* Face */
    418:             idxGlobal[count] = globalOffset + j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + stag->dof[0]                + d;
    419:             idxLocal[count]  =                jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + stag->dof[0] + stag->dof[1] + d;
    420:           }
    421:         }
    422:       }
    423:     }

    425:     /* Neighbor 2 (down right) */
    426:     if (!star && !dummyEnd[0] && !dummyStart[1]) {
    427:       const PetscInt         neighbor             = 2;
    428:       const PetscInt         globalOffset         = globalOffsets[stag->neighbors[neighbor]];
    429:       const PetscInt * const nNeighbor            = nNeighbors[neighbor];
    430:       const PetscInt entriesPerElementRowNeighbor = nNeighbor[0]*stag->entriesPerElement + (nextToDummyEnd[0] ? entriesPerFace : 0);
    431:       for (jghost = 0; jghost<ghostOffsetStart[1]; ++jghost) {
    432:         const PetscInt j = nNeighbor[1] - ghostOffsetStart[1] + jghost;
    433:         for (i=0; i<ghostOffsetEnd[0]; ++i) {
    434:           const PetscInt ighost = stag->nGhost[0] - ghostOffsetEnd[0] + i;
    435:           for (d=0; d<stag->entriesPerElement; ++d, ++count) {
    436:             idxGlobal[count] = globalOffset + j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    437:             idxLocal[count]  =                jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    438:           }
    439:         }
    440:       }
    441:     }

    443:     /* Neighbor 3 (left) */
    444:     if (!dummyStart[0]) {
    445:       /* Our neighbor is never a ghosted boundary in x, but we may be
    446:          Here, we may be a ghosted boundary in y and thus so will our neighbor be */
    447:       const PetscInt         neighbor             = 3;
    448:       const PetscInt         globalOffset         = globalOffsets[stag->neighbors[neighbor]];
    449:       const PetscInt * const nNeighbor            = nNeighbors[neighbor];
    450:       const PetscInt entriesPerElementRowNeighbor = nNeighbor[0]*stag->entriesPerElement;
    451:       for (jghost = ghostOffsetStart[1]; jghost<stag->nGhost[1] - ghostOffsetEnd[1]; ++jghost) {
    452:         const PetscInt j = jghost-ghostOffsetStart[1];
    453:         for (ighost = 0; ighost<ghostOffsetStart[0]; ++ighost) {
    454:           const PetscInt i = nNeighbor[0] - ghostOffsetStart[0] + ighost;
    455:           for (d=0; d<stag->entriesPerElement; ++d, ++count) {
    456:             idxGlobal[count] = globalOffset + j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    457:             idxLocal[count]  =                jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    458:           }
    459:         }
    460:       }
    461:       if (dummyEnd[1]) {
    462:         const PetscInt jghost = stag->nGhost[1]-ghostOffsetEnd[1];
    463:         const PetscInt j = stag->n[1];
    464:         for (ighost = 0; ighost<ghostOffsetStart[0]; ++ighost) {
    465:           const PetscInt i = nNeighbor[0] - ghostOffsetStart[0] + ighost;
    466:           for (d=0; d<entriesPerFace; ++d, ++count) { /* only vertices and horizontal edge (which are the first dof) */
    467:             idxGlobal[count] = globalOffset + j     *entriesPerElementRowNeighbor + i     *entriesPerFace          + d; /* i moves by edge here */
    468:             idxLocal[count]  =                jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    469:           }
    470:         }
    471:       }
    472:     }

    474:     /* Interior/Resident-here-in-global elements ("Neighbor 4" - same rank)
    475:        *including* entries from boundary dummy elements */
    476:     {
    477:       const PetscInt neighbor     = 4;
    478:       const PetscInt globalOffset = globalOffsets[stag->neighbors[neighbor]];
    479:       for (j=0; j<stag->n[1]; ++j) {
    480:         const PetscInt jghost = j + ghostOffsetStart[1];
    481:         for (i=0; i<stag->n[0]; ++i) {
    482:           const PetscInt ighost = i + ghostOffsetStart[0];
    483:           for (d=0; d<stag->entriesPerElement; ++d, ++count) {
    484:             idxGlobal[count] = globalOffset + j     *entriesPerElementRow       + i     *stag->entriesPerElement + d;
    485:             idxLocal[count]  =                jghost*entriesPerElementRowGhost  + ighost*stag->entriesPerElement + d;
    486:           }
    487:         }
    488:         if (dummyEnd[0]) {
    489:           const PetscInt ighost = i + ghostOffsetStart[0];
    490:           i = stag->n[0];
    491:           for (d=0; d<stag->dof[0]; ++d, ++count) { /* vertex first */
    492:             idxGlobal[count] = globalOffset + j     *entriesPerElementRow      + i     *stag->entriesPerElement + d;
    493:             idxLocal[count]  =                jghost*entriesPerElementRowGhost + ighost*stag->entriesPerElement + d;
    494:           }
    495:           for (d=0; d<stag->dof[1]; ++d, ++count) { /* then left ege (skipping bottom edge) */
    496:             idxGlobal[count] = globalOffset + j     *entriesPerElementRow       + i     *stag->entriesPerElement + stag->dof[0]                + d;
    497:             idxLocal[count]  =                jghost*entriesPerElementRowGhost  + ighost*stag->entriesPerElement + stag->dof[0] + stag->dof[1] + d;
    498:           }
    499:         }
    500:       }
    501:       if (dummyEnd[1]) {
    502:         const PetscInt jghost = j + ghostOffsetStart[1];
    503:         j = stag->n[1];
    504:         for (i=0; i<stag->n[0]; ++i) {
    505:           const PetscInt ighost = i + ghostOffsetStart[0];
    506:           for (d=0; d<entriesPerFace; ++d, ++count) { /* vertex and bottom edge (which are the first entries) */
    507:             idxGlobal[count] = globalOffset + j     *entriesPerElementRow +      i*entriesPerFace               + d; /* note i increment by entriesPerFace */
    508:             idxLocal[count]  =                jghost*entriesPerElementRowGhost + ighost*stag->entriesPerElement + d;
    509:           }
    510:         }
    511:         if (dummyEnd[0]) {
    512:           const PetscInt ighost = i + ghostOffsetStart[0];
    513:           i = stag->n[0];
    514:           for (d=0; d<entriesPerCorner; ++d, ++count) { /* vertex only */
    515:             idxGlobal[count] = globalOffset + j     *entriesPerElementRow       + i     *entriesPerFace          + d; /* note i increment by entriesPerFace */
    516:             idxLocal[count]  =                jghost*entriesPerElementRowGhost  + ighost*stag->entriesPerElement + d;
    517:           }
    518:         }
    519:       }
    520:     }

    522:     /* Neighbor 5 (right) */
    523:     if (!dummyEnd[0]) {
    524:       /* We can never be right boundary, but we may be a top boundary, along with the right neighbor */
    525:       const PetscInt         neighbor             = 5;
    526:       const PetscInt         globalOffset         = globalOffsets[stag->neighbors[neighbor]];
    527:       const PetscInt * const nNeighbor            = nNeighbors[neighbor];
    528:       const PetscInt entriesPerElementRowNeighbor = nNeighbor[0]*stag->entriesPerElement + (nextToDummyEnd[0] ? entriesPerFace : 0);
    529:       for (jghost = ghostOffsetStart[1];jghost<stag->nGhost[1]-ghostOffsetEnd[1]; ++jghost) {
    530:         const PetscInt j = jghost-ghostOffsetStart[1];
    531:         for (i=0; i<ghostOffsetEnd[0]; ++i) {
    532:           const PetscInt ighost = stag->nGhost[0] - ghostOffsetEnd[0] + i;
    533:           for (d=0; d<stag->entriesPerElement; ++d, ++count) {
    534:             idxGlobal[count] = globalOffset+ j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    535:             idxLocal[count]  =               jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    536:           }
    537:         }
    538:       }
    539:       if (dummyEnd[1]) {
    540:         const PetscInt jghost = stag->nGhost[1]-ghostOffsetEnd[1];
    541:         const PetscInt j = nNeighbor[1];
    542:         for (i=0; i<ghostOffsetEnd[0]; ++i) {
    543:           const PetscInt ighost = stag->nGhost[0] - ghostOffsetEnd[0] + i;
    544:           for (d=0; d<entriesPerFace; ++d, ++count) { /* only vertices and horizontal edge (which are the first dof) */
    545:             idxGlobal[count] = globalOffset+ j     *entriesPerElementRowNeighbor    + i     *entriesPerFace    + d; /* Note i increment by entriesPerFace */
    546:             idxLocal[count]  =               jghost*entriesPerElementRowGhost + ighost*stag->entriesPerElement + d;
    547:           }
    548:         }
    549:       }
    550:     }

    552:     /* Neighbor 6 (up left) */
    553:     if (!star && !dummyStart[0] && !dummyEnd[1]) {
    554:       /* We can never be a top boundary, but our neighbor may be
    555:        We may be a right boundary, but our neighbor cannot be */
    556:       const PetscInt         neighbor             = 6;
    557:       const PetscInt         globalOffset         = globalOffsets[stag->neighbors[neighbor]];
    558:       const PetscInt * const nNeighbor            = nNeighbors[neighbor];
    559:       const PetscInt entriesPerElementRowNeighbor = nNeighbor[0]*stag->entriesPerElement;
    560:       for (j=0; j<ghostOffsetEnd[1]; ++j) {
    561:         const PetscInt jghost = stag->nGhost[1] - ghostOffsetEnd[1] + j;
    562:         for (ighost = 0; ighost<ghostOffsetStart[0]; ++ighost) {
    563:           const PetscInt i = nNeighbor[0] - ghostOffsetStart[0] + ighost;
    564:           for (d=0; d<stag->entriesPerElement; ++d, ++count) {
    565:             idxGlobal[count] = globalOffset+ j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    566:             idxLocal[count]  =               jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    567:           }
    568:         }
    569:       }
    570:     }

    572:     /* Neighbor 7 (up) */
    573:     if (!dummyEnd[1]) {
    574:       /* We cannot be the last rank in y, though our neighbor may be
    575:        We may be the last rank in x, in which case our neighbor is also */
    576:       const PetscInt         neighbor             = 7;
    577:       const PetscInt         globalOffset         = globalOffsets[stag->neighbors[neighbor]];
    578:       const PetscInt * const nNeighbor            = nNeighbors[neighbor];
    579:       const PetscInt entriesPerElementRowNeighbor = entriesPerElementRow; /* same as here */
    580:       for (j=0; j<ghostOffsetEnd[1]; ++j) {
    581:         const PetscInt jghost = stag->nGhost[1] - ghostOffsetEnd[1] + j;
    582:         for (ighost = ghostOffsetStart[0]; ighost<stag->nGhost[0]-ghostOffsetEnd[0]; ++ighost) {
    583:           const PetscInt i = ighost - ghostOffsetStart[0];
    584:           for (d=0; d<stag->entriesPerElement; ++d, ++count) {
    585:             idxGlobal[count] = globalOffset + j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    586:             idxLocal[count]  =                jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    587:           }
    588:         }
    589:         if (dummyEnd[0]) {
    590:           const PetscInt ighost = stag->nGhost[0]-ghostOffsetEnd[0];
    591:           const PetscInt i = nNeighbor[0];
    592:           for (d=0; d<stag->dof[0]; ++d, ++count) { /* Vertex */
    593:             idxGlobal[count] = globalOffset+ j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    594:             idxLocal[count]  =               jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    595:           }
    596:           for (d=0; d<stag->dof[1]; ++d, ++count) { /* Face */
    597:             idxGlobal[count] = globalOffset+ j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + stag->dof[0]                + d;
    598:             idxLocal[count]  =               jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + stag->dof[0] + stag->dof[1] + d;
    599:           }
    600:         }
    601:       }
    602:     }

    604:     /* Neighbor 8 (up right) */
    605:     if (!star && !dummyEnd[0] && !dummyEnd[1]) {
    606:       /* We can never be a ghosted boundary
    607:          Our neighbor may be a top boundary, a right boundary, or both */
    608:       const PetscInt         neighbor             = 8;
    609:       const PetscInt         globalOffset         = globalOffsets[stag->neighbors[neighbor]];
    610:       const PetscInt * const nNeighbor            = nNeighbors[neighbor];
    611:       const PetscInt entriesPerElementRowNeighbor = nNeighbor[0]*stag->entriesPerElement + (nextToDummyEnd[0] ? entriesPerFace : 0);
    612:       for (j=0; j<ghostOffsetEnd[1]; ++j) {
    613:         const PetscInt jghost = stag->nGhost[1] - ghostOffsetEnd[1] + j;
    614:         for (i=0; i<ghostOffsetEnd[0]; ++i) {
    615:           const PetscInt ighost = stag->nGhost[0] - ghostOffsetEnd[0] + i;
    616:           for (d=0; d<stag->entriesPerElement; ++d, ++count) {
    617:             idxGlobal[count] = globalOffset + j     *entriesPerElementRowNeighbor + i     *stag->entriesPerElement + d;
    618:             idxLocal[count]  =                jghost*entriesPerElementRowGhost    + ighost*stag->entriesPerElement + d;
    619:           }
    620:         }
    621:       }
    622:     }

    626:     /* Create Local and Global ISs (transferring pointer ownership) */
    627:     ISCreateGeneral(PetscObjectComm((PetscObject)dm),entriesToTransferTotal,idxLocal,PETSC_OWN_POINTER,&isLocal);
    628:     ISCreateGeneral(PetscObjectComm((PetscObject)dm),entriesToTransferTotal,idxGlobal,PETSC_OWN_POINTER,&isGlobal);

    630:     /* Create stag->gtol. The order is computed as PETSc ordering, and doesn't include dummy entries */
    631:     {
    632:       Vec local,global;
    633:       VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm),1,stag->entries,PETSC_DECIDE,NULL,&global);
    634:       VecCreateSeqWithArray(PETSC_COMM_SELF,stag->entriesPerElement,stag->entriesGhost,NULL,&local);
    635:       VecScatterCreate(global,isGlobal,local,isLocal,&stag->gtol);
    636:       VecDestroy(&global);
    637:       VecDestroy(&local);
    638:     }

    640:     /* Destroy ISs */
    641:     ISDestroy(&isLocal);
    642:     ISDestroy(&isGlobal);

    644:     /* Next, we iterate over the local entries  again, in local order, recording the global entry to which each maps,
    645:        or -1 if there is none */
    646:     PetscMalloc1(stag->entriesGhost,&idxGlobalAll);

    648:     countAll = 0;

    650:     /* Loop over rows 1/3 : down */
    651:     if (!dummyStart[1]) {
    652:       for (jghost=0; jghost<ghostOffsetStart[1]; ++jghost) {

    654:         /* Loop over columns 1/3 : down left */
    655:         if (!star && !dummyStart[0]) {
    656:           const PetscInt         neighbor     = 0;
    657:           const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    658:           const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    659:           const PetscInt         j            = nNeighbor[1] - ghostOffsetStart[1] + jghost; /* Note: this is actually the same value for the whole row of ranks below, so recomputing it for the next two ranks is redundant, and one could even get rid of jghost entirely if desired */
    660:           const PetscInt         eprNeighbor  = nNeighbor[0] * stag->entriesPerElement;
    661:           for (i=nNeighbor[0]-ghostOffsetStart[0]; i<nNeighbor[0]; ++i) {
    662:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    663:               idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + d;
    664:             }
    665:           }
    666:         } else {
    667:           /* Down Left dummies */
    668:           for (ighost=0; ighost<ghostOffsetStart[0]; ++ighost) {
    669:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    670:               idxGlobalAll[countAll] = -1;
    671:             }
    672:           }
    673:         }

    675:         /* Loop over columns 2/3 : down middle */
    676:         {
    677:           const PetscInt         neighbor     = 1;
    678:           const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    679:           const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    680:           const PetscInt         j            = nNeighbor[1] - ghostOffsetStart[1] + jghost;
    681:           const PetscInt         eprNeighbor  = entriesPerElementRow; /* same as here */
    682:           for (i=0; i<nNeighbor[0]; ++i) {
    683:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    684:               idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + d;
    685:             }
    686:           }
    687:         }

    689:         /* Loop over columns 3/3 : down right */
    690:         if (!star && !dummyEnd[0]) {
    691:           const PetscInt         neighbor     = 2;
    692:           const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    693:           const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    694:           const PetscInt         j            = nNeighbor[1] - ghostOffsetStart[1] + jghost;
    695:           const PetscInt         eprNeighbor  = nNeighbor[0]*stag->entriesPerElement + (nextToDummyEnd[0] ? entriesPerFace : 0);
    696:           for (i=0; i<ghostOffsetEnd[0]; ++i) {
    697:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    698:               idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + d;
    699:             }
    700:           }
    701:         } else if (dummyEnd[0]) {
    702:           /* Down right partial dummy elements, living on the *down* rank */
    703:           const PetscInt         neighbor     = 1;
    704:           const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    705:           const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    706:           const PetscInt         j            = nNeighbor[1] - ghostOffsetStart[1] + jghost;
    707:           const PetscInt         eprNeighbor  = entriesPerElementRow; /* same as here */
    708:           PetscInt dGlobal;
    709:           i = nNeighbor[0];
    710:           for (d=0,dGlobal=0; d<stag->dof[0]; ++d, ++dGlobal, ++countAll) {
    711:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + dGlobal;
    712:           }
    713:           for (; d<stag->dof[0] + stag->dof[1]; ++d, ++countAll) {
    714:             idxGlobalAll[countAll] = -1; /* dummy down edge point */
    715:           }
    716:           for (; d<stag->dof[0] + 2*stag->dof[1]; ++d, ++dGlobal, ++countAll) {
    717:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + dGlobal;
    718:           }
    719:           for (; d<stag->entriesPerElement; ++d, ++countAll) {
    720:             idxGlobalAll[countAll] = -1; /* dummy element point */
    721:           }
    722:           ++i;
    723:           for (; i<nNeighbor[0]+ghostOffsetEnd[0]; ++i) {
    724:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    725:               idxGlobalAll[countAll] = -1;
    726:             }
    727:           }
    728:         } else {
    729:           /* Down Right dummies */
    730:           for (ighost=0; ighost<ghostOffsetEnd[0]; ++ighost) {
    731:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    732:               idxGlobalAll[countAll] = -1;
    733:             }
    734:           }
    735:         }
    736:       }
    737:     } else {
    738:       /* Down dummies row */
    739:       for (jghost=0; jghost<ghostOffsetStart[1]; ++jghost) {
    740:         for (ighost=0; ighost<stag->nGhost[0]; ++ighost) {
    741:           for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    742:             idxGlobalAll[countAll] = -1;
    743:           }
    744:         }
    745:       }
    746:     }

    748:     /* Loop over rows 2/3 : center */
    749:     for (j=0; j<stag->n[1]; ++j) {
    750:       /* Loop over columns 1/3 : left */
    751:       if (!dummyStart[0]) {
    752:         const PetscInt         neighbor     = 3;
    753:         const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    754:         const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    755:         const PetscInt         eprNeighbor  = nNeighbor[0] * stag->entriesPerElement;
    756:         for (i=nNeighbor[0]-ghostOffsetStart[0]; i<nNeighbor[0]; ++i) {
    757:           for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    758:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + d;
    759:           }
    760:         }
    761:       } else {
    762:         /* (Middle) Left dummies */
    763:         for (ighost=0; ighost < ghostOffsetStart[0]; ++ighost) {
    764:           for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    765:             idxGlobalAll[countAll] = -1;
    766:           }
    767:         }
    768:       }

    770:       /* Loop over columns 2/3 : here (the "neighbor" is ourselves, here) */
    771:       {
    772:         const PetscInt neighbor     = 4;
    773:         const PetscInt globalOffset = globalOffsets[stag->neighbors[neighbor]];
    774:         const PetscInt eprNeighbor  = entriesPerElementRow; /* same as here (obviously) */
    775:         for (i=0; i<stag->n[0]; ++i) {
    776:           for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    777:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + d;
    778:           }
    779:         }
    780:       }

    782:       /* Loop over columns 3/3 : right */
    783:       if (!dummyEnd[0]) {
    784:           const PetscInt         neighbor     = 5;
    785:           const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    786:           const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    787:           const PetscInt         eprNeighbor  = nNeighbor[0]*stag->entriesPerElement + (nextToDummyEnd[0] ? entriesPerFace : 0);
    788:         for (i=0; i<ghostOffsetEnd[0]; ++i) {
    789:           for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    790:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + d;
    791:           }
    792:         }
    793:       } else {
    794:         /* -1's for right layer of partial dummies, living on *this* rank */
    795:         const PetscInt         neighbor     = 4;
    796:         const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    797:         const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    798:         const PetscInt         eprNeighbor  = entriesPerElementRow; /* same as here (obviously) */
    799:         PetscInt dGlobal;
    800:         i = nNeighbor[0];
    801:         for (d=0,dGlobal=0; d<stag->dof[0]; ++d, ++dGlobal, ++countAll) {
    802:           idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + dGlobal;
    803:         }
    804:         for (; d<stag->dof[0] + stag->dof[1]; ++d, ++countAll) {
    805:           idxGlobalAll[countAll] = -1; /* dummy down edge point */
    806:         }
    807:         for (; d<stag->dof[0] + 2*stag->dof[1]; ++d, ++dGlobal, ++countAll) {
    808:           idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + dGlobal;
    809:         }
    810:         for (; d<stag->entriesPerElement; ++d, ++countAll) {
    811:           idxGlobalAll[countAll] = -1; /* dummy element point */
    812:         }
    813:         ++i;
    814:         for (; i<nNeighbor[0]+ghostOffsetEnd[0]; ++i) {
    815:           for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    816:             idxGlobalAll[countAll] = -1;
    817:           }
    818:         }
    819:       }
    820:     }

    822:     /* Loop over rows 3/3 : up */
    823:     if (!dummyEnd[1]) {
    824:       for (j=0; j<ghostOffsetEnd[1]; ++j) {

    826:         /* Loop over columns 1/3 : up left */
    827:         if (!star && !dummyStart[0]) {
    828:           const PetscInt         neighbor     = 6;
    829:           const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    830:           const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    831:           const PetscInt         eprNeighbor  = nNeighbor[0] * stag->entriesPerElement;
    832:           for (i=nNeighbor[0]-ghostOffsetStart[0]; i<nNeighbor[0]; ++i) {
    833:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    834:               idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + d;
    835:             }
    836:           }
    837:         } else {
    838:           /* Up Left dummies */
    839:           for (ighost=0; ighost<ghostOffsetStart[0]; ++ighost) {
    840:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    841:               idxGlobalAll[countAll] = -1;
    842:             }
    843:           }
    844:         }

    846:         /* Loop over columns 2/3 : up */
    847:         {
    848:           const PetscInt         neighbor     = 7;
    849:           const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    850:           const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    851:           const PetscInt         eprNeighbor  = entriesPerElementRow; /* Same as here */
    852:           for (i=0; i<nNeighbor[0]; ++i) {
    853:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    854:               idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + d;
    855:             }
    856:           }
    857:         }

    859:         /* Loop over columns 3/3 : up right */
    860:         if (!star && !dummyEnd[0]) {
    861:           const PetscInt         neighbor     = 8;
    862:           const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    863:           const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    864:           const PetscInt         eprNeighbor  = nNeighbor[0]*stag->entriesPerElement + (nextToDummyEnd[0] ? entriesPerFace : 0);
    865:           for (i=0; i<ghostOffsetEnd[0]; ++i) {
    866:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    867:               idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + d;
    868:             }
    869:           }
    870:         } else if (dummyEnd[0]) {
    871:           /* -1's for right layer of partial dummies, living on rank above */
    872:           const PetscInt         neighbor     = 7;
    873:           const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    874:           const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    875:           const PetscInt         eprNeighbor  = entriesPerElementRow; /* Same as here */
    876:           PetscInt dGlobal;
    877:           i = nNeighbor[0];
    878:           for (d=0,dGlobal=0; d<stag->dof[0]; ++d, ++dGlobal, ++countAll) {
    879:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + dGlobal;
    880:           }
    881:           for (; d<stag->dof[0] + stag->dof[1]; ++d, ++countAll) {
    882:             idxGlobalAll[countAll] = -1; /* dummy down edge point */
    883:           }
    884:           for (; d<stag->dof[0] + 2*stag->dof[1]; ++d, ++dGlobal, ++countAll) {
    885:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*stag->entriesPerElement + dGlobal;
    886:           }
    887:           for (; d<stag->entriesPerElement; ++d, ++countAll) {
    888:             idxGlobalAll[countAll] = -1; /* dummy element point */
    889:           }
    890:           ++i;
    891:           for (; i<nNeighbor[0]+ghostOffsetEnd[0]; ++i) {
    892:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    893:               idxGlobalAll[countAll] = -1;
    894:             }
    895:           }
    896:         } else {
    897:           /* Up Right dummies */
    898:           for (ighost=0; ighost<ghostOffsetEnd[0]; ++ighost) {
    899:             for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    900:               idxGlobalAll[countAll] = -1;
    901:             }
    902:           }
    903:         }
    904:       }
    905:     } else {
    906:       j = stag->n[1];
    907:       /* Top layer of partial dummies */

    909:       /* up left partial dummies layer : Loop over columns 1/3 : living on *left* neighbor */
    910:       if (!dummyStart[0]) {
    911:         const PetscInt         neighbor     = 3;
    912:         const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    913:         const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    914:         const PetscInt         eprNeighbor  = nNeighbor[0] * stag->entriesPerElement;
    915:         for (i=nNeighbor[0]-ghostOffsetStart[0]; i<nNeighbor[0]; ++i) {
    916:           for (d=0; d<stag->dof[0] + stag->dof[1]; ++d, ++countAll) {
    917:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*entriesPerFace + d; /* Note entriesPerFace here */
    918:           }
    919:           for (; d<stag->entriesPerElement; ++d, ++countAll) {
    920:             idxGlobalAll[countAll] = -1; /* dummy left edge and element points */
    921:           }
    922:         }
    923:       } else {
    924:         for (ighost=0; ighost<ghostOffsetStart[0]; ++ighost) {
    925:           for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    926:             idxGlobalAll[countAll] = -1;
    927:           }
    928:         }
    929:       }

    931:       /* up partial dummies layer : Loop over columns 2/3 : living on *this* rank */
    932:       {
    933:         const PetscInt         neighbor     = 4;
    934:         const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    935:         const PetscInt         eprNeighbor  = entriesPerElementRow; /* same as here (obviously) */
    936:         for (i=0; i<stag->n[0]; ++i) {
    937:           for (d=0; d<stag->dof[0] + stag->dof[1]; ++d, ++countAll) {
    938:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*entriesPerFace + d; /* Note entriesPerFace here */
    939:           }
    940:           for (; d<stag->entriesPerElement; ++d, ++countAll) {
    941:             idxGlobalAll[countAll] = -1; /* dummy left edge and element points */
    942:           }
    943:         }
    944:       }

    946:       if (!dummyEnd[0]) {
    947:         /* up right partial dummies layer : Loop over columns 3/3 :  living on *right* neighbor */
    948:         const PetscInt         neighbor     = 5;
    949:         const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    950:         const PetscInt * const nNeighbor    = nNeighbors[neighbor];
    951:         const PetscInt         eprNeighbor  = nNeighbor[0]*stag->entriesPerElement + (nextToDummyEnd[0] ? entriesPerFace : 0);
    952:         for (i = 0; i<ghostOffsetEnd[0]; ++i) {
    953:           for (d=0; d<stag->dof[0] + stag->dof[1]; ++d, ++countAll) {
    954:             idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*entriesPerFace + d; /* Note entriesPerFace here */
    955:           }
    956:           for (; d<stag->entriesPerElement; ++d, ++countAll) {
    957:             idxGlobalAll[countAll] = -1; /* dummy left edge and element points */
    958:           }
    959:         }
    960:       } else {
    961:         /* Top partial dummies layer : Loop over columns 3/3 : right, living *here* */
    962:         const PetscInt         neighbor     = 4;
    963:         const PetscInt         globalOffset = globalOffsets[stag->neighbors[neighbor]];
    964:         const PetscInt         eprNeighbor  = entriesPerElementRow; /* same as here (obviously) */
    965:         i = stag->n[0];
    966:         for (d=0; d<stag->dof[0]; ++d, ++countAll) { /* Note just the vertex here */
    967:           idxGlobalAll[countAll] = globalOffset + j*eprNeighbor + i*entriesPerFace + d; /* Note entriesPerFace here */
    968:         }
    969:         for (; d<stag->entriesPerElement; ++d, ++countAll) {
    970:           idxGlobalAll[countAll] = -1; /* dummy bottom edge, left edge and element points */
    971:         }
    972:         ++i;
    973:         for (; i<stag->n[0] + ghostOffsetEnd[0]; ++i) {
    974:           for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    975:             idxGlobalAll[countAll] = -1;
    976:           }
    977:         }
    978:       }
    979:       ++j;
    980:       /* Additional top dummy layers */
    981:       for (; j<stag->n[1]+ghostOffsetEnd[1]; ++j) {
    982:         for (ighost=0; ighost<stag->nGhost[0]; ++ighost) {
    983:           for (d=0; d<stag->entriesPerElement; ++d, ++countAll) {
    984:             idxGlobalAll[countAll] = -1;
    985:           }
    986:         }
    987:       }
    988:     }

    990:     /* Create local-to-global map (in local ordering, includes maps to -1 for dummy points) */
    991:     ISLocalToGlobalMappingCreate(comm,1,stag->entriesGhost,idxGlobalAll,PETSC_OWN_POINTER,&dm->ltogmap);
    992:     PetscLogObjectParent((PetscObject)dm,(PetscObject)dm->ltogmap);
    993:   }

    995:   /* In special cases, create a dedicated injective local-to-global map */
    996:   if ((stag->boundaryType[0] == DM_BOUNDARY_PERIODIC && stag->nRanks[0] == 1) ||
    997:       (stag->boundaryType[1] == DM_BOUNDARY_PERIODIC && stag->nRanks[1] == 1)) {
    998:     DMStagPopulateLocalToGlobalInjective(dm);
    999:   }

    1001:   /* Free global offsets */
    1002:   PetscFree(globalOffsets);

    1004:   /* Precompute location offsets */
    1005:   DMStagComputeLocationOffsets_2d(dm);

    1007:   /* View from Options */
    1008:   DMViewFromOptions(dm,NULL,"-dm_view");

    1010:   return 0;
    1011: }

    1013: /* adapted from da2.c */
    1014: static PetscErrorCode DMStagSetUpBuildRankGrid_2d(DM dm)
    1015: {
    1016:   DM_Stag * const stag = (DM_Stag*)dm->data;
    1017:   PetscInt        m,n;
    1018:   PetscMPIInt     rank,size;
    1019:   const PetscInt  M = stag->N[0];
    1020:   const PetscInt  N = stag->N[1];

    1022:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
    1023:   MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);
    1024:   m = stag->nRanks[0];
    1025:   n = stag->nRanks[1];
    1026:   if (m != PETSC_DECIDE) {
    1029:   }
    1030:   if (n != PETSC_DECIDE) {
    1033:   }
    1034:   if (m == PETSC_DECIDE || n == PETSC_DECIDE) {
    1035:     if (n != PETSC_DECIDE) {
    1036:       m = size/n;
    1037:     } else if (m != PETSC_DECIDE) {
    1038:       n = size/m;
    1039:     } else {
    1040:       /* try for squarish distribution */
    1041:       m = (PetscInt)(0.5 + PetscSqrtReal(((PetscReal)M)*((PetscReal)size)/((PetscReal)N)));
    1042:       if (!m) m = 1;
    1043:       while (m > 0) {
    1044:         n = size/m;
    1045:         if (m*n == size) break;
    1046:         m--;
    1047:       }
    1048:       if (M > N && m < n) {PetscInt _m = m; m = n; n = _m;}
    1049:     }
    1054:   stag->nRanks[0] = m;
    1055:   stag->nRanks[1] = n;
    1056:   return 0;
    1057: }

    1059: static PetscErrorCode DMStagSetUpBuildNeighbors_2d(DM dm)
    1060: {
    1061:   DM_Stag * const stag = (DM_Stag*)dm->data;
    1062:   PetscInt        d,i;
    1063:   PetscBool       per[2],first[2],last[2];
    1064:   PetscInt        neighborRank[9][2],r[2],n[2];
    1065:   const PetscInt  dim = 2;

    1069:   /* Assemble some convenience variables */
    1070:   for (d=0; d<dim; ++d) {
    1071:     per[d]   = (PetscBool)(stag->boundaryType[d] == DM_BOUNDARY_PERIODIC);
    1072:     first[d] = stag->firstRank[d];
    1073:     last[d]  = stag->lastRank[d];
    1074:     r[d]     = stag->rank[d];
    1075:     n[d]     = stag->nRanks[d];
    1076:   }

    1078:   /* First, compute the position in the rank grid for all neighbors */
    1079:   neighborRank[0][0]  = first[0] ? (per[0] ?  n[0]-1 : -1) : r[0] - 1; /* left  down */
    1080:   neighborRank[0][1]  = first[1] ? (per[1] ?  n[1]-1 : -1) : r[1] - 1;

    1082:   neighborRank[1][0] =                                      r[0]    ; /*       down */
    1083:   neighborRank[1][1] = first[1] ? (per[1] ?  n[1]-1 : -1) : r[1] - 1;

    1085:   neighborRank[2][0] = last[0]  ? (per[0] ?  0      : -1) : r[0] + 1; /* right down */
    1086:   neighborRank[2][1] = first[1] ? (per[1] ?  n[1]-1 : -1) : r[1] - 1;

    1088:   neighborRank[3][0] = first[0] ? (per[0] ?  n[0]-1 : -1) : r[0] - 1; /* left       */
    1089:   neighborRank[3][1] =                                      r[1]    ;

    1091:   neighborRank[4][0] =                                      r[0]    ; /*            */
    1092:   neighborRank[4][1] =                                      r[1]    ;

    1094:   neighborRank[5][0] = last[0]  ? (per[0] ?  0      : -1) : r[0] + 1; /* right      */
    1095:   neighborRank[5][1] =                                      r[1]    ;

    1097:   neighborRank[6][0] = first[0] ? (per[0] ?  n[0]-1 : -1) : r[0] - 1; /* left  up   */
    1098:   neighborRank[6][1] = last[1]  ? (per[1] ?  0      : -1) : r[1] + 1;

    1100:   neighborRank[7][0] =                                      r[0]    ; /*       up   */
    1101:   neighborRank[7][1] = last[1]  ? (per[1] ?  0      : -1) : r[1] + 1;

    1103:   neighborRank[8][0] = last[0]  ? (per[0] ?  0      : -1) : r[0] + 1; /* right up   */
    1104:   neighborRank[8][1] = last[1]  ? (per[1] ?  0      : -1) : r[1] + 1;

    1106:   /* Then, compute the rank of each in the linear ordering */
    1107:   PetscMalloc1(9,&stag->neighbors);
    1108:   for (i=0; i<9; ++i) {
    1109:     if  (neighborRank[i][0] >= 0 && neighborRank[i][1] >=0) {
    1110:       stag->neighbors[i] = neighborRank[i][0] + n[0]*neighborRank[i][1];
    1111:     } else {
    1112:       stag->neighbors[i] = -1;
    1113:     }
    1114:   }

    1116:   return 0;
    1117: }

    1119: static PetscErrorCode DMStagSetUpBuildGlobalOffsets_2d(DM dm,PetscInt **pGlobalOffsets)
    1120: {
    1121:   const DM_Stag * const stag = (DM_Stag*)dm->data;
    1122:   PetscInt              *globalOffsets;
    1123:   PetscInt              i,j,d,entriesPerFace,count;
    1124:   PetscMPIInt           size;
    1125:   PetscBool             extra[2];

    1127:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
    1128:   for (d=0; d<2; ++d) extra[d] = (PetscBool)(stag->boundaryType[d] != DM_BOUNDARY_PERIODIC); /* Extra points in global rep */
    1129:   entriesPerFace = stag->dof[0] + stag->dof[1];
    1130:   PetscMalloc1(size,pGlobalOffsets);
    1131:   globalOffsets = *pGlobalOffsets;
    1132:   globalOffsets[0] = 0;
    1133:   count = 1; /* note the count is offset by 1 here. We add the size of the previous rank */
    1134:   for (j=0; j<stag->nRanks[1]-1; ++j) {
    1135:     const PetscInt nnj = stag->l[1][j];
    1136:     for (i=0; i<stag->nRanks[0]-1; ++i) {
    1137:       const PetscInt nni = stag->l[0][i];
    1138:       globalOffsets[count] = globalOffsets[count-1] + nnj*nni*stag->entriesPerElement; /* No right/top/front boundaries */
    1139:       ++count;
    1140:     }
    1141:     {
    1142:       /* i = stag->nRanks[0]-1; */
    1143:       const PetscInt nni = stag->l[0][i];
    1144:       globalOffsets[count] = globalOffsets[count-1] + nnj*nni*stag->entriesPerElement
    1145:                              + (extra[0] ? nnj*entriesPerFace : 0); /* Extra edges on the right */
    1146:       ++count;
    1147:     }
    1148:   }
    1149:   {
    1150:     /* j = stag->nRanks[1]-1; */
    1151:     const PetscInt nnj = stag->l[1][j];
    1152:     for (i=0; i<stag->nRanks[0]-1; ++i) {
    1153:       const PetscInt nni = stag->l[0][i];
    1154:       globalOffsets[count] = globalOffsets[count-1] + nni*nnj*stag->entriesPerElement
    1155:                              + (extra[1] ? nni*entriesPerFace : 0); /* Extra edges on the top */
    1156:       ++count;
    1157:     }
    1158:     /* Don't need to compute entries in last element */
    1159:   }
    1160:   return 0;
    1161: }

    1163: static PetscErrorCode DMStagComputeLocationOffsets_2d(DM dm)
    1164: {
    1165:   DM_Stag * const stag = (DM_Stag*)dm->data;
    1166:   const PetscInt  epe = stag->entriesPerElement;
    1167:   const PetscInt  epr = stag->nGhost[0]*epe;

    1169:   PetscMalloc1(DMSTAG_NUMBER_LOCATIONS,&stag->locationOffsets);
    1170:   stag->locationOffsets[DMSTAG_DOWN_LEFT]  = 0;
    1171:   stag->locationOffsets[DMSTAG_DOWN]       = stag->locationOffsets[DMSTAG_DOWN_LEFT]  + stag->dof[0];
    1172:   stag->locationOffsets[DMSTAG_DOWN_RIGHT] = stag->locationOffsets[DMSTAG_DOWN_LEFT]  + epe;
    1173:   stag->locationOffsets[DMSTAG_LEFT]       = stag->locationOffsets[DMSTAG_DOWN]       + stag->dof[1];
    1174:   stag->locationOffsets[DMSTAG_ELEMENT]    = stag->locationOffsets[DMSTAG_LEFT]       + stag->dof[1];
    1175:   stag->locationOffsets[DMSTAG_RIGHT]      = stag->locationOffsets[DMSTAG_LEFT]       + epe;
    1176:   stag->locationOffsets[DMSTAG_UP_LEFT]    = stag->locationOffsets[DMSTAG_DOWN_LEFT]  + epr;
    1177:   stag->locationOffsets[DMSTAG_UP]         = stag->locationOffsets[DMSTAG_DOWN]       + epr;
    1178:   stag->locationOffsets[DMSTAG_UP_RIGHT]   = stag->locationOffsets[DMSTAG_UP_LEFT]    + epe;
    1179:   return 0;
    1180: }

    1182: PETSC_INTERN PetscErrorCode DMStagPopulateLocalToGlobalInjective_2d(DM dm)
    1183: {
    1184:   DM_Stag * const stag = (DM_Stag*)dm->data;
    1185:   PetscInt        *idxLocal,*idxGlobal,*globalOffsetsRecomputed;
    1186:   const PetscInt  *globalOffsets;
    1187:   PetscInt        i,j,d,count,entriesPerCorner,entriesPerFace,entriesPerElementRowGhost,entriesPerElementRow,ghostOffsetStart[2];
    1188:   IS              isLocal,isGlobal;
    1189:   PetscBool       dummyEnd[2];

    1191:   DMStagSetUpBuildGlobalOffsets_2d(dm,&globalOffsetsRecomputed); /* note that we don't actually use all of these. An available optimization is to pass them, when available */
    1192:   globalOffsets = globalOffsetsRecomputed;
    1193:   PetscMalloc1(stag->entries,&idxLocal);
    1194:   PetscMalloc1(stag->entries,&idxGlobal);
    1195:   for (d=0; d<2; ++d) dummyEnd[d]   = (PetscBool)(stag->lastRank[d] && stag->boundaryType[d] != DM_BOUNDARY_PERIODIC);
    1196:   entriesPerCorner          = stag->dof[0];
    1197:   entriesPerFace            = stag->dof[0] + stag->dof[1];
    1198:   entriesPerElementRow      = stag->n[0]     *stag->entriesPerElement + (dummyEnd[0] ? entriesPerFace : 0);
    1199:   entriesPerElementRowGhost = stag->nGhost[0]*stag->entriesPerElement;
    1200:   count = 0;
    1201:   for (d=0; d<2; ++d) ghostOffsetStart[d] = stag->start[d] - stag->startGhost[d];
    1202:   {
    1203:     const PetscInt neighbor     = 4;
    1204:     const PetscInt globalOffset = globalOffsets[stag->neighbors[neighbor]];
    1205:     for (j=0; j<stag->n[1]; ++j) {
    1206:       const PetscInt jghost = j + ghostOffsetStart[1];
    1207:       for (i=0; i<stag->n[0]; ++i) {
    1208:         const PetscInt ighost = i + ghostOffsetStart[0];
    1209:         for (d=0; d<stag->entriesPerElement; ++d, ++count) {
    1210:           idxGlobal[count] = globalOffset + j     *entriesPerElementRow       + i     *stag->entriesPerElement + d;
    1211:           idxLocal[count]  =                jghost*entriesPerElementRowGhost  + ighost*stag->entriesPerElement + d;
    1212:         }
    1213:       }
    1214:       if (dummyEnd[0]) {
    1215:         const PetscInt ighost = i + ghostOffsetStart[0];
    1216:         i = stag->n[0];
    1217:         for (d=0; d<stag->dof[0]; ++d, ++count) { /* vertex first */
    1218:           idxGlobal[count] = globalOffset + j     *entriesPerElementRow      + i     *stag->entriesPerElement + d;
    1219:           idxLocal[count]  =                jghost*entriesPerElementRowGhost + ighost*stag->entriesPerElement + d;
    1220:         }
    1221:         for (d=0; d<stag->dof[1]; ++d, ++count) { /* then left ege (skipping bottom edge) */
    1222:           idxGlobal[count] = globalOffset + j     *entriesPerElementRow       + i     *stag->entriesPerElement + stag->dof[0]                + d;
    1223:           idxLocal[count]  =                jghost*entriesPerElementRowGhost  + ighost*stag->entriesPerElement + stag->dof[0] + stag->dof[1] + d;
    1224:         }
    1225:       }
    1226:     }
    1227:     if (dummyEnd[1]) {
    1228:       const PetscInt jghost = j + ghostOffsetStart[1];
    1229:       j = stag->n[1];
    1230:       for (i=0; i<stag->n[0]; ++i) {
    1231:         const PetscInt ighost = i + ghostOffsetStart[0];
    1232:         for (d=0; d<entriesPerFace; ++d, ++count) { /* vertex and bottom edge (which are the first entries) */
    1233:           idxGlobal[count] = globalOffset + j     *entriesPerElementRow +      i*entriesPerFace               + d; /* note i increment by entriesPerFace */
    1234:           idxLocal[count]  =                jghost*entriesPerElementRowGhost + ighost*stag->entriesPerElement + d;
    1235:         }
    1236:       }
    1237:       if (dummyEnd[0]) {
    1238:         const PetscInt ighost = i + ghostOffsetStart[0];
    1239:         i = stag->n[0];
    1240:         for (d=0; d<entriesPerCorner; ++d, ++count) { /* vertex only */
    1241:           idxGlobal[count] = globalOffset + j     *entriesPerElementRow       + i     *entriesPerFace          + d; /* note i increment by entriesPerFace */
    1242:           idxLocal[count]  =                jghost*entriesPerElementRowGhost  + ighost*stag->entriesPerElement + d;
    1243:         }
    1244:       }
    1245:     }
    1246:   }
    1247:   ISCreateGeneral(PetscObjectComm((PetscObject)dm),stag->entries,idxLocal,PETSC_OWN_POINTER,&isLocal);
    1248:   ISCreateGeneral(PetscObjectComm((PetscObject)dm),stag->entries,idxGlobal,PETSC_OWN_POINTER,&isGlobal);
    1249:   {
    1250:     Vec local,global;
    1251:     VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm),1,stag->entries,PETSC_DECIDE,NULL,&global);
    1252:     VecCreateSeqWithArray(PETSC_COMM_SELF,stag->entriesPerElement,stag->entriesGhost,NULL,&local);
    1253:     VecScatterCreate(local,isLocal,global,isGlobal,&stag->ltog_injective);
    1254:     VecDestroy(&global);
    1255:     VecDestroy(&local);
    1256:   }
    1257:   ISDestroy(&isLocal);
    1258:   ISDestroy(&isGlobal);
    1259:   if (globalOffsetsRecomputed) {
    1260:     PetscFree(globalOffsetsRecomputed);
    1261:   }
    1262:   return 0;
    1263: }

    1265: PETSC_INTERN PetscErrorCode DMCreateMatrix_Stag_2D_AIJ_Assemble(DM dm,Mat A)
    1266: {
    1267:   PetscInt          entries,dof[DMSTAG_MAX_STRATA],epe,stencil_width,N[2],start[2],n[2],n_extra[2];
    1268:   DMStagStencilType stencil_type;
    1269:   DMBoundaryType    boundary_type[2];

    1271:   DMStagGetDOF(dm,&dof[0],&dof[1],&dof[2],NULL);
    1272:   DMStagGetStencilType(dm,&stencil_type);
    1273:   DMStagGetStencilWidth(dm,&stencil_width);
    1274:   DMStagGetEntries(dm,&entries);
    1275:   DMStagGetEntriesPerElement(dm,&epe);
    1276:   DMStagGetCorners(dm,&start[0],&start[1],NULL,&n[0],&n[1],NULL,&n_extra[0],&n_extra[1],NULL);
    1277:   DMStagGetGlobalSizes(dm,&N[0],&N[1],NULL);
    1278:   DMStagGetBoundaryTypes(dm,&boundary_type[0],&boundary_type[1],NULL);

    1280:   if (stencil_type == DMSTAG_STENCIL_NONE) {
    1281:     /* Couple all DOF at each location to each other */
    1282:     DMStagStencil *row_vertex,*row_edge_down,*row_edge_left,*row_element;

    1284:     PetscMalloc1(dof[0],&row_vertex);
    1285:     for (PetscInt c=0; c<dof[0]; ++c) {
    1286:       row_vertex[c].loc = DMSTAG_DOWN_LEFT;
    1287:       row_vertex[c].c = c;
    1288:     }

    1290:     PetscMalloc1(dof[1],&row_edge_down);
    1291:     for (PetscInt c=0; c<dof[1]; ++c) {
    1292:       row_edge_down[c].loc = DMSTAG_DOWN;
    1293:       row_edge_down[c].c = c;
    1294:     }

    1296:     PetscMalloc1(dof[1],&row_edge_left);
    1297:     for (PetscInt c=0; c<dof[1]; ++c) {
    1298:       row_edge_left[c].loc = DMSTAG_LEFT;
    1299:       row_edge_left[c].c = c;
    1300:     }

    1302:     PetscMalloc1(dof[2],&row_element);
    1303:     for (PetscInt c=0; c<dof[2]; ++c) {
    1304:       row_element[c].loc = DMSTAG_ELEMENT;
    1305:       row_element[c].c = c;
    1306:     }

    1308:     for (PetscInt ey=start[1]; ey<start[1]+n[1]+n_extra[1]; ++ey) {
    1309:       for (PetscInt ex=start[0]; ex<start[0]+n[0]+n_extra[0]; ++ex) {
    1310:         {
    1311:           for (PetscInt c=0; c<dof[0]; ++c){
    1312:             row_vertex[c].i = ex;
    1313:             row_vertex[c].j = ey;
    1314:           }
    1315:           DMStagMatSetValuesStencil(dm,A,dof[0],row_vertex,dof[0],row_vertex,NULL,INSERT_VALUES);
    1316:         }
    1317:         if (ex < N[0]) {
    1318:           for (PetscInt c=0; c<dof[1]; ++c){
    1319:             row_edge_down[c].i = ex;
    1320:             row_edge_down[c].j = ey;
    1321:           }
    1322:           DMStagMatSetValuesStencil(dm,A,dof[1],row_edge_down,dof[1],row_edge_down,NULL,INSERT_VALUES);
    1323:         }
    1324:         if (ey < N[1]) {
    1325:           for (PetscInt c=0; c<dof[1]; ++c){
    1326:             row_edge_left[c].i = ex;
    1327:             row_edge_left[c].j = ey;
    1328:           }
    1329:           DMStagMatSetValuesStencil(dm,A,dof[1],row_edge_left,dof[1],row_edge_left,NULL,INSERT_VALUES);
    1330:         }
    1331:         if (ex < N[0] && ey < N[1]) {
    1332:           for (PetscInt c=0; c<dof[2]; ++c) {
    1333:             row_element[c].i = ex;
    1334:             row_element[c].j = ey;
    1335:           }
    1336:           DMStagMatSetValuesStencil(dm,A,dof[2],row_element,dof[2],row_element,NULL,INSERT_VALUES);
    1337:         }
    1338:       }
    1339:     }
    1340:     PetscFree(row_vertex);
    1341:     PetscFree(row_edge_left);
    1342:     PetscFree(row_edge_down);
    1343:     PetscFree(row_element);
    1344:   } else if (stencil_type == DMSTAG_STENCIL_STAR || stencil_type == DMSTAG_STENCIL_BOX) {
    1345:     DMStagStencil *col,*row;

    1347:     PetscMalloc1(epe,&row);
    1348:     {
    1349:       PetscInt nrows = 0;

    1351:       for (PetscInt c=0; c<dof[0]; ++c) {
    1352:         row[nrows].c = c;
    1353:         row[nrows].loc = DMSTAG_DOWN_LEFT;
    1354:         ++nrows;
    1355:       }
    1356:       for (PetscInt c=0; c<dof[1]; ++c) {
    1357:         row[nrows].c = c;
    1358:         row[nrows].loc = DMSTAG_LEFT;
    1359:         ++nrows;
    1360:       }
    1361:       for (PetscInt c=0; c<dof[1]; ++c) {
    1362:         row[nrows].c = c;
    1363:         row[nrows].loc = DMSTAG_DOWN;
    1364:         ++nrows;
    1365:       }
    1366:       for (PetscInt c=0; c<dof[2]; ++c) {
    1367:         row[nrows].c = c;
    1368:         row[nrows].loc = DMSTAG_ELEMENT;
    1369:         ++nrows;
    1370:       }
    1371:     }

    1373:     PetscMalloc1(epe,&col);
    1374:     {
    1375:       PetscInt ncols = 0;

    1377:       for (PetscInt c=0; c<dof[0]; ++c) {
    1378:         col[ncols].c = c;
    1379:         col[ncols].loc = DMSTAG_DOWN_LEFT;
    1380:         ++ncols;
    1381:       }
    1382:       for (PetscInt c=0; c<dof[1]; ++c) {
    1383:         col[ncols].c = c;
    1384:         col[ncols].loc = DMSTAG_LEFT;
    1385:         ++ncols;
    1386:       }
    1387:       for (PetscInt c=0; c<dof[1]; ++c) {
    1388:         col[ncols].c = c;
    1389:         col[ncols].loc = DMSTAG_DOWN;
    1390:         ++ncols;
    1391:       }
    1392:       for (PetscInt c=0; c<dof[2]; ++c) {
    1393:         col[ncols].c = c;
    1394:         col[ncols].loc = DMSTAG_ELEMENT;
    1395:         ++ncols;
    1396:       }
    1397:     }

    1399:     for (PetscInt ey=start[1]; ey<start[1]+n[1]+n_extra[1]; ++ey) {
    1400:       for (PetscInt ex=start[0]; ex<start[0]+n[0]+n_extra[0]; ++ex) {
    1401:         for (PetscInt i=0; i<epe; ++i) {
    1402:           row[i].i = ex;
    1403:           row[i].j = ey;
    1404:         }
    1405:         for (PetscInt offset_y = -stencil_width; offset_y<=stencil_width; ++offset_y) {
    1406:           const PetscInt ey_offset = ey + offset_y;
    1407:           for (PetscInt offset_x = -stencil_width; offset_x<=stencil_width; ++offset_x) {
    1408:             const PetscInt ex_offset = ex + offset_x;
    1409:             /* Only set values corresponding to elements which can have non-dummy entries,
    1410:                meaning those that map to unknowns in the global representation. In the periodic
    1411:                case, this is the entire stencil, but in all other cases, only includes a single
    1412:                "extra" element which is partially outside the physical domain (those points in the
    1413:                global representation */
    1414:             if ((stencil_type == DMSTAG_STENCIL_BOX || offset_x == 0 || offset_y == 0) &&
    1415:                 (boundary_type[0] == DM_BOUNDARY_PERIODIC || (ex_offset < N[0]+1 && ex_offset >= 0)) &&
    1416:                 (boundary_type[1] == DM_BOUNDARY_PERIODIC || (ey_offset < N[1]+1 && ey_offset >= 0)))
    1417:             {
    1418:               for (PetscInt i=0; i<epe; ++i) {
    1419:                 col[i].i = ex_offset;
    1420:                 col[i].j = ey_offset;
    1421:               }
    1422:               DMStagMatSetValuesStencil(dm,A,epe,row,epe,col,NULL,INSERT_VALUES);
    1423:             }
    1424:           }
    1425:         }
    1426:       }
    1427:     }
    1428:     PetscFree(row);
    1429:     PetscFree(col);
    1430:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Unsupported stencil type %s",DMStagStencilTypes[stencil_type]);
    1431:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    1432:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
    1433:   return 0;
    1434: }