Actual source code: matnest.c
petsc-3.7.1 2016-05-15
Report Typos and Errors

      2: #include <../src/mat/impls/nest/matnestimpl.h> /*I   "petscmat.h"   I*/
      3: #include <petscsf.h>

      5: static PetscErrorCode MatSetUp_NestIS_Private(Mat,PetscInt,const IS[],PetscInt,const IS[]);
      6: static PetscErrorCode MatCreateVecs_Nest(Mat A,Vec *right,Vec *left);

      8: /* private functions */
     11: static PetscErrorCode MatNestGetSizes_Private(Mat A,PetscInt *m,PetscInt *n,PetscInt *M,PetscInt *N)
     12: {
     13:   Mat_Nest       *bA = (Mat_Nest*)A->data;
     14:   PetscInt       i,j;

     18:   *m = *n = *M = *N = 0;
     19:   for (i=0; i<bA->nr; i++) {  /* rows */
     20:     PetscInt sm,sM;
     21:     ISGetLocalSize(bA->isglobal.row[i],&sm);
     22:     ISGetSize(bA->isglobal.row[i],&sM);
     23:     *m  += sm;
     24:     *M  += sM;
     25:   }
     26:   for (j=0; j<bA->nc; j++) {  /* cols */
     27:     PetscInt sn,sN;
     28:     ISGetLocalSize(bA->isglobal.col[j],&sn);
     29:     ISGetSize(bA->isglobal.col[j],&sN);
     30:     *n  += sn;
     31:     *N  += sN;
     32:   }
     33:   return(0);
     34: }

     36: /* operations */
     39: static PetscErrorCode MatMult_Nest(Mat A,Vec x,Vec y)
     40: {
     41:   Mat_Nest       *bA = (Mat_Nest*)A->data;
     42:   Vec            *bx = bA->right,*by = bA->left;
     43:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

     47:   for (i=0; i<nr; i++) {VecGetSubVector(y,bA->isglobal.row[i],&by[i]);}
     48:   for (i=0; i<nc; i++) {VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);}
     49:   for (i=0; i<nr; i++) {
     50:     VecZeroEntries(by[i]);
     51:     for (j=0; j<nc; j++) {
     52:       if (!bA->m[i][j]) continue;
     53:       /* y[i] <- y[i] + A[i][j] * x[j] */
     54:       MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]);
     55:     }
     56:   }
     57:   for (i=0; i<nr; i++) {VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]);}
     58:   for (i=0; i<nc; i++) {VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);}
     59:   return(0);
     60: }

     64: static PetscErrorCode MatMultAdd_Nest(Mat A,Vec x,Vec y,Vec z)
     65: {
     66:   Mat_Nest       *bA = (Mat_Nest*)A->data;
     67:   Vec            *bx = bA->right,*bz = bA->left;
     68:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

     72:   for (i=0; i<nr; i++) {VecGetSubVector(z,bA->isglobal.row[i],&bz[i]);}
     73:   for (i=0; i<nc; i++) {VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);}
     74:   for (i=0; i<nr; i++) {
     75:     if (y != z) {
     76:       Vec by;
     77:       VecGetSubVector(y,bA->isglobal.row[i],&by);
     78:       VecCopy(by,bz[i]);
     79:       VecRestoreSubVector(y,bA->isglobal.row[i],&by);
     80:     }
     81:     for (j=0; j<nc; j++) {
     82:       if (!bA->m[i][j]) continue;
     83:       /* y[i] <- y[i] + A[i][j] * x[j] */
     84:       MatMultAdd(bA->m[i][j],bx[j],bz[i],bz[i]);
     85:     }
     86:   }
     87:   for (i=0; i<nr; i++) {VecRestoreSubVector(z,bA->isglobal.row[i],&bz[i]);}
     88:   for (i=0; i<nc; i++) {VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);}
     89:   return(0);
     90: }

     94: static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y)
     95: {
     96:   Mat_Nest       *bA = (Mat_Nest*)A->data;
     97:   Vec            *bx = bA->left,*by = bA->right;
     98:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

    102:   for (i=0; i<nr; i++) {VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);}
    103:   for (i=0; i<nc; i++) {VecGetSubVector(y,bA->isglobal.col[i],&by[i]);}
    104:   for (j=0; j<nc; j++) {
    105:     VecZeroEntries(by[j]);
    106:     for (i=0; i<nr; i++) {
    107:       if (!bA->m[i][j]) continue;
    108:       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
    109:       MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]);
    110:     }
    111:   }
    112:   for (i=0; i<nr; i++) {VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);}
    113:   for (i=0; i<nc; i++) {VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]);}
    114:   return(0);
    115: }

    119: static PetscErrorCode MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)
    120: {
    121:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    122:   Vec            *bx = bA->left,*bz = bA->right;
    123:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

    127:   for (i=0; i<nr; i++) {VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);}
    128:   for (i=0; i<nc; i++) {VecGetSubVector(z,bA->isglobal.col[i],&bz[i]);}
    129:   for (j=0; j<nc; j++) {
    130:     if (y != z) {
    131:       Vec by;
    132:       VecGetSubVector(y,bA->isglobal.col[j],&by);
    133:       VecCopy(by,bz[j]);
    134:       VecRestoreSubVector(y,bA->isglobal.col[j],&by);
    135:     }
    136:     for (i=0; i<nr; i++) {
    137:       if (!bA->m[i][j]) continue;
    138:       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
    139:       MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]);
    140:     }
    141:   }
    142:   for (i=0; i<nr; i++) {VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);}
    143:   for (i=0; i<nc; i++) {VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]);}
    144:   return(0);
    145: }

    149: static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
    150: {
    152:   IS             *lst = *list;
    153:   PetscInt       i;

    156:   if (!lst) return(0);
    157:   for (i=0; i<n; i++) if (lst[i]) {ISDestroy(&lst[i]);}
    158:   PetscFree(lst);
    159:   *list = NULL;
    160:   return(0);
    161: }

    165: static PetscErrorCode MatDestroy_Nest(Mat A)
    166: {
    167:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    168:   PetscInt       i,j;

    172:   /* release the matrices and the place holders */
    173:   MatNestDestroyISList(vs->nr,&vs->isglobal.row);
    174:   MatNestDestroyISList(vs->nc,&vs->isglobal.col);
    175:   MatNestDestroyISList(vs->nr,&vs->islocal.row);
    176:   MatNestDestroyISList(vs->nc,&vs->islocal.col);

    178:   PetscFree(vs->row_len);
    179:   PetscFree(vs->col_len);

    181:   PetscFree2(vs->left,vs->right);

    183:   /* release the matrices and the place holders */
    184:   if (vs->m) {
    185:     for (i=0; i<vs->nr; i++) {
    186:       for (j=0; j<vs->nc; j++) {
    187:         MatDestroy(&vs->m[i][j]);
    188:       }
    189:       PetscFree(vs->m[i]);
    190:     }
    191:     PetscFree(vs->m);
    192:   }
    193:   PetscFree(A->data);

    195:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",0);
    196:   PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",0);
    197:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",0);
    198:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",0);
    199:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",0);
    200:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",0);
    201:   PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",0);
    202:   PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",0);
    203:   return(0);
    204: }

    208: static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
    209: {
    210:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    211:   PetscInt       i,j;

    215:   for (i=0; i<vs->nr; i++) {
    216:     for (j=0; j<vs->nc; j++) {
    217:       if (vs->m[i][j]) {
    218:         MatAssemblyBegin(vs->m[i][j],type);
    219:         if (!vs->splitassembly) {
    220:           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
    221:            * sub-block). This could be fixed by adding a flag to Mat so that there was a way to check if a Mat was
    222:            * already performing an assembly, but the result would by more complicated and appears to offer less
    223:            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
    224:            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
    225:            */
    226:           MatAssemblyEnd(vs->m[i][j],type);
    227:         }
    228:       }
    229:     }
    230:   }
    231:   return(0);
    232: }

    236: static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
    237: {
    238:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    239:   PetscInt       i,j;

    243:   for (i=0; i<vs->nr; i++) {
    244:     for (j=0; j<vs->nc; j++) {
    245:       if (vs->m[i][j]) {
    246:         if (vs->splitassembly) {
    247:           MatAssemblyEnd(vs->m[i][j],type);
    248:         }
    249:       }
    250:     }
    251:   }
    252:   return(0);
    253: }

    257: static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
    258: {
    260:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    261:   PetscInt       j;
    262:   Mat            sub;

    265:   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
    266:   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
    267:   if (sub) {MatSetUp(sub);}       /* Ensure that the sizes are available */
    268:   *B = sub;
    269:   return(0);
    270: }

    274: static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
    275: {
    277:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    278:   PetscInt       i;
    279:   Mat            sub;

    282:   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
    283:   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
    284:   if (sub) {MatSetUp(sub);}       /* Ensure that the sizes are available */
    285:   *B = sub;
    286:   return(0);
    287: }

    291: static PetscErrorCode MatNestFindIS(Mat A,PetscInt n,const IS list[],IS is,PetscInt *found)
    292: {
    294:   PetscInt       i;
    295:   PetscBool      flg;

    301:   *found = -1;
    302:   for (i=0; i<n; i++) {
    303:     if (!list[i]) continue;
    304:     ISEqual(list[i],is,&flg);
    305:     if (flg) {
    306:       *found = i;
    307:       return(0);
    308:     }
    309:   }
    310:   SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Could not find index set");
    311:   return(0);
    312: }

    316: /* Get a block row as a new MatNest */
    317: static PetscErrorCode MatNestGetRow(Mat A,PetscInt row,Mat *B)
    318: {
    319:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    320:   char           keyname[256];

    324:   *B   = NULL;
    325:   PetscSNPrintf(keyname,sizeof(keyname),"NestRow_%D",row);
    326:   PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);
    327:   if (*B) return(0);

    329:   MatCreateNest(PetscObjectComm((PetscObject)A),1,NULL,vs->nc,vs->isglobal.col,vs->m[row],B);

    331:   (*B)->assembled = A->assembled;

    333:   PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);
    334:   PetscObjectDereference((PetscObject)*B); /* Leave the only remaining reference in the composition */
    335:   return(0);
    336: }

    340: static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
    341: {
    342:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    344:   PetscInt       row,col;
    345:   PetscBool      same,isFullCol,isFullColGlobal;

    348:   /* Check if full column space. This is a hack */
    349:   isFullCol = PETSC_FALSE;
    350:   PetscObjectTypeCompare((PetscObject)iscol,ISSTRIDE,&same);
    351:   if (same) {
    352:     PetscInt n,first,step,i,an,am,afirst,astep;
    353:     ISStrideGetInfo(iscol,&first,&step);
    354:     ISGetLocalSize(iscol,&n);
    355:     isFullCol = PETSC_TRUE;
    356:     for (i=0,an=A->cmap->rstart; i<vs->nc; i++) {
    357:       ISStrideGetInfo(is->col[i],&afirst,&astep);
    358:       ISGetLocalSize(is->col[i],&am);
    359:       if (afirst != an || astep != step) isFullCol = PETSC_FALSE;
    360:       an += am;
    361:     }
    362:     if (an != A->cmap->rstart+n) isFullCol = PETSC_FALSE;
    363:   }
    364:   MPIU_Allreduce(&isFullCol,&isFullColGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)iscol));

    366:   if (isFullColGlobal) {
    367:     PetscInt row;
    368:     MatNestFindIS(A,vs->nr,is->row,isrow,&row);
    369:     MatNestGetRow(A,row,B);
    370:   } else {
    371:     MatNestFindIS(A,vs->nr,is->row,isrow,&row);
    372:     MatNestFindIS(A,vs->nc,is->col,iscol,&col);
    373:     *B   = vs->m[row][col];
    374:   }
    375:   return(0);
    376: }

    380: static PetscErrorCode MatGetSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
    381: {
    383:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    384:   Mat            sub;

    387:   MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);
    388:   switch (reuse) {
    389:   case MAT_INITIAL_MATRIX:
    390:     if (sub) { PetscObjectReference((PetscObject)sub); }
    391:     *B = sub;
    392:     break;
    393:   case MAT_REUSE_MATRIX:
    394:     if (sub != *B) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
    395:     break;
    396:   case MAT_IGNORE_MATRIX:       /* Nothing to do */
    397:     break;
    398:   case MAT_INPLACE_MATRIX:       /* Nothing to do */
    399:     SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MAT_INPLACE_MATRIX is not supported yet");
    400:     break;
    401:   }
    402:   return(0);
    403: }

    407: PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
    408: {
    410:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    411:   Mat            sub;

    414:   MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);
    415:   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
    416:   if (sub) {PetscObjectReference((PetscObject)sub);}
    417:   *B = sub;
    418:   return(0);
    419: }

    423: static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
    424: {
    426:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    427:   Mat            sub;

    430:   MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);
    431:   if (*B != sub) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
    432:   if (sub) {
    433:     if (((PetscObject)sub)->refct <= 1) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
    434:     MatDestroy(B);
    435:   }
    436:   return(0);
    437: }

    441: static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
    442: {
    443:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    444:   PetscInt       i;

    448:   for (i=0; i<bA->nr; i++) {
    449:     Vec bv;
    450:     VecGetSubVector(v,bA->isglobal.row[i],&bv);
    451:     if (bA->m[i][i]) {
    452:       MatGetDiagonal(bA->m[i][i],bv);
    453:     } else {
    454:       VecSet(bv,0.0);
    455:     }
    456:     VecRestoreSubVector(v,bA->isglobal.row[i],&bv);
    457:   }
    458:   return(0);
    459: }

    463: static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
    464: {
    465:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    466:   Vec            bl,*br;
    467:   PetscInt       i,j;

    471:   PetscCalloc1(bA->nc,&br);
    472:   if (r) {
    473:     for (j=0; j<bA->nc; j++) {VecGetSubVector(r,bA->isglobal.col[j],&br[j]);}
    474:   }
    475:   bl = NULL;
    476:   for (i=0; i<bA->nr; i++) {
    477:     if (l) {
    478:       VecGetSubVector(l,bA->isglobal.row[i],&bl);
    479:     }
    480:     for (j=0; j<bA->nc; j++) {
    481:       if (bA->m[i][j]) {
    482:         MatDiagonalScale(bA->m[i][j],bl,br[j]);
    483:       }
    484:     }
    485:     if (l) {
    486:       VecRestoreSubVector(l,bA->isglobal.row[i],&bl);
    487:     }
    488:   }
    489:   if (r) {
    490:     for (j=0; j<bA->nc; j++) {VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]);}
    491:   }
    492:   PetscFree(br);
    493:   return(0);
    494: }

    498: static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
    499: {
    500:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    501:   PetscInt       i,j;

    505:   for (i=0; i<bA->nr; i++) {
    506:     for (j=0; j<bA->nc; j++) {
    507:       if (bA->m[i][j]) {
    508:         MatScale(bA->m[i][j],a);
    509:       }
    510:     }
    511:   }
    512:   return(0);
    513: }

    517: static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
    518: {
    519:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    520:   PetscInt       i;

    524:   for (i=0; i<bA->nr; i++) {
    525:     if (!bA->m[i][i]) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support for shifting an empty diagonal block, insert a matrix in block (%D,%D)",i,i);
    526:     MatShift(bA->m[i][i],a);
    527:   }
    528:   return(0);
    529: }

    533: static PetscErrorCode MatCreateVecs_Nest(Mat A,Vec *right,Vec *left)
    534: {
    535:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    536:   Vec            *L,*R;
    537:   MPI_Comm       comm;
    538:   PetscInt       i,j;

    542:   PetscObjectGetComm((PetscObject)A,&comm);
    543:   if (right) {
    544:     /* allocate R */
    545:     PetscMalloc1(bA->nc, &R);
    546:     /* Create the right vectors */
    547:     for (j=0; j<bA->nc; j++) {
    548:       for (i=0; i<bA->nr; i++) {
    549:         if (bA->m[i][j]) {
    550:           MatCreateVecs(bA->m[i][j],&R[j],NULL);
    551:           break;
    552:         }
    553:       }
    554:       if (i==bA->nr) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
    555:     }
    556:     VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);
    557:     /* hand back control to the nest vector */
    558:     for (j=0; j<bA->nc; j++) {
    559:       VecDestroy(&R[j]);
    560:     }
    561:     PetscFree(R);
    562:   }

    564:   if (left) {
    565:     /* allocate L */
    566:     PetscMalloc1(bA->nr, &L);
    567:     /* Create the left vectors */
    568:     for (i=0; i<bA->nr; i++) {
    569:       for (j=0; j<bA->nc; j++) {
    570:         if (bA->m[i][j]) {
    571:           MatCreateVecs(bA->m[i][j],NULL,&L[i]);
    572:           break;
    573:         }
    574:       }
    575:       if (j==bA->nc) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
    576:     }

    578:     VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);
    579:     for (i=0; i<bA->nr; i++) {
    580:       VecDestroy(&L[i]);
    581:     }

    583:     PetscFree(L);
    584:   }
    585:   return(0);
    586: }

    590: static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
    591: {
    592:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    593:   PetscBool      isascii;
    594:   PetscInt       i,j;

    598:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
    599:   if (isascii) {

    601:     PetscViewerASCIIPrintf(viewer,"Matrix object: \n");
    602:     PetscViewerASCIIPushTab(viewer);    /* push0 */
    603:     PetscViewerASCIIPrintf(viewer, "type=nest, rows=%d, cols=%d \n",bA->nr,bA->nc);

    605:     PetscViewerASCIIPrintf(viewer,"MatNest structure: \n");
    606:     for (i=0; i<bA->nr; i++) {
    607:       for (j=0; j<bA->nc; j++) {
    608:         MatType   type;
    609:         char      name[256] = "",prefix[256] = "";
    610:         PetscInt  NR,NC;
    611:         PetscBool isNest = PETSC_FALSE;

    613:         if (!bA->m[i][j]) {
    614:           PetscViewerASCIIPrintf(viewer, "(%D,%D) : NULL \n",i,j);
    615:           continue;
    616:         }
    617:         MatGetSize(bA->m[i][j],&NR,&NC);
    618:         MatGetType(bA->m[i][j], &type);
    619:         if (((PetscObject)bA->m[i][j])->name) {PetscSNPrintf(name,sizeof(name),"name=\"%s\", ",((PetscObject)bA->m[i][j])->name);}
    620:         if (((PetscObject)bA->m[i][j])->prefix) {PetscSNPrintf(prefix,sizeof(prefix),"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix);}
    621:         PetscObjectTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);

    623:         PetscViewerASCIIPrintf(viewer,"(%D,%D) : %s%stype=%s, rows=%D, cols=%D \n",i,j,name,prefix,type,NR,NC);

    625:         if (isNest) {
    626:           PetscViewerASCIIPushTab(viewer);  /* push1 */
    627:           MatView(bA->m[i][j],viewer);
    628:           PetscViewerASCIIPopTab(viewer);    /* pop1 */
    629:         }
    630:       }
    631:     }
    632:     PetscViewerASCIIPopTab(viewer);    /* pop0 */
    633:   }
    634:   return(0);
    635: }

    639: static PetscErrorCode MatZeroEntries_Nest(Mat A)
    640: {
    641:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    642:   PetscInt       i,j;

    646:   for (i=0; i<bA->nr; i++) {
    647:     for (j=0; j<bA->nc; j++) {
    648:       if (!bA->m[i][j]) continue;
    649:       MatZeroEntries(bA->m[i][j]);
    650:     }
    651:   }
    652:   return(0);
    653: }

    657: static PetscErrorCode MatCopy_Nest(Mat A,Mat B,MatStructure str)
    658: {
    659:   Mat_Nest       *bA = (Mat_Nest*)A->data,*bB = (Mat_Nest*)B->data;
    660:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

    664:   if (nr != bB->nr || nc != bB->nc) SETERRQ4(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Cannot copy a Mat_Nest of block size (%D,%D) to a Mat_Nest of block size (%D,%D)",bB->nr,bB->nc,nr,nc);
    665:   for (i=0; i<nr; i++) {
    666:     for (j=0; j<nc; j++) {
    667:       if (bA->m[i][j] && bB->m[i][j]) {
    668:         MatCopy(bA->m[i][j],bB->m[i][j],str);
    669:       } else if (bA->m[i][j] || bB->m[i][j]) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %D,%D",i,j);
    670:     }
    671:   }
    672:   return(0);
    673: }

    677: static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
    678: {
    679:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    680:   Mat            *b;
    681:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

    685:   PetscMalloc1(nr*nc,&b);
    686:   for (i=0; i<nr; i++) {
    687:     for (j=0; j<nc; j++) {
    688:       if (bA->m[i][j]) {
    689:         MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);
    690:       } else {
    691:         b[i*nc+j] = NULL;
    692:       }
    693:     }
    694:   }
    695:   MatCreateNest(PetscObjectComm((PetscObject)A),nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);
    696:   /* Give the new MatNest exclusive ownership */
    697:   for (i=0; i<nr*nc; i++) {
    698:     MatDestroy(&b[i]);
    699:   }
    700:   PetscFree(b);

    702:   MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);
    703:   MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);
    704:   return(0);
    705: }

    707: /* nest api */
    710: PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
    711: {
    712:   Mat_Nest *bA = (Mat_Nest*)A->data;

    715:   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
    716:   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
    717:   *mat = bA->m[idxm][jdxm];
    718:   return(0);
    719: }

    723: /*@
    724:  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.

    726:  Not collective

    728:  Input Parameters:
    729: +   A  - nest matrix
    730: .   idxm - index of the matrix within the nest matrix
    731: -   jdxm - index of the matrix within the nest matrix

    733:  Output Parameter:
    734: .   sub - matrix at index idxm,jdxm within the nest matrix

    736:  Level: developer

    738: .seealso: MatNestGetSize(), MatNestGetSubMats()
    739: @*/
    740: PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
    741: {

    745:   PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));
    746:   return(0);
    747: }

    751: PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)
    752: {
    753:   Mat_Nest       *bA = (Mat_Nest*)A->data;
    754:   PetscInt       m,n,M,N,mi,ni,Mi,Ni;

    758:   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
    759:   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
    760:   MatGetLocalSize(mat,&m,&n);
    761:   MatGetSize(mat,&M,&N);
    762:   ISGetLocalSize(bA->isglobal.row[idxm],&mi);
    763:   ISGetSize(bA->isglobal.row[idxm],&Mi);
    764:   ISGetLocalSize(bA->isglobal.col[jdxm],&ni);
    765:   ISGetSize(bA->isglobal.col[jdxm],&Ni);
    766:   if (M != Mi || N != Ni) SETERRQ4(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_INCOMP,"Submatrix dimension (%D,%D) incompatible with nest block (%D,%D)",M,N,Mi,Ni);
    767:   if (m != mi || n != ni) SETERRQ4(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_INCOMP,"Submatrix local dimension (%D,%D) incompatible with nest block (%D,%D)",m,n,mi,ni);

    769:   PetscObjectReference((PetscObject)mat);
    770:   MatDestroy(&bA->m[idxm][jdxm]);
    771:   bA->m[idxm][jdxm] = mat;
    772:   return(0);
    773: }

    777: /*@
    778:  MatNestSetSubMat - Set a single submatrix in the nest matrix.

    780:  Logically collective on the submatrix communicator

    782:  Input Parameters:
    783: +   A  - nest matrix
    784: .   idxm - index of the matrix within the nest matrix
    785: .   jdxm - index of the matrix within the nest matrix
    786: -   sub - matrix at index idxm,jdxm within the nest matrix

    788:  Notes:
    789:  The new submatrix must have the same size and communicator as that block of the nest.

    791:  This increments the reference count of the submatrix.

    793:  Level: developer

    795: .seealso: MatNestSetSubMats(), MatNestGetSubMat()
    796: @*/
    797: PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
    798: {

    802:   PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));
    803:   return(0);
    804: }

    808: PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
    809: {
    810:   Mat_Nest *bA = (Mat_Nest*)A->data;

    813:   if (M)   *M   = bA->nr;
    814:   if (N)   *N   = bA->nc;
    815:   if (mat) *mat = bA->m;
    816:   return(0);
    817: }

    821: /*@C
    822:  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.

    824:  Not collective

    826:  Input Parameters:
    827: .   A  - nest matrix

    829:  Output Parameter:
    830: +   M - number of rows in the nest matrix
    831: .   N - number of cols in the nest matrix
    832: -   mat - 2d array of matrices

    834:  Notes:

    836:  The user should not free the array mat.

    838:  Level: developer

    840: .seealso: MatNestGetSize(), MatNestGetSubMat()
    841: @*/
    842: PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
    843: {

    847:   PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));
    848:   return(0);
    849: }

    853: PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
    854: {
    855:   Mat_Nest *bA = (Mat_Nest*)A->data;

    858:   if (M) *M = bA->nr;
    859:   if (N) *N = bA->nc;
    860:   return(0);
    861: }

    865: /*@
    866:  MatNestGetSize - Returns the size of the nest matrix.

    868:  Not collective

    870:  Input Parameters:
    871: .   A  - nest matrix

    873:  Output Parameter:
    874: +   M - number of rows in the nested mat
    875: -   N - number of cols in the nested mat

    877:  Notes:

    879:  Level: developer

    881: .seealso: MatNestGetSubMat(), MatNestGetSubMats()
    882: @*/
    883: PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
    884: {

    888:   PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));
    889:   return(0);
    890: }

    894: static PetscErrorCode MatNestGetISs_Nest(Mat A,IS rows[],IS cols[])
    895: {
    896:   Mat_Nest *vs = (Mat_Nest*)A->data;
    897:   PetscInt i;

    900:   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->isglobal.row[i];
    901:   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->isglobal.col[i];
    902:   return(0);
    903: }

    907: /*@C
    908:  MatNestGetISs - Returns the index sets partitioning the row and column spaces

    910:  Not collective

    912:  Input Parameters:
    913: .   A  - nest matrix

    915:  Output Parameter:
    916: +   rows - array of row index sets
    917: -   cols - array of column index sets

    919:  Level: advanced

    921:  Notes:
    922:  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.

    924: .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetLocalISs()
    925: @*/
    926: PetscErrorCode  MatNestGetISs(Mat A,IS rows[],IS cols[])
    927: {

    932:   PetscUseMethod(A,"MatNestGetISs_C",(Mat,IS[],IS[]),(A,rows,cols));
    933:   return(0);
    934: }

    938: static PetscErrorCode MatNestGetLocalISs_Nest(Mat A,IS rows[],IS cols[])
    939: {
    940:   Mat_Nest *vs = (Mat_Nest*)A->data;
    941:   PetscInt i;

    944:   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->islocal.row[i];
    945:   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->islocal.col[i];
    946:   return(0);
    947: }

    951: /*@C
    952:  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces

    954:  Not collective

    956:  Input Parameters:
    957: .   A  - nest matrix

    959:  Output Parameter:
    960: +   rows - array of row index sets (or NULL to ignore)
    961: -   cols - array of column index sets (or NULL to ignore)

    963:  Level: advanced

    965:  Notes:
    966:  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.

    968: .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetISs()
    969: @*/
    970: PetscErrorCode  MatNestGetLocalISs(Mat A,IS rows[],IS cols[])
    971: {

    976:   PetscUseMethod(A,"MatNestGetLocalISs_C",(Mat,IS[],IS[]),(A,rows,cols));
    977:   return(0);
    978: }

    982: PetscErrorCode  MatNestSetVecType_Nest(Mat A,VecType vtype)
    983: {
    985:   PetscBool      flg;

    988:   PetscStrcmp(vtype,VECNEST,&flg);
    989:   /* In reality, this only distinguishes VECNEST and "other" */
    990:   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
    991:   else A->ops->getvecs = (PetscErrorCode (*)(Mat,Vec*,Vec*)) 0;
    992:   return(0);
    993: }

    997: /*@C
    998:  MatNestSetVecType - Sets the type of Vec returned by MatCreateVecs()

    1000:  Not collective

    1002:  Input Parameters:
    1003: +  A  - nest matrix
    1004: -  vtype - type to use for creating vectors

    1006:  Notes:

    1008:  Level: developer

    1010: .seealso: MatCreateVecs()
    1011: @*/
    1012: PetscErrorCode  MatNestSetVecType(Mat A,VecType vtype)
    1013: {

    1017:   PetscTryMethod(A,"MatNestSetVecType_C",(Mat,VecType),(A,vtype));
    1018:   return(0);
    1019: }

    1023: PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
    1024: {
    1025:   Mat_Nest       *s = (Mat_Nest*)A->data;
    1026:   PetscInt       i,j,m,n,M,N;

    1030:   s->nr = nr;
    1031:   s->nc = nc;

    1033:   /* Create space for submatrices */
    1034:   PetscMalloc1(nr,&s->m);
    1035:   for (i=0; i<nr; i++) {
    1036:     PetscMalloc1(nc,&s->m[i]);
    1037:   }
    1038:   for (i=0; i<nr; i++) {
    1039:     for (j=0; j<nc; j++) {
    1040:       s->m[i][j] = a[i*nc+j];
    1041:       if (a[i*nc+j]) {
    1042:         PetscObjectReference((PetscObject)a[i*nc+j]);
    1043:       }
    1044:     }
    1045:   }

    1047:   MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);

    1049:   PetscMalloc1(nr,&s->row_len);
    1050:   PetscMalloc1(nc,&s->col_len);
    1051:   for (i=0; i<nr; i++) s->row_len[i]=-1;
    1052:   for (j=0; j<nc; j++) s->col_len[j]=-1;

    1054:   MatNestGetSizes_Private(A,&m,&n,&M,&N);

    1056:   PetscLayoutSetSize(A->rmap,M);
    1057:   PetscLayoutSetLocalSize(A->rmap,m);
    1058:   PetscLayoutSetSize(A->cmap,N);
    1059:   PetscLayoutSetLocalSize(A->cmap,n);

    1061:   PetscLayoutSetUp(A->rmap);
    1062:   PetscLayoutSetUp(A->cmap);

    1064:   PetscCalloc2(nr,&s->left,nc,&s->right);
    1065:   return(0);
    1066: }

    1070: /*@
    1071:    MatNestSetSubMats - Sets the nested submatrices

    1073:    Collective on Mat

    1075:    Input Parameter:
    1076: +  N - nested matrix
    1077: .  nr - number of nested row blocks
    1078: .  is_row - index sets for each nested row block, or NULL to make contiguous
    1079: .  nc - number of nested column blocks
    1080: .  is_col - index sets for each nested column block, or NULL to make contiguous
    1081: -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL

    1083:    Level: advanced

    1085: .seealso: MatCreateNest(), MATNEST
    1086: @*/
    1087: PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
    1088: {
    1090:   PetscInt       i;

    1094:   if (nr < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
    1095:   if (nr && is_row) {
    1098:   }
    1099:   if (nc < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
    1100:   if (nc && is_col) {
    1103:   }
    1105:   PetscUseMethod(A,"MatNestSetSubMats_C",(Mat,PetscInt,const IS[],PetscInt,const IS[],const Mat[]),(A,nr,is_row,nc,is_col,a));
    1106:   return(0);
    1107: }

    1111: static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog)
    1112: {
    1114:   PetscBool      flg;
    1115:   PetscInt       i,j,m,mi,*ix;

    1118:   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
    1119:     if (islocal[i]) {
    1120:       ISGetSize(islocal[i],&mi);
    1121:       flg  = PETSC_TRUE;      /* We found a non-trivial entry */
    1122:     } else {
    1123:       ISGetSize(isglobal[i],&mi);
    1124:     }
    1125:     m += mi;
    1126:   }
    1127:   if (flg) {
    1128:     PetscMalloc1(m,&ix);
    1129:     for (i=0,n=0; i<n; i++) {
    1130:       ISLocalToGlobalMapping smap = NULL;
    1131:       VecScatter             scat;
    1132:       IS                     isreq;
    1133:       Vec                    lvec,gvec;
    1134:       union {char padding[sizeof(PetscScalar)]; PetscInt integer;} *x;
    1135:       Mat sub;

    1137:       if (sizeof(*x) != sizeof(PetscScalar)) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support when scalars smaller than integers");
    1138:       if (colflg) {
    1139:         MatNestFindNonzeroSubMatRow(A,i,&sub);
    1140:       } else {
    1141:         MatNestFindNonzeroSubMatCol(A,i,&sub);
    1142:       }
    1143:       if (sub) {MatGetLocalToGlobalMapping(sub,&smap,NULL);}
    1144:       if (islocal[i]) {
    1145:         ISGetSize(islocal[i],&mi);
    1146:       } else {
    1147:         ISGetSize(isglobal[i],&mi);
    1148:       }
    1149:       for (j=0; j<mi; j++) ix[m+j] = j;
    1150:       if (smap) {ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);}
    1151:       /*
    1152:         Now we need to extract the monolithic global indices that correspond to the given split global indices.
    1153:         In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces.
    1154:         The approach here is ugly because it uses VecScatter to move indices.
    1155:        */
    1156:       VecCreateSeq(PETSC_COMM_SELF,mi,&lvec);
    1157:       VecCreateMPI(((PetscObject)isglobal[i])->comm,mi,PETSC_DECIDE,&gvec);
    1158:       ISCreateGeneral(((PetscObject)isglobal[i])->comm,mi,ix+m,PETSC_COPY_VALUES,&isreq);
    1159:       VecScatterCreate(gvec,isreq,lvec,NULL,&scat);
    1160:       VecGetArray(gvec,(PetscScalar**)&x);
    1161:       for (j=0; j<mi; j++) x[j].integer = ix[m+j];
    1162:       VecRestoreArray(gvec,(PetscScalar**)&x);
    1163:       VecScatterBegin(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);
    1164:       VecScatterEnd(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);
    1165:       VecGetArray(lvec,(PetscScalar**)&x);
    1166:       for (j=0; j<mi; j++) ix[m+j] = x[j].integer;
    1167:       VecRestoreArray(lvec,(PetscScalar**)&x);
    1168:       VecDestroy(&lvec);
    1169:       VecDestroy(&gvec);
    1170:       ISDestroy(&isreq);
    1171:       VecScatterDestroy(&scat);
    1172:       m   += mi;
    1173:     }
    1174:     ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,m,ix,PETSC_OWN_POINTER,ltog);
    1175:   } else {
    1176:     *ltog  = NULL;
    1177:   }
    1178:   return(0);
    1179: }

    1182: /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
    1183: /*
    1184:   nprocessors = NP
    1185:   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
    1186:        proc 0: => (g_0,h_0,)
    1187:        proc 1: => (g_1,h_1,)
    1188:        ...
    1189:        proc nprocs-1: => (g_NP-1,h_NP-1,)

    1191:             proc 0:                      proc 1:                    proc nprocs-1:
    1192:     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))

    1194:             proc 0:
    1195:     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
    1196:             proc 1:
    1197:     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)

    1199:             proc NP-1:
    1200:     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
    1201: */
    1204: static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
    1205: {
    1206:   Mat_Nest       *vs = (Mat_Nest*)A->data;
    1207:   PetscInt       i,j,offset,n,nsum,bs;
    1209:   Mat            sub = NULL;

    1212:   PetscMalloc1(nr,&vs->isglobal.row);
    1213:   PetscMalloc1(nc,&vs->isglobal.col);
    1214:   if (is_row) { /* valid IS is passed in */
    1215:     /* refs on is[] are incremeneted */
    1216:     for (i=0; i<vs->nr; i++) {
    1217:       PetscObjectReference((PetscObject)is_row[i]);

    1219:       vs->isglobal.row[i] = is_row[i];
    1220:     }
    1221:   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
    1222:     nsum = 0;
    1223:     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
    1224:       MatNestFindNonzeroSubMatRow(A,i,&sub);
    1225:       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
    1226:       MatGetLocalSize(sub,&n,NULL);
    1227:       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
    1228:       nsum += n;
    1229:     }
    1230:     MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));
    1231:     offset -= nsum;
    1232:     for (i=0; i<vs->nr; i++) {
    1233:       MatNestFindNonzeroSubMatRow(A,i,&sub);
    1234:       MatGetLocalSize(sub,&n,NULL);
    1235:       MatGetBlockSize(sub,&bs);
    1236:       ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.row[i]);
    1237:       ISSetBlockSize(vs->isglobal.row[i],bs);
    1238:       offset += n;
    1239:     }
    1240:   }

    1242:   if (is_col) { /* valid IS is passed in */
    1243:     /* refs on is[] are incremeneted */
    1244:     for (j=0; j<vs->nc; j++) {
    1245:       PetscObjectReference((PetscObject)is_col[j]);

    1247:       vs->isglobal.col[j] = is_col[j];
    1248:     }
    1249:   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
    1250:     offset = A->cmap->rstart;
    1251:     nsum   = 0;
    1252:     for (j=0; j<vs->nc; j++) {
    1253:       MatNestFindNonzeroSubMatCol(A,j,&sub);
    1254:       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
    1255:       MatGetLocalSize(sub,NULL,&n);
    1256:       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
    1257:       nsum += n;
    1258:     }
    1259:     MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));
    1260:     offset -= nsum;
    1261:     for (j=0; j<vs->nc; j++) {
    1262:       MatNestFindNonzeroSubMatCol(A,j,&sub);
    1263:       MatGetLocalSize(sub,NULL,&n);
    1264:       MatGetBlockSize(sub,&bs);
    1265:       ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.col[j]);
    1266:       ISSetBlockSize(vs->isglobal.col[j],bs);
    1267:       offset += n;
    1268:     }
    1269:   }

    1271:   /* Set up the local ISs */
    1272:   PetscMalloc1(vs->nr,&vs->islocal.row);
    1273:   PetscMalloc1(vs->nc,&vs->islocal.col);
    1274:   for (i=0,offset=0; i<vs->nr; i++) {
    1275:     IS                     isloc;
    1276:     ISLocalToGlobalMapping rmap = NULL;
    1277:     PetscInt               nlocal,bs;
    1278:     MatNestFindNonzeroSubMatRow(A,i,&sub);
    1279:     if (sub) {MatGetLocalToGlobalMapping(sub,&rmap,NULL);}
    1280:     if (rmap) {
    1281:       MatGetBlockSize(sub,&bs);
    1282:       ISLocalToGlobalMappingGetSize(rmap,&nlocal);
    1283:       ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);
    1284:       ISSetBlockSize(isloc,bs);
    1285:     } else {
    1286:       nlocal = 0;
    1287:       isloc  = NULL;
    1288:     }
    1289:     vs->islocal.row[i] = isloc;
    1290:     offset            += nlocal;
    1291:   }
    1292:   for (i=0,offset=0; i<vs->nc; i++) {
    1293:     IS                     isloc;
    1294:     ISLocalToGlobalMapping cmap = NULL;
    1295:     PetscInt               nlocal,bs;
    1296:     MatNestFindNonzeroSubMatCol(A,i,&sub);
    1297:     if (sub) {MatGetLocalToGlobalMapping(sub,NULL,&cmap);}
    1298:     if (cmap) {
    1299:       MatGetBlockSize(sub,&bs);
    1300:       ISLocalToGlobalMappingGetSize(cmap,&nlocal);
    1301:       ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);
    1302:       ISSetBlockSize(isloc,bs);
    1303:     } else {
    1304:       nlocal = 0;
    1305:       isloc  = NULL;
    1306:     }
    1307:     vs->islocal.col[i] = isloc;
    1308:     offset            += nlocal;
    1309:   }

    1311:   /* Set up the aggregate ISLocalToGlobalMapping */
    1312:   {
    1313:     ISLocalToGlobalMapping rmap,cmap;
    1314:     MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap);
    1315:     MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap);
    1316:     if (rmap && cmap) {MatSetLocalToGlobalMapping(A,rmap,cmap);}
    1317:     ISLocalToGlobalMappingDestroy(&rmap);
    1318:     ISLocalToGlobalMappingDestroy(&cmap);
    1319:   }

    1321: #if defined(PETSC_USE_DEBUG)
    1322:   for (i=0; i<vs->nr; i++) {
    1323:     for (j=0; j<vs->nc; j++) {
    1324:       PetscInt m,n,M,N,mi,ni,Mi,Ni;
    1325:       Mat      B = vs->m[i][j];
    1326:       if (!B) continue;
    1327:       MatGetSize(B,&M,&N);
    1328:       MatGetLocalSize(B,&m,&n);
    1329:       ISGetSize(vs->isglobal.row[i],&Mi);
    1330:       ISGetSize(vs->isglobal.col[j],&Ni);
    1331:       ISGetLocalSize(vs->isglobal.row[i],&mi);
    1332:       ISGetLocalSize(vs->isglobal.col[j],&ni);
    1333:       if (M != Mi || N != Ni) SETERRQ6(PetscObjectComm((PetscObject)sub),PETSC_ERR_ARG_INCOMP,"Global sizes (%D,%D) of nested submatrix (%D,%D) do not agree with space defined by index sets (%D,%D)",M,N,i,j,Mi,Ni);
    1334:       if (m != mi || n != ni) SETERRQ6(PetscObjectComm((PetscObject)sub),PETSC_ERR_ARG_INCOMP,"Local sizes (%D,%D) of nested submatrix (%D,%D) do not agree with space defined by index sets (%D,%D)",m,n,i,j,mi,ni);
    1335:     }
    1336:   }
    1337: #endif

    1339:   /* Set A->assembled if all non-null blocks are currently assembled */
    1340:   for (i=0; i<vs->nr; i++) {
    1341:     for (j=0; j<vs->nc; j++) {
    1342:       if (vs->m[i][j] && !vs->m[i][j]->assembled) return(0);
    1343:     }
    1344:   }
    1345:   A->assembled = PETSC_TRUE;
    1346:   return(0);
    1347: }

    1351: /*@C
    1352:    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately

    1354:    Collective on Mat

    1356:    Input Parameter:
    1357: +  comm - Communicator for the new Mat
    1358: .  nr - number of nested row blocks
    1359: .  is_row - index sets for each nested row block, or NULL to make contiguous
    1360: .  nc - number of nested column blocks
    1361: .  is_col - index sets for each nested column block, or NULL to make contiguous
    1362: -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL

    1364:    Output Parameter:
    1365: .  B - new matrix

    1367:    Level: advanced

    1369: .seealso: MatCreate(), VecCreateNest(), DMCreateMatrix(), MATNEST
    1370: @*/
    1371: PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
    1372: {
    1373:   Mat            A;

    1377:   *B   = 0;
    1378:   MatCreate(comm,&A);
    1379:   MatSetType(A,MATNEST);
    1380:   MatSetUp(A);
    1381:   MatNestSetSubMats(A,nr,is_row,nc,is_col,a);
    1382:   *B   = A;
    1383:   return(0);
    1384: }

    1388: PETSC_INTERN PetscErrorCode MatConvert_Nest_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
    1389: {
    1391:   Mat_Nest       *nest = (Mat_Nest*)A->data;
    1392:   PetscInt       m,n,M,N,i,j,k,*dnnz,*onnz,rstart;
    1393:   PetscInt       cstart,cend;
    1394:   Mat            C;

    1397:   MatGetSize(A,&M,&N);
    1398:   MatGetLocalSize(A,&m,&n);
    1399:   MatGetOwnershipRangeColumn(A,&cstart,&cend);
    1400:   switch (reuse) {
    1401:   case MAT_INITIAL_MATRIX:
    1402:     MatCreate(PetscObjectComm((PetscObject)A),&C);
    1403:     MatSetType(C,newtype);
    1404:     MatSetSizes(C,m,n,M,N);
    1405:     *newmat = C;
    1406:     break;
    1407:   case MAT_REUSE_MATRIX:
    1408:     C = *newmat;
    1409:     break;
    1410:   default: SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MatReuse");
    1411:   }
    1412:   PetscMalloc1(2*m,&dnnz);
    1413:   onnz = dnnz + m;
    1414:   for (k=0; k<m; k++) {
    1415:     dnnz[k] = 0;
    1416:     onnz[k] = 0;
    1417:   }
    1418:   for (j=0; j<nest->nc; ++j) {
    1419:     IS             bNis;
    1420:     PetscInt       bN;
    1421:     const PetscInt *bNindices;
    1422:     /* Using global column indices and ISAllGather() is not scalable. */
    1423:     ISAllGather(nest->isglobal.col[j], &bNis);
    1424:     ISGetSize(bNis, &bN);
    1425:     ISGetIndices(bNis,&bNindices);
    1426:     for (i=0; i<nest->nr; ++i) {
    1427:       PetscSF        bmsf;
    1428:       PetscSFNode    *iremote;
    1429:       Mat            B;
    1430:       PetscInt       bm, *sub_dnnz,*sub_onnz, br;
    1431:       const PetscInt *bmindices;
    1432:       B = nest->m[i][j];
    1433:       if (!B) continue;
    1434:       ISGetLocalSize(nest->isglobal.row[i],&bm);
    1435:       ISGetIndices(nest->isglobal.row[i],&bmindices);
    1436:       PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf);
    1437:       PetscMalloc1(bm,&iremote);
    1438:       PetscMalloc1(bm,&sub_dnnz);
    1439:       PetscMalloc1(bm,&sub_onnz);
    1440:       for (k = 0; k < bm; ++k){
    1441:             sub_dnnz[k] = 0;
    1442:             sub_onnz[k] = 0;
    1443:       }
    1444:       /*
    1445:        Locate the owners for all of the locally-owned global row indices for this row block.
    1446:        These determine the roots of PetscSF used to communicate preallocation data to row owners.
    1447:        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
    1448:        */
    1449:       MatGetOwnershipRange(B,&rstart,NULL);
    1450:       for (br = 0; br < bm; ++br) {
    1451:         PetscInt       row = bmindices[br], rowowner = 0, brncols, col;
    1452:         const PetscInt *brcols;
    1453:         PetscInt       rowrel = 0; /* row's relative index on its owner rank */
    1454:         PetscLayoutFindOwnerIndex(A->rmap,row,&rowowner,&rowrel);
    1455:         /* how many roots  */
    1456:         iremote[br].rank = rowowner; iremote[br].index = rowrel;           /* edge from bmdnnz to dnnz */
    1457:         /* get nonzero pattern */
    1458:         MatGetRow(B,br+rstart,&brncols,&brcols,NULL);
    1459:         for (k=0; k<brncols; k++) {
    1460:           col  = bNindices[brcols[k]];
    1461:           if(col>=A->cmap->range[rowowner] && col<A->cmap->range[rowowner+1]){
    1462:                 sub_dnnz[br]++;
    1463:           }else{
    1464:                 sub_onnz[br]++;
    1465:           }
    1466:         }
    1467:         MatRestoreRow(B,br+rstart,&brncols,&brcols,NULL);
    1468:       }
    1469:       ISRestoreIndices(nest->isglobal.row[i],&bmindices);
    1470:       /* bsf will have to take care of disposing of bedges. */
    1471:       PetscSFSetGraph(bmsf,m,bm,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);
    1472:       PetscSFReduceBegin(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);
    1473:       PetscSFReduceEnd(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);
    1474:       PetscSFReduceBegin(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);
    1475:       PetscSFReduceEnd(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);
    1476:       PetscFree(sub_dnnz);
    1477:       PetscFree(sub_onnz);
    1478:       PetscSFDestroy(&bmsf);
    1479:     }
    1480:     ISRestoreIndices(bNis,&bNindices);
    1481:     ISDestroy(&bNis);
    1482:   }
    1483:   MatSeqAIJSetPreallocation(C,0,dnnz);
    1484:   MatMPIAIJSetPreallocation(C,0,dnnz,0,onnz);
    1485:   PetscFree(dnnz);

    1487:   /* Fill by row */
    1488:   for (j=0; j<nest->nc; ++j) {
    1489:     /* Using global column indices and ISAllGather() is not scalable. */
    1490:     IS             bNis;
    1491:     PetscInt       bN;
    1492:     const PetscInt *bNindices;
    1493:     ISAllGather(nest->isglobal.col[j], &bNis);
    1494:     ISGetSize(bNis,&bN);
    1495:     ISGetIndices(bNis,&bNindices);
    1496:     for (i=0; i<nest->nr; ++i) {
    1497:       Mat            B;
    1498:       PetscInt       bm, br;
    1499:       const PetscInt *bmindices;
    1500:       B = nest->m[i][j];
    1501:       if (!B) continue;
    1502:       ISGetLocalSize(nest->isglobal.row[i],&bm);
    1503:       ISGetIndices(nest->isglobal.row[i],&bmindices);
    1504:       MatGetOwnershipRange(B,&rstart,NULL);
    1505:       for (br = 0; br < bm; ++br) {
    1506:         PetscInt          row = bmindices[br], brncols,  *cols;
    1507:         const PetscInt    *brcols;
    1508:         const PetscScalar *brcoldata;
    1509:         MatGetRow(B,br+rstart,&brncols,&brcols,&brcoldata);
    1510:         PetscMalloc1(brncols,&cols);
    1511:         for (k=0; k<brncols; k++) cols[k] = bNindices[brcols[k]];
    1512:         /*
    1513:           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
    1514:           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
    1515:          */
    1516:         MatSetValues(C,1,&row,brncols,cols,brcoldata,ADD_VALUES);
    1517:         MatRestoreRow(B,br+rstart,&brncols,&brcols,&brcoldata);
    1518:         PetscFree(cols);
    1519:       }
    1520:       ISRestoreIndices(nest->isglobal.row[i],&bmindices);
    1521:     }
    1522:     ISRestoreIndices(bNis,&bNindices);
    1523:     ISDestroy(&bNis);
    1524:   }
    1525:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
    1526:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
    1527:   return(0);
    1528: }

    1530: /*MC
    1531:   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.

    1533:   Level: intermediate

    1535:   Notes:
    1536:   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
    1537:   It allows the use of symmetric and block formats for parts of multi-physics simulations.
    1538:   It is usually used with DMComposite and DMCreateMatrix()

    1540: .seealso: MatCreate(), MatType, MatCreateNest()
    1541: M*/
    1544: PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
    1545: {
    1546:   Mat_Nest       *s;

    1550:   PetscNewLog(A,&s);
    1551:   A->data = (void*)s;

    1553:   s->nr            = -1;
    1554:   s->nc            = -1;
    1555:   s->m             = NULL;
    1556:   s->splitassembly = PETSC_FALSE;

    1558:   PetscMemzero(A->ops,sizeof(*A->ops));

    1560:   A->ops->mult                  = MatMult_Nest;
    1561:   A->ops->multadd               = MatMultAdd_Nest;
    1562:   A->ops->multtranspose         = MatMultTranspose_Nest;
    1563:   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
    1564:   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
    1565:   A->ops->assemblyend           = MatAssemblyEnd_Nest;
    1566:   A->ops->zeroentries           = MatZeroEntries_Nest;
    1567:   A->ops->copy                  = MatCopy_Nest;
    1568:   A->ops->duplicate             = MatDuplicate_Nest;
    1569:   A->ops->getsubmatrix          = MatGetSubMatrix_Nest;
    1570:   A->ops->destroy               = MatDestroy_Nest;
    1571:   A->ops->view                  = MatView_Nest;
    1572:   A->ops->getvecs               = 0; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
    1573:   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
    1574:   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
    1575:   A->ops->getdiagonal           = MatGetDiagonal_Nest;
    1576:   A->ops->diagonalscale         = MatDiagonalScale_Nest;
    1577:   A->ops->scale                 = MatScale_Nest;
    1578:   A->ops->shift                 = MatShift_Nest;

    1580:   A->spptr        = 0;
    1581:   A->assembled    = PETSC_FALSE;

    1583:   /* expose Nest api's */
    1584:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",   MatNestGetSubMat_Nest);
    1585:   PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",   MatNestSetSubMat_Nest);
    1586:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",  MatNestGetSubMats_Nest);
    1587:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",     MatNestGetSize_Nest);
    1588:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",      MatNestGetISs_Nest);
    1589:   PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C", MatNestGetLocalISs_Nest);
    1590:   PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",  MatNestSetVecType_Nest);
    1591:   PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",  MatNestSetSubMats_Nest);
    1592:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",MatConvert_Nest_AIJ);

    1594:   PetscObjectChangeTypeName((PetscObject)A,MATNEST);
    1595:   return(0);
    1596: }