Actual source code: dadd.c

      1: #include <petsc/private/dmdaimpl.h>

      3: /*@
      4:   DMDACreatePatchIS - Creates an index set corresponding to a patch of the DA.

      6:   Collective

      8:   Input Parameters:
      9: +  da - the DMDA
     10: .  lower - a matstencil with i, j and k corresponding to the lower corner of the patch
     11: .  upper - a matstencil with i, j and k corresponding to the upper corner of the patch
     12: -  offproc - indicate whether the returned IS will contain off process indices

     14:   Output Parameters:
     15: .  is - the IS corresponding to the patch

     17:   Level: developer

     19: Notes:
     20: This routine always returns an IS on the DMDA's comm, if offproc is set to PETSC_TRUE,
     21: the routine returns an IS with all the indices requested regardless of whether these indices
     22: are present on the requesting rank or not. Thus, it is upon the caller to ensure that
     23: the indices returned in this mode are appropriate. If offproc is set to PETSC_FALSE,
     24: the IS only returns the subset of indices that are present on the requesting rank and there
     25: is no duplication of indices.

     27: .seealso: DMDACreateDomainDecomposition(), DMDACreateDomainDecompositionScatters()
     28: @*/
     29: PetscErrorCode DMDACreatePatchIS(DM da,MatStencil *lower,MatStencil *upper,IS *is, PetscBool offproc)
     30: {
     31:   PetscInt       ms=0,ns=0,ps=0;
     32:   PetscInt       mw=0,nw=0,pw=0;
     33:   PetscInt       me=1,ne=1,pe=1;
     34:   PetscInt       mr=0,nr=0,pr=0;
     35:   PetscInt       ii,jj,kk;
     36:   PetscInt       si,sj,sk;
     37:   PetscInt       i,j,k,l,idx=0;
     38:   PetscInt       base;
     39:   PetscInt       xm=1,ym=1,zm=1;
     40:   PetscInt       ox,oy,oz;
     41:   PetscInt       m,n,p,M,N,P,dof;
     42:   const PetscInt *lx,*ly,*lz;
     43:   PetscInt       nindices;
     44:   PetscInt       *indices;
     45:   DM_DA          *dd = (DM_DA*)da->data;
     46:   PetscBool      skip_i=PETSC_TRUE, skip_j=PETSC_TRUE, skip_k=PETSC_TRUE;
     47:   PetscBool      valid_j=PETSC_FALSE, valid_k=PETSC_FALSE; /* DMDA has at least 1 dimension */

     49:   M = dd->M; N = dd->N; P = dd->P;
     50:   m = dd->m; n = dd->n; p = dd->p;
     51:   dof = dd->w;

     53:   nindices = -1;
     54:   if (PetscLikely(upper->i - lower->i)) {
     55:     nindices = nindices*(upper->i - lower->i);
     56:     skip_i=PETSC_FALSE;
     57:   }
     58:   if (N>1) {
     59:     valid_j = PETSC_TRUE;
     60:     if (PetscLikely(upper->j - lower->j)) {
     61:       nindices = nindices*(upper->j - lower->j);
     62:       skip_j=PETSC_FALSE;
     63:     }
     64:   }
     65:   if (P>1) {
     66:     valid_k = PETSC_TRUE;
     67:     if (PetscLikely(upper->k - lower->k)) {
     68:       nindices = nindices*(upper->k - lower->k);
     69:       skip_k=PETSC_FALSE;
     70:     }
     71:   }
     72:   if (PetscLikely(nindices<0)) {
     73:     if (PetscUnlikely(skip_i && skip_j && skip_k)) {
     74:       nindices = 0;
     75:     } else nindices = nindices*(-1);
     76:   } else SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONG,"Lower and Upper stencils are identical! Please check inputs.");

     78:   PetscMalloc1(nindices*dof,&indices);
     79:   DMDAGetOffset(da,&ox,&oy,&oz,NULL,NULL,NULL);

     81:   if (!valid_k) {
     82:     k = 0;
     83:     upper->k=0;
     84:     lower->k=0;
     85:   }
     86:   if (!valid_j) {
     87:     j = 0;
     88:     upper->j=0;
     89:     lower->j=0;
     90:   }

     92:   if (offproc) {
     93:     DMDAGetOwnershipRanges(da,&lx,&ly,&lz);
     94:     /* start at index 0 on processor 0 */
     95:     mr = 0;
     96:     nr = 0;
     97:     pr = 0;
     98:     ms = 0;
     99:     ns = 0;
    100:     ps = 0;
    101:     if (lx) me = lx[0];
    102:     if (ly) ne = ly[0];
    103:     if (lz) pe = lz[0];
    104:     /*
    105:        If no indices are to be returned, create an empty is,
    106:        this prevents hanging in while loops
    107:     */
    108:     if (skip_i && skip_j && skip_k) goto createis;
    109:     /*
    110:        do..while loops to ensure the block gets entered once,
    111:        regardless of control condition being met, necessary for
    112:        cases when a subset of skip_i/j/k is true
    113:     */
    114:     if (skip_k) k = upper->k-oz; else k = lower->k-oz;
    115:     do {
    116:       if (skip_j) j = upper->j-oy; else j = lower->j-oy;
    117:       do {
    118:         if (skip_i) i = upper->i-ox; else i = lower->i-ox;
    119:         do {
    120:           /* "actual" indices rather than ones outside of the domain */
    121:           ii = i;
    122:           jj = j;
    123:           kk = k;
    124:           if (ii < 0) ii = M + ii;
    125:           if (jj < 0) jj = N + jj;
    126:           if (kk < 0) kk = P + kk;
    127:           if (ii > M-1) ii = ii - M;
    128:           if (jj > N-1) jj = jj - N;
    129:           if (kk > P-1) kk = kk - P;
    130:           /* gone out of processor range on x axis */
    131:           while (ii > me-1 || ii < ms) {
    132:             if (mr == m-1) {
    133:               ms = 0;
    134:               me = lx[0];
    135:               mr = 0;
    136:             } else {
    137:               mr++;
    138:               ms = me;
    139:               me += lx[mr];
    140:             }
    141:           }
    142:           /* gone out of processor range on y axis */
    143:           while (jj > ne-1 || jj < ns) {
    144:             if (nr == n-1) {
    145:               ns = 0;
    146:               ne = ly[0];
    147:               nr = 0;
    148:             } else {
    149:               nr++;
    150:               ns = ne;
    151:               ne += ly[nr];
    152:             }
    153:           }
    154:           /* gone out of processor range on z axis */
    155:           while (kk > pe-1 || kk < ps) {
    156:             if (pr == p-1) {
    157:               ps = 0;
    158:               pe = lz[0];
    159:               pr = 0;
    160:             } else {
    161:               pr++;
    162:               ps = pe;
    163:               pe += lz[pr];
    164:             }
    165:           }
    166:           /* compute the vector base on owning processor */
    167:           xm = me - ms;
    168:           ym = ne - ns;
    169:           zm = pe - ps;
    170:           base = ms*ym*zm + ns*M*zm + ps*M*N;
    171:           /* compute the local coordinates on owning processor */
    172:           si = ii - ms;
    173:           sj = jj - ns;
    174:           sk = kk - ps;
    175:           for (l=0;l<dof;l++) {
    176:             indices[idx] = l + dof*(base + si + xm*sj + xm*ym*sk);
    177:             idx++;
    178:           }
    179:           i++;
    180:         } while (i<upper->i-ox);
    181:         j++;
    182:       } while (j<upper->j-oy);
    183:       k++;
    184:     } while (k<upper->k-oz);
    185:   }

    187:   if (!offproc) {
    188:     DMDAGetCorners(da, &ms, &ns, &ps, &mw, &nw, &pw);
    189:     me = ms + mw;
    190:     if (N>1) ne = ns + nw;
    191:     if (P>1) pe = ps + pw;
    192:     /* Account for DM offsets */
    193:     ms = ms - ox; me = me - ox;
    194:     ns = ns - oy; ne = ne - oy;
    195:     ps = ps - oz; pe = pe - oz;

    197:     /* compute the vector base on owning processor */
    198:     xm = me - ms;
    199:     ym = ne - ns;
    200:     zm = pe - ps;
    201:     base = ms*ym*zm + ns*M*zm + ps*M*N;
    202:     /*
    203:        if no indices are to be returned, create an empty is,
    204:        this prevents hanging in while loops
    205:     */
    206:     if (skip_i && skip_j && skip_k) goto createis;
    207:     /*
    208:        do..while loops to ensure the block gets entered once,
    209:        regardless of control condition being met, necessary for
    210:        cases when a subset of skip_i/j/k is true
    211:     */
    212:     if (skip_k) k = upper->k-oz; else k = lower->k-oz;
    213:     do {
    214:       if (skip_j) j = upper->j-oy; else j = lower->j-oy;
    215:       do {
    216:         if (skip_i) i = upper->i-ox; else i = lower->i-ox;
    217:         do {
    218:           if (k>=ps && k<=pe-1) {
    219:             if (j>=ns && j<=ne-1) {
    220:               if (i>=ms && i<=me-1) {
    221:                 /* compute the local coordinates on owning processor */
    222:                 si = i - ms;
    223:                 sj = j - ns;
    224:                 sk = k - ps;
    225:                 for (l=0; l<dof; l++) {
    226:                   indices[idx] = l + dof*(base + si + xm*sj + xm*ym*sk);
    227:                   idx++;
    228:                 }
    229:               }
    230:             }
    231:           }
    232:           i++;
    233:         } while (i<upper->i-ox);
    234:         j++;
    235:       } while (j<upper->j-oy);
    236:       k++;
    237:     } while (k<upper->k-oz);

    239:     PetscRealloc((size_t)(idx*sizeof(PetscInt)), (void*)&indices);
    240:   }

    242:   createis:
    243:   ISCreateGeneral(PetscObjectComm((PetscObject)da),idx,indices,PETSC_OWN_POINTER,is);
    244:   return 0;
    245: }

    247: PetscErrorCode DMDASubDomainDA_Private(DM dm, PetscInt *nlocal, DM **sdm)
    248: {
    249:   DM             *da;
    250:   PetscInt       dim,size,i,j,k,idx;
    251:   DMDALocalInfo  info;
    252:   PetscInt       xsize,ysize,zsize;
    253:   PetscInt       xo,yo,zo;
    254:   PetscInt       xs,ys,zs;
    255:   PetscInt       xm=1,ym=1,zm=1;
    256:   PetscInt       xol,yol,zol;
    257:   PetscInt       m=1,n=1,p=1;
    258:   PetscInt       M,N,P;
    259:   PetscInt       pm,mtmp;

    261:   DMDAGetLocalInfo(dm,&info);
    262:   DMDAGetOverlap(dm,&xol,&yol,&zol);
    263:   DMDAGetNumLocalSubDomains(dm,&size);
    264:   PetscMalloc1(size,&da);

    266:   if (nlocal) *nlocal = size;

    268:   dim = info.dim;

    270:   M = info.xm;
    271:   N = info.ym;
    272:   P = info.zm;

    274:   if (dim == 1) {
    275:     m = size;
    276:   } else if (dim == 2) {
    277:     m = (PetscInt)(0.5 + PetscSqrtReal(((PetscReal)M)*((PetscReal)size)/((PetscReal)N)));
    278:     while (m > 0) {
    279:       n = size/m;
    280:       if (m*n*p == size) break;
    281:       m--;
    282:     }
    283:   } else if (dim == 3) {
    284:     n = (PetscInt)(0.5 + PetscPowReal(((PetscReal)N*N)*((PetscReal)size)/((PetscReal)P*M),(PetscReal)(1./3.))); if (!n) n = 1;
    285:     while (n > 0) {
    286:       pm = size/n;
    287:       if (n*pm == size) break;
    288:       n--;
    289:     }
    290:     if (!n) n = 1;
    291:     m = (PetscInt)(0.5 + PetscSqrtReal(((PetscReal)M)*((PetscReal)size)/((PetscReal)P*n)));
    292:     if (!m) m = 1;
    293:     while (m > 0) {
    294:       p = size/(m*n);
    295:       if (m*n*p == size) break;
    296:       m--;
    297:     }
    298:     if (M > P && m < p) {mtmp = m; m = p; p = mtmp;}
    299:   }

    301:   zs = info.zs;
    302:   idx = 0;
    303:   for (k = 0; k < p; k++) {
    304:     ys = info.ys;
    305:     for (j = 0; j < n; j++) {
    306:       xs = info.xs;
    307:       for (i = 0; i < m; i++) {
    308:         if (dim == 1) {
    309:           xm = M/m + ((M % m) > i);
    310:         } else if (dim == 2) {
    311:           xm = M/m + ((M % m) > i);
    312:           ym = N/n + ((N % n) > j);
    313:         } else if (dim == 3) {
    314:           xm = M/m + ((M % m) > i);
    315:           ym = N/n + ((N % n) > j);
    316:           zm = P/p + ((P % p) > k);
    317:         }

    319:         xsize = xm;
    320:         ysize = ym;
    321:         zsize = zm;
    322:         xo = xs;
    323:         yo = ys;
    324:         zo = zs;

    326:         DMDACreate(PETSC_COMM_SELF,&(da[idx]));
    327:         DMSetOptionsPrefix(da[idx],"sub_");
    328:         DMSetDimension(da[idx], info.dim);
    329:         DMDASetDof(da[idx], info.dof);

    331:         DMDASetStencilType(da[idx],info.st);
    332:         DMDASetStencilWidth(da[idx],info.sw);

    334:         if (info.bx == DM_BOUNDARY_PERIODIC || (xs != 0)) {
    335:           xsize += xol;
    336:           xo    -= xol;
    337:         }
    338:         if (info.by == DM_BOUNDARY_PERIODIC || (ys != 0)) {
    339:           ysize += yol;
    340:           yo    -= yol;
    341:         }
    342:         if (info.bz == DM_BOUNDARY_PERIODIC || (zs != 0)) {
    343:           zsize += zol;
    344:           zo    -= zol;
    345:         }

    347:         if (info.bx == DM_BOUNDARY_PERIODIC || (xs+xm != info.mx)) xsize += xol;
    348:         if (info.by == DM_BOUNDARY_PERIODIC || (ys+ym != info.my)) ysize += yol;
    349:         if (info.bz == DM_BOUNDARY_PERIODIC || (zs+zm != info.mz)) zsize += zol;

    351:         if (info.bx != DM_BOUNDARY_PERIODIC) {
    352:           if (xo < 0) {
    353:             xsize += xo;
    354:             xo = 0;
    355:           }
    356:           if (xo+xsize > info.mx-1) {
    357:             xsize -= xo+xsize - info.mx;
    358:           }
    359:         }
    360:         if (info.by != DM_BOUNDARY_PERIODIC) {
    361:           if (yo < 0) {
    362:             ysize += yo;
    363:             yo = 0;
    364:           }
    365:           if (yo+ysize > info.my-1) {
    366:             ysize -= yo+ysize - info.my;
    367:           }
    368:         }
    369:         if (info.bz != DM_BOUNDARY_PERIODIC) {
    370:           if (zo < 0) {
    371:             zsize += zo;
    372:             zo = 0;
    373:           }
    374:           if (zo+zsize > info.mz-1) {
    375:             zsize -= zo+zsize - info.mz;
    376:           }
    377:         }

    379:         DMDASetSizes(da[idx], xsize, ysize, zsize);
    380:         DMDASetNumProcs(da[idx], 1, 1, 1);
    381:         DMDASetBoundaryType(da[idx], DM_BOUNDARY_GHOSTED, DM_BOUNDARY_GHOSTED, DM_BOUNDARY_GHOSTED);

    383:         /* set up as a block instead */
    384:         DMSetUp(da[idx]);

    386:         /* nonoverlapping region */
    387:         DMDASetNonOverlappingRegion(da[idx],xs,ys,zs,xm,ym,zm);

    389:         /* this alters the behavior of DMDAGetInfo, DMDAGetLocalInfo, DMDAGetCorners, and DMDAGetGhostedCorners and should be used with care */
    390:         DMDASetOffset(da[idx],xo,yo,zo,info.mx,info.my,info.mz);
    391:         xs += xm;
    392:         idx++;
    393:       }
    394:       ys += ym;
    395:     }
    396:     zs += zm;
    397:   }
    398:   *sdm = da;
    399:   return 0;
    400: }

    402: /*
    403:    Fills the local vector problem on the subdomain from the global problem.

    405:    Right now this assumes one subdomain per processor.

    407: */
    408: PetscErrorCode DMCreateDomainDecompositionScatters_DA(DM dm,PetscInt nsubdms,DM *subdms,VecScatter **iscat,VecScatter **oscat, VecScatter **lscat)
    409: {
    410:   DMDALocalInfo  info,subinfo;
    411:   DM             subdm;
    412:   MatStencil     upper,lower;
    413:   IS             idis,isis,odis,osis,gdis;
    414:   Vec            svec,dvec,slvec;
    415:   PetscInt       xm,ym,zm,xs,ys,zs;
    416:   PetscInt       i;
    417:   PetscBool      patchis_offproc = PETSC_TRUE;

    419:   /* allocate the arrays of scatters */
    420:   if (iscat) PetscMalloc1(nsubdms,iscat);
    421:   if (oscat) PetscMalloc1(nsubdms,oscat);
    422:   if (lscat) PetscMalloc1(nsubdms,lscat);

    424:   DMDAGetLocalInfo(dm,&info);
    425:   for (i = 0; i < nsubdms; i++) {
    426:     subdm = subdms[i];
    427:     DMDAGetLocalInfo(subdm,&subinfo);
    428:     DMDAGetNonOverlappingRegion(subdm,&xs,&ys,&zs,&xm,&ym,&zm);

    430:     /* create the global and subdomain index sets for the inner domain */
    431:     lower.i = xs;
    432:     lower.j = ys;
    433:     lower.k = zs;
    434:     upper.i = xs+xm;
    435:     upper.j = ys+ym;
    436:     upper.k = zs+zm;
    437:     DMDACreatePatchIS(dm,&lower,&upper,&idis,patchis_offproc);
    438:     DMDACreatePatchIS(subdm,&lower,&upper,&isis,patchis_offproc);

    440:     /* create the global and subdomain index sets for the outer subdomain */
    441:     lower.i = subinfo.xs;
    442:     lower.j = subinfo.ys;
    443:     lower.k = subinfo.zs;
    444:     upper.i = subinfo.xs+subinfo.xm;
    445:     upper.j = subinfo.ys+subinfo.ym;
    446:     upper.k = subinfo.zs+subinfo.zm;
    447:     DMDACreatePatchIS(dm,&lower,&upper,&odis,patchis_offproc);
    448:     DMDACreatePatchIS(subdm,&lower,&upper,&osis,patchis_offproc);

    450:     /* global and subdomain ISes for the local indices of the subdomain */
    451:     /* todo - make this not loop over at nonperiodic boundaries, which will be more involved */
    452:     lower.i = subinfo.gxs;
    453:     lower.j = subinfo.gys;
    454:     lower.k = subinfo.gzs;
    455:     upper.i = subinfo.gxs+subinfo.gxm;
    456:     upper.j = subinfo.gys+subinfo.gym;
    457:     upper.k = subinfo.gzs+subinfo.gzm;
    458:     DMDACreatePatchIS(dm,&lower,&upper,&gdis,patchis_offproc);

    460:     /* form the scatter */
    461:     DMGetGlobalVector(dm,&dvec);
    462:     DMGetGlobalVector(subdm,&svec);
    463:     DMGetLocalVector(subdm,&slvec);

    465:     if (iscat) VecScatterCreate(dvec,idis,svec,isis,&(*iscat)[i]);
    466:     if (oscat) VecScatterCreate(dvec,odis,svec,osis,&(*oscat)[i]);
    467:     if (lscat) VecScatterCreate(dvec,gdis,slvec,NULL,&(*lscat)[i]);

    469:     DMRestoreGlobalVector(dm,&dvec);
    470:     DMRestoreGlobalVector(subdm,&svec);
    471:     DMRestoreLocalVector(subdm,&slvec);

    473:     ISDestroy(&idis);
    474:     ISDestroy(&isis);

    476:     ISDestroy(&odis);
    477:     ISDestroy(&osis);

    479:     ISDestroy(&gdis);
    480:   }
    481:   return 0;
    482: }

    484: PetscErrorCode DMDASubDomainIS_Private(DM dm,PetscInt n,DM *subdm,IS **iis,IS **ois)
    485: {
    486:   PetscInt       i;
    487:   DMDALocalInfo  info,subinfo;
    488:   MatStencil     lower,upper;
    489:   PetscBool      patchis_offproc = PETSC_TRUE;

    491:   DMDAGetLocalInfo(dm,&info);
    492:   if (iis) PetscMalloc1(n,iis);
    493:   if (ois) PetscMalloc1(n,ois);

    495:   for (i = 0;i < n; i++) {
    496:     DMDAGetLocalInfo(subdm[i],&subinfo);
    497:     if (iis) {
    498:       /* create the inner IS */
    499:       lower.i = info.xs;
    500:       lower.j = info.ys;
    501:       lower.k = info.zs;
    502:       upper.i = info.xs+info.xm;
    503:       upper.j = info.ys+info.ym;
    504:       upper.k = info.zs+info.zm;
    505:       DMDACreatePatchIS(dm,&lower,&upper,&(*iis)[i],patchis_offproc);
    506:     }

    508:     if (ois) {
    509:       /* create the outer IS */
    510:       lower.i = subinfo.xs;
    511:       lower.j = subinfo.ys;
    512:       lower.k = subinfo.zs;
    513:       upper.i = subinfo.xs+subinfo.xm;
    514:       upper.j = subinfo.ys+subinfo.ym;
    515:       upper.k = subinfo.zs+subinfo.zm;
    516:       DMDACreatePatchIS(dm,&lower,&upper,&(*ois)[i],patchis_offproc);
    517:     }
    518:   }
    519:   return 0;
    520: }

    522: PetscErrorCode DMCreateDomainDecomposition_DA(DM dm,PetscInt *len,char ***names,IS **iis,IS **ois,DM **subdm)
    523: {
    524:   DM             *sdm;
    525:   PetscInt       n,i;

    527:   DMDASubDomainDA_Private(dm,&n,&sdm);
    528:   if (names) {
    529:     PetscMalloc1(n,names);
    530:     for (i=0;i<n;i++) (*names)[i] = NULL;
    531:   }
    532:   DMDASubDomainIS_Private(dm,n,sdm,iis,ois);
    533:   if (subdm) *subdm = sdm;
    534:   else {
    535:     for (i=0;i<n;i++) {
    536:       DMDestroy(&sdm[i]);
    537:     }
    538:   }
    539:   if (len) *len = n;
    540:   return 0;
    541: }