Actual source code: mpidense.c

      2: /*
      3:    Basic functions for basic parallel dense matrices.
      4: */

      6: #include <../src/mat/impls/dense/mpi/mpidense.h>
      7: #include <../src/mat/impls/aij/mpi/mpiaij.h>
      8: #include <petscblaslapack.h>

     10: /*@

     12:       MatDenseGetLocalMatrix - For a MATMPIDENSE or MATSEQDENSE matrix returns the sequential
     13:               matrix that represents the operator. For sequential matrices it returns itself.

     15:     Input Parameter:
     16: .      A - the Seq or MPI dense matrix

     18:     Output Parameter:
     19: .      B - the inner matrix

     21:     Level: intermediate

     23: @*/
     24: PetscErrorCode MatDenseGetLocalMatrix(Mat A,Mat *B)
     25: {
     26:   Mat_MPIDense   *mat = (Mat_MPIDense*)A->data;
     28:   PetscBool      flg;

     33:   PetscObjectBaseTypeCompare((PetscObject)A,MATMPIDENSE,&flg);
     34:   if (flg) *B = mat->A;
     35:   else {
     36:     PetscObjectBaseTypeCompare((PetscObject)A,MATSEQDENSE,&flg);
     37:     if (!flg) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)A)->type_name);
     38:     *B = A;
     39:   }
     40:   return(0);
     41: }

     43: PetscErrorCode MatCopy_MPIDense(Mat A, Mat B, MatStructure s)
     44: {
     45:   Mat_MPIDense   *Amat = (Mat_MPIDense*)A->data;
     46:   Mat_MPIDense   *Bmat = (Mat_MPIDense*)B->data;

     50:   MatCopy(Amat->A,Bmat->A,s);
     51:   return(0);
     52: }

     54: PetscErrorCode MatGetRow_MPIDense(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
     55: {
     56:   Mat_MPIDense   *mat = (Mat_MPIDense*)A->data;
     58:   PetscInt       lrow,rstart = A->rmap->rstart,rend = A->rmap->rend;

     61:   if (row < rstart || row >= rend) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"only local rows");
     62:   lrow = row - rstart;
     63:   MatGetRow(mat->A,lrow,nz,(const PetscInt**)idx,(const PetscScalar**)v);
     64:   return(0);
     65: }

     67: PetscErrorCode MatRestoreRow_MPIDense(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
     68: {
     69:   Mat_MPIDense   *mat = (Mat_MPIDense*)A->data;
     71:   PetscInt       lrow,rstart = A->rmap->rstart,rend = A->rmap->rend;

     74:   if (row < rstart || row >= rend) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"only local rows");
     75:   lrow = row - rstart;
     76:   MatRestoreRow(mat->A,lrow,nz,(const PetscInt**)idx,(const PetscScalar**)v);
     77:   return(0);
     78: }

     80: PetscErrorCode  MatGetDiagonalBlock_MPIDense(Mat A,Mat *a)
     81: {
     82:   Mat_MPIDense   *mdn = (Mat_MPIDense*)A->data;
     84:   PetscInt       m = A->rmap->n,rstart = A->rmap->rstart;
     85:   PetscScalar    *array;
     86:   MPI_Comm       comm;
     87:   PetscBool      flg;
     88:   Mat            B;

     91:   MatHasCongruentLayouts(A,&flg);
     92:   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only square matrices supported.");
     93:   PetscObjectQuery((PetscObject)A,"DiagonalBlock",(PetscObject*)&B);
     94:   if (!B) { /* This should use MatDenseGetSubMatrix (not create), but we would need a call like MatRestoreDiagonalBlock */

     96:     PetscObjectTypeCompare((PetscObject)mdn->A,MATSEQDENSECUDA,&flg);
     97:     if (flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not coded for %s. Send an email to petsc-dev@mcs.anl.gov to request this feature",MATSEQDENSECUDA);
     98:     PetscObjectGetComm((PetscObject)(mdn->A),&comm);
     99:     MatCreate(comm,&B);
    100:     MatSetSizes(B,m,m,m,m);
    101:     MatSetType(B,((PetscObject)mdn->A)->type_name);
    102:     MatDenseGetArrayRead(mdn->A,(const PetscScalar**)&array);
    103:     MatSeqDenseSetPreallocation(B,array+m*rstart);
    104:     MatDenseRestoreArrayRead(mdn->A,(const PetscScalar**)&array);
    105:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
    106:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
    107:     PetscObjectCompose((PetscObject)A,"DiagonalBlock",(PetscObject)B);
    108:     *a   = B;
    109:     MatDestroy(&B);
    110:   } else *a = B;
    111:   return(0);
    112: }

    114: PetscErrorCode MatSetValues_MPIDense(Mat mat,PetscInt m,const PetscInt idxm[],PetscInt n,const PetscInt idxn[],const PetscScalar v[],InsertMode addv)
    115: {
    116:   Mat_MPIDense   *A = (Mat_MPIDense*)mat->data;
    118:   PetscInt       i,j,rstart = mat->rmap->rstart,rend = mat->rmap->rend,row;
    119:   PetscBool      roworiented = A->roworiented;

    122:   for (i=0; i<m; i++) {
    123:     if (idxm[i] < 0) continue;
    124:     if (idxm[i] >= mat->rmap->N) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Row too large");
    125:     if (idxm[i] >= rstart && idxm[i] < rend) {
    126:       row = idxm[i] - rstart;
    127:       if (roworiented) {
    128:         MatSetValues(A->A,1,&row,n,idxn,v+i*n,addv);
    129:       } else {
    130:         for (j=0; j<n; j++) {
    131:           if (idxn[j] < 0) continue;
    132:           if (idxn[j] >= mat->cmap->N) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Column too large");
    133:           MatSetValues(A->A,1,&row,1,&idxn[j],v+i+j*m,addv);
    134:         }
    135:       }
    136:     } else if (!A->donotstash) {
    137:       mat->assembled = PETSC_FALSE;
    138:       if (roworiented) {
    139:         MatStashValuesRow_Private(&mat->stash,idxm[i],n,idxn,v+i*n,PETSC_FALSE);
    140:       } else {
    141:         MatStashValuesCol_Private(&mat->stash,idxm[i],n,idxn,v+i,m,PETSC_FALSE);
    142:       }
    143:     }
    144:   }
    145:   return(0);
    146: }

    148: PetscErrorCode MatGetValues_MPIDense(Mat mat,PetscInt m,const PetscInt idxm[],PetscInt n,const PetscInt idxn[],PetscScalar v[])
    149: {
    150:   Mat_MPIDense   *mdn = (Mat_MPIDense*)mat->data;
    152:   PetscInt       i,j,rstart = mat->rmap->rstart,rend = mat->rmap->rend,row;

    155:   for (i=0; i<m; i++) {
    156:     if (idxm[i] < 0) continue; /* SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative row"); */
    157:     if (idxm[i] >= mat->rmap->N) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Row too large");
    158:     if (idxm[i] >= rstart && idxm[i] < rend) {
    159:       row = idxm[i] - rstart;
    160:       for (j=0; j<n; j++) {
    161:         if (idxn[j] < 0) continue; /* SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative column"); */
    162:         if (idxn[j] >= mat->cmap->N) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Column too large");
    163:         MatGetValues(mdn->A,1,&row,1,&idxn[j],v+i*n+j);
    164:       }
    165:     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only local values currently supported");
    166:   }
    167:   return(0);
    168: }

    170: static PetscErrorCode MatDenseGetLDA_MPIDense(Mat A,PetscInt *lda)
    171: {
    172:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    176:   MatDenseGetLDA(a->A,lda);
    177:   return(0);
    178: }

    180: static PetscErrorCode MatDenseSetLDA_MPIDense(Mat A,PetscInt lda)
    181: {
    182:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;
    183:   PetscBool      iscuda;

    187:   if (!a->A) {
    188:     if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    189:     PetscLayoutSetUp(A->rmap);
    190:     PetscLayoutSetUp(A->cmap);
    191:     MatCreate(PETSC_COMM_SELF,&a->A);
    192:     PetscLogObjectParent((PetscObject)A,(PetscObject)a->A);
    193:     MatSetSizes(a->A,A->rmap->n,A->cmap->N,A->rmap->n,A->cmap->N);
    194:     PetscObjectTypeCompare((PetscObject)A,MATMPIDENSECUDA,&iscuda);
    195:     MatSetType(a->A,iscuda ? MATSEQDENSECUDA : MATSEQDENSE);
    196:   }
    197:   MatDenseSetLDA(a->A,lda);
    198:   return(0);
    199: }

    201: static PetscErrorCode MatDenseGetArray_MPIDense(Mat A,PetscScalar **array)
    202: {
    203:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    207:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    208:   MatDenseGetArray(a->A,array);
    209:   return(0);
    210: }

    212: static PetscErrorCode MatDenseGetArrayRead_MPIDense(Mat A,const PetscScalar **array)
    213: {
    214:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    218:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    219:   MatDenseGetArrayRead(a->A,array);
    220:   return(0);
    221: }

    223: static PetscErrorCode MatDenseGetArrayWrite_MPIDense(Mat A,PetscScalar **array)
    224: {
    225:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    229:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    230:   MatDenseGetArrayWrite(a->A,array);
    231:   return(0);
    232: }

    234: static PetscErrorCode MatDensePlaceArray_MPIDense(Mat A,const PetscScalar *array)
    235: {
    236:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    240:   if (a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    241:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    242:   MatDensePlaceArray(a->A,array);
    243:   return(0);
    244: }

    246: static PetscErrorCode MatDenseResetArray_MPIDense(Mat A)
    247: {
    248:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    252:   if (a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    253:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    254:   MatDenseResetArray(a->A);
    255:   return(0);
    256: }

    258: static PetscErrorCode MatDenseReplaceArray_MPIDense(Mat A,const PetscScalar *array)
    259: {
    260:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    264:   if (a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    265:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    266:   MatDenseReplaceArray(a->A,array);
    267:   return(0);
    268: }

    270: static PetscErrorCode MatCreateSubMatrix_MPIDense(Mat A,IS isrow,IS iscol,MatReuse scall,Mat *B)
    271: {
    272:   Mat_MPIDense      *mat  = (Mat_MPIDense*)A->data,*newmatd;
    273:   PetscErrorCode    ierr;
    274:   PetscInt          lda,i,j,rstart,rend,nrows,ncols,Ncols,nlrows,nlcols;
    275:   const PetscInt    *irow,*icol;
    276:   const PetscScalar *v;
    277:   PetscScalar       *bv;
    278:   Mat               newmat;
    279:   IS                iscol_local;
    280:   MPI_Comm          comm_is,comm_mat;

    283:   PetscObjectGetComm((PetscObject)A,&comm_mat);
    284:   PetscObjectGetComm((PetscObject)iscol,&comm_is);
    285:   if (comm_mat != comm_is) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"IS communicator must match matrix communicator");

    287:   ISAllGather(iscol,&iscol_local);
    288:   ISGetIndices(isrow,&irow);
    289:   ISGetIndices(iscol_local,&icol);
    290:   ISGetLocalSize(isrow,&nrows);
    291:   ISGetLocalSize(iscol,&ncols);
    292:   ISGetSize(iscol,&Ncols); /* global number of columns, size of iscol_local */

    294:   /* No parallel redistribution currently supported! Should really check each index set
    295:      to comfirm that it is OK.  ... Currently supports only submatrix same partitioning as
    296:      original matrix! */

    298:   MatGetLocalSize(A,&nlrows,&nlcols);
    299:   MatGetOwnershipRange(A,&rstart,&rend);

    301:   /* Check submatrix call */
    302:   if (scall == MAT_REUSE_MATRIX) {
    303:     /* SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Reused submatrix wrong size"); */
    304:     /* Really need to test rows and column sizes! */
    305:     newmat = *B;
    306:   } else {
    307:     /* Create and fill new matrix */
    308:     MatCreate(PetscObjectComm((PetscObject)A),&newmat);
    309:     MatSetSizes(newmat,nrows,ncols,PETSC_DECIDE,Ncols);
    310:     MatSetType(newmat,((PetscObject)A)->type_name);
    311:     MatMPIDenseSetPreallocation(newmat,NULL);
    312:   }

    314:   /* Now extract the data pointers and do the copy, column at a time */
    315:   newmatd = (Mat_MPIDense*)newmat->data;
    316:   MatDenseGetArray(newmatd->A,&bv);
    317:   MatDenseGetArrayRead(mat->A,&v);
    318:   MatDenseGetLDA(mat->A,&lda);
    319:   for (i=0; i<Ncols; i++) {
    320:     const PetscScalar *av = v + lda*icol[i];
    321:     for (j=0; j<nrows; j++) {
    322:       *bv++ = av[irow[j] - rstart];
    323:     }
    324:   }
    325:   MatDenseRestoreArrayRead(mat->A,&v);
    326:   MatDenseRestoreArray(newmatd->A,&bv);

    328:   /* Assemble the matrices so that the correct flags are set */
    329:   MatAssemblyBegin(newmat,MAT_FINAL_ASSEMBLY);
    330:   MatAssemblyEnd(newmat,MAT_FINAL_ASSEMBLY);

    332:   /* Free work space */
    333:   ISRestoreIndices(isrow,&irow);
    334:   ISRestoreIndices(iscol_local,&icol);
    335:   ISDestroy(&iscol_local);
    336:   *B   = newmat;
    337:   return(0);
    338: }

    340: PetscErrorCode MatDenseRestoreArray_MPIDense(Mat A,PetscScalar **array)
    341: {
    342:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    346:   MatDenseRestoreArray(a->A,array);
    347:   return(0);
    348: }

    350: PetscErrorCode MatDenseRestoreArrayRead_MPIDense(Mat A,const PetscScalar **array)
    351: {
    352:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    356:   MatDenseRestoreArrayRead(a->A,array);
    357:   return(0);
    358: }

    360: PetscErrorCode MatDenseRestoreArrayWrite_MPIDense(Mat A,PetscScalar **array)
    361: {
    362:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    366:   MatDenseRestoreArrayWrite(a->A,array);
    367:   return(0);
    368: }

    370: PetscErrorCode MatAssemblyBegin_MPIDense(Mat mat,MatAssemblyType mode)
    371: {
    372:   Mat_MPIDense   *mdn = (Mat_MPIDense*)mat->data;
    374:   PetscInt       nstash,reallocs;

    377:   if (mdn->donotstash || mat->nooffprocentries) return(0);

    379:   MatStashScatterBegin_Private(mat,&mat->stash,mat->rmap->range);
    380:   MatStashGetInfo_Private(&mat->stash,&nstash,&reallocs);
    381:   PetscInfo2(mdn->A,"Stash has %D entries, uses %D mallocs.\n",nstash,reallocs);
    382:   return(0);
    383: }

    385: PetscErrorCode MatAssemblyEnd_MPIDense(Mat mat,MatAssemblyType mode)
    386: {
    387:   Mat_MPIDense   *mdn=(Mat_MPIDense*)mat->data;
    389:   PetscInt       i,*row,*col,flg,j,rstart,ncols;
    390:   PetscMPIInt    n;
    391:   PetscScalar    *val;

    394:   if (!mdn->donotstash && !mat->nooffprocentries) {
    395:     /*  wait on receives */
    396:     while (1) {
    397:       MatStashScatterGetMesg_Private(&mat->stash,&n,&row,&col,&val,&flg);
    398:       if (!flg) break;

    400:       for (i=0; i<n;) {
    401:         /* Now identify the consecutive vals belonging to the same row */
    402:         for (j=i,rstart=row[j]; j<n; j++) {
    403:           if (row[j] != rstart) break;
    404:         }
    405:         if (j < n) ncols = j-i;
    406:         else       ncols = n-i;
    407:         /* Now assemble all these values with a single function call */
    408:         MatSetValues_MPIDense(mat,1,row+i,ncols,col+i,val+i,mat->insertmode);
    409:         i    = j;
    410:       }
    411:     }
    412:     MatStashScatterEnd_Private(&mat->stash);
    413:   }

    415:   MatAssemblyBegin(mdn->A,mode);
    416:   MatAssemblyEnd(mdn->A,mode);

    418:   if (!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) {
    419:     MatSetUpMultiply_MPIDense(mat);
    420:   }
    421:   return(0);
    422: }

    424: PetscErrorCode MatZeroEntries_MPIDense(Mat A)
    425: {
    427:   Mat_MPIDense   *l = (Mat_MPIDense*)A->data;

    430:   MatZeroEntries(l->A);
    431:   return(0);
    432: }

    434: PetscErrorCode MatZeroRows_MPIDense(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
    435: {
    436:   Mat_MPIDense      *l = (Mat_MPIDense*)A->data;
    437:   PetscErrorCode    ierr;
    438:   PetscInt          i,len,*lrows;

    441:   /* get locally owned rows */
    442:   PetscLayoutMapLocal(A->rmap,n,rows,&len,&lrows,NULL);
    443:   /* fix right hand side if needed */
    444:   if (x && b) {
    445:     const PetscScalar *xx;
    446:     PetscScalar       *bb;

    448:     VecGetArrayRead(x, &xx);
    449:     VecGetArrayWrite(b, &bb);
    450:     for (i=0;i<len;++i) bb[lrows[i]] = diag*xx[lrows[i]];
    451:     VecRestoreArrayRead(x, &xx);
    452:     VecRestoreArrayWrite(b, &bb);
    453:   }
    454:   MatZeroRows(l->A,len,lrows,0.0,NULL,NULL);
    455:   if (diag != 0.0) {
    456:     Vec d;

    458:     MatCreateVecs(A,NULL,&d);
    459:     VecSet(d,diag);
    460:     MatDiagonalSet(A,d,INSERT_VALUES);
    461:     VecDestroy(&d);
    462:   }
    463:   PetscFree(lrows);
    464:   return(0);
    465: }

    467: PETSC_INTERN PetscErrorCode MatMult_SeqDense(Mat,Vec,Vec);
    468: PETSC_INTERN PetscErrorCode MatMultAdd_SeqDense(Mat,Vec,Vec,Vec);
    469: PETSC_INTERN PetscErrorCode MatMultTranspose_SeqDense(Mat,Vec,Vec);
    470: PETSC_INTERN PetscErrorCode MatMultTransposeAdd_SeqDense(Mat,Vec,Vec,Vec);

    472: PetscErrorCode MatMult_MPIDense(Mat mat,Vec xx,Vec yy)
    473: {
    474:   Mat_MPIDense      *mdn = (Mat_MPIDense*)mat->data;
    475:   PetscErrorCode    ierr;
    476:   const PetscScalar *ax;
    477:   PetscScalar       *ay;
    478:   PetscMemType      axmtype,aymtype;

    481:   VecGetArrayReadAndMemType(xx,&ax,&axmtype);
    482:   VecGetArrayAndMemType(mdn->lvec,&ay,&aymtype);
    483:   PetscSFBcastWithMemTypeBegin(mdn->Mvctx,MPIU_SCALAR,axmtype,ax,aymtype,ay,MPI_REPLACE);
    484:   PetscSFBcastEnd(mdn->Mvctx,MPIU_SCALAR,ax,ay,MPI_REPLACE);
    485:   VecRestoreArrayAndMemType(mdn->lvec,&ay);
    486:   VecRestoreArrayReadAndMemType(xx,&ax);
    487:   (*mdn->A->ops->mult)(mdn->A,mdn->lvec,yy);
    488:   return(0);
    489: }

    491: PetscErrorCode MatMultAdd_MPIDense(Mat mat,Vec xx,Vec yy,Vec zz)
    492: {
    493:   Mat_MPIDense      *mdn = (Mat_MPIDense*)mat->data;
    494:   PetscErrorCode    ierr;
    495:   const PetscScalar *ax;
    496:   PetscScalar       *ay;
    497:   PetscMemType      axmtype,aymtype;

    500:   VecGetArrayReadAndMemType(xx,&ax,&axmtype);
    501:   VecGetArrayAndMemType(mdn->lvec,&ay,&aymtype);
    502:   PetscSFBcastWithMemTypeBegin(mdn->Mvctx,MPIU_SCALAR,axmtype,ax,aymtype,ay,MPI_REPLACE);
    503:   PetscSFBcastEnd(mdn->Mvctx,MPIU_SCALAR,ax,ay,MPI_REPLACE);
    504:   VecRestoreArrayAndMemType(mdn->lvec,&ay);
    505:   VecRestoreArrayReadAndMemType(xx,&ax);
    506:   (*mdn->A->ops->multadd)(mdn->A,mdn->lvec,yy,zz);
    507:   return(0);
    508: }

    510: PetscErrorCode MatMultTranspose_MPIDense(Mat A,Vec xx,Vec yy)
    511: {
    512:   Mat_MPIDense      *a = (Mat_MPIDense*)A->data;
    513:   PetscErrorCode    ierr;
    514:   const PetscScalar *ax;
    515:   PetscScalar       *ay;
    516:   PetscMemType      axmtype,aymtype;

    519:   VecSet(yy,0.0);
    520:   (*a->A->ops->multtranspose)(a->A,xx,a->lvec);
    521:   VecGetArrayReadAndMemType(a->lvec,&ax,&axmtype);
    522:   VecGetArrayAndMemType(yy,&ay,&aymtype);
    523:   PetscSFReduceWithMemTypeBegin(a->Mvctx,MPIU_SCALAR,axmtype,ax,aymtype,ay,MPIU_SUM);
    524:   PetscSFReduceEnd(a->Mvctx,MPIU_SCALAR,ax,ay,MPIU_SUM);
    525:   VecRestoreArrayReadAndMemType(a->lvec,&ax);
    526:   VecRestoreArrayAndMemType(yy,&ay);
    527:   return(0);
    528: }

    530: PetscErrorCode MatMultTransposeAdd_MPIDense(Mat A,Vec xx,Vec yy,Vec zz)
    531: {
    532:   Mat_MPIDense      *a = (Mat_MPIDense*)A->data;
    533:   PetscErrorCode    ierr;
    534:   const PetscScalar *ax;
    535:   PetscScalar       *ay;
    536:   PetscMemType      axmtype,aymtype;

    539:   VecCopy(yy,zz);
    540:   (*a->A->ops->multtranspose)(a->A,xx,a->lvec);
    541:   VecGetArrayReadAndMemType(a->lvec,&ax,&axmtype);
    542:   VecGetArrayAndMemType(zz,&ay,&aymtype);
    543:   PetscSFReduceWithMemTypeBegin(a->Mvctx,MPIU_SCALAR,axmtype,ax,aymtype,ay,MPIU_SUM);
    544:   PetscSFReduceEnd(a->Mvctx,MPIU_SCALAR,ax,ay,MPIU_SUM);
    545:   VecRestoreArrayReadAndMemType(a->lvec,&ax);
    546:   VecRestoreArrayAndMemType(zz,&ay);
    547:   return(0);
    548: }

    550: PetscErrorCode MatGetDiagonal_MPIDense(Mat A,Vec v)
    551: {
    552:   Mat_MPIDense      *a    = (Mat_MPIDense*)A->data;
    553:   PetscErrorCode    ierr;
    554:   PetscInt          lda,len,i,n,m = A->rmap->n,radd;
    555:   PetscScalar       *x,zero = 0.0;
    556:   const PetscScalar *av;

    559:   VecSet(v,zero);
    560:   VecGetArray(v,&x);
    561:   VecGetSize(v,&n);
    562:   if (n != A->rmap->N) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Nonconforming mat and vec");
    563:   len  = PetscMin(a->A->rmap->n,a->A->cmap->n);
    564:   radd = A->rmap->rstart*m;
    565:   MatDenseGetArrayRead(a->A,&av);
    566:   MatDenseGetLDA(a->A,&lda);
    567:   for (i=0; i<len; i++) {
    568:     x[i] = av[radd + i*lda + i];
    569:   }
    570:   MatDenseRestoreArrayRead(a->A,&av);
    571:   VecRestoreArray(v,&x);
    572:   return(0);
    573: }

    575: PetscErrorCode MatDestroy_MPIDense(Mat mat)
    576: {
    577:   Mat_MPIDense   *mdn = (Mat_MPIDense*)mat->data;

    581: #if defined(PETSC_USE_LOG)
    582:   PetscLogObjectState((PetscObject)mat,"Rows=%D, Cols=%D",mat->rmap->N,mat->cmap->N);
    583: #endif
    584:   MatStashDestroy_Private(&mat->stash);
    585:   if (mdn->vecinuse) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    586:   if (mdn->matinuse) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    587:   MatDestroy(&mdn->A);
    588:   VecDestroy(&mdn->lvec);
    589:   PetscSFDestroy(&mdn->Mvctx);
    590:   VecDestroy(&mdn->cvec);
    591:   MatDestroy(&mdn->cmat);

    593:   PetscFree(mat->data);
    594:   PetscObjectChangeTypeName((PetscObject)mat,NULL);

    596:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetLDA_C",NULL);
    597:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseSetLDA_C",NULL);
    598:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetArray_C",NULL);
    599:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreArray_C",NULL);
    600:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetArrayRead_C",NULL);
    601:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreArrayRead_C",NULL);
    602:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetArrayWrite_C",NULL);
    603:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreArrayWrite_C",NULL);
    604:   PetscObjectComposeFunction((PetscObject)mat,"MatDensePlaceArray_C",NULL);
    605:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseResetArray_C",NULL);
    606:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseReplaceArray_C",NULL);
    607:   PetscObjectComposeFunction((PetscObject)mat,"MatConvert_mpiaij_mpidense_C",NULL);
    608:   PetscObjectComposeFunction((PetscObject)mat,"MatConvert_mpidense_mpiaij_C",NULL);
    609: #if defined(PETSC_HAVE_ELEMENTAL)
    610:   PetscObjectComposeFunction((PetscObject)mat,"MatConvert_mpidense_elemental_C",NULL);
    611: #endif
    612: #if defined(PETSC_HAVE_SCALAPACK)
    613:   PetscObjectComposeFunction((PetscObject)mat,"MatConvert_mpidense_scalapack_C",NULL);
    614: #endif
    615:   PetscObjectComposeFunction((PetscObject)mat,"MatMPIDenseSetPreallocation_C",NULL);
    616:   PetscObjectComposeFunction((PetscObject)mat,"MatProductSetFromOptions_mpiaij_mpidense_C",NULL);
    617:   PetscObjectComposeFunction((PetscObject)mat,"MatProductSetFromOptions_mpidense_mpiaij_C",NULL);
    618: #if defined (PETSC_HAVE_CUDA)
    619:   PetscObjectComposeFunction((PetscObject)mat,"MatProductSetFromOptions_mpiaijcusparse_mpidense_C",NULL);
    620:   PetscObjectComposeFunction((PetscObject)mat,"MatProductSetFromOptions_mpidense_mpiaijcusparse_C",NULL);
    621: #endif
    622:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumn_C",NULL);
    623:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumn_C",NULL);
    624:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVec_C",NULL);
    625:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVec_C",NULL);
    626:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVecRead_C",NULL);
    627:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVecRead_C",NULL);
    628:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVecWrite_C",NULL);
    629:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVecWrite_C",NULL);
    630:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetSubMatrix_C",NULL);
    631:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreSubMatrix_C",NULL);
    632:   return(0);
    633: }

    635: PETSC_INTERN PetscErrorCode MatView_SeqDense(Mat,PetscViewer);

    637: #include <petscdraw.h>
    638: static PetscErrorCode MatView_MPIDense_ASCIIorDraworSocket(Mat mat,PetscViewer viewer)
    639: {
    640:   Mat_MPIDense      *mdn = (Mat_MPIDense*)mat->data;
    641:   PetscErrorCode    ierr;
    642:   PetscMPIInt       rank;
    643:   PetscViewerType   vtype;
    644:   PetscBool         iascii,isdraw;
    645:   PetscViewer       sviewer;
    646:   PetscViewerFormat format;

    649:   MPI_Comm_rank(PetscObjectComm((PetscObject)mat),&rank);
    650:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
    651:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);
    652:   if (iascii) {
    653:     PetscViewerGetType(viewer,&vtype);
    654:     PetscViewerGetFormat(viewer,&format);
    655:     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
    656:       MatInfo info;
    657:       MatGetInfo(mat,MAT_LOCAL,&info);
    658:       PetscViewerASCIIPushSynchronized(viewer);
    659:       PetscViewerASCIISynchronizedPrintf(viewer,"  [%d] local rows %D nz %D nz alloced %D mem %D \n",rank,mat->rmap->n,(PetscInt)info.nz_used,(PetscInt)info.nz_allocated,(PetscInt)info.memory);
    660:       PetscViewerFlush(viewer);
    661:       PetscViewerASCIIPopSynchronized(viewer);
    662:       PetscSFView(mdn->Mvctx,viewer);
    663:       return(0);
    664:     } else if (format == PETSC_VIEWER_ASCII_INFO) {
    665:       return(0);
    666:     }
    667:   } else if (isdraw) {
    668:     PetscDraw draw;
    669:     PetscBool isnull;

    671:     PetscViewerDrawGetDraw(viewer,0,&draw);
    672:     PetscDrawIsNull(draw,&isnull);
    673:     if (isnull) return(0);
    674:   }

    676:   {
    677:     /* assemble the entire matrix onto first processor. */
    678:     Mat         A;
    679:     PetscInt    M = mat->rmap->N,N = mat->cmap->N,m,row,i,nz;
    680:     PetscInt    *cols;
    681:     PetscScalar *vals;

    683:     MatCreate(PetscObjectComm((PetscObject)mat),&A);
    684:     if (!rank) {
    685:       MatSetSizes(A,M,N,M,N);
    686:     } else {
    687:       MatSetSizes(A,0,0,M,N);
    688:     }
    689:     /* Since this is a temporary matrix, MATMPIDENSE instead of ((PetscObject)A)->type_name here is probably acceptable. */
    690:     MatSetType(A,MATMPIDENSE);
    691:     MatMPIDenseSetPreallocation(A,NULL);
    692:     PetscLogObjectParent((PetscObject)mat,(PetscObject)A);

    694:     /* Copy the matrix ... This isn't the most efficient means,
    695:        but it's quick for now */
    696:     A->insertmode = INSERT_VALUES;

    698:     row = mat->rmap->rstart;
    699:     m   = mdn->A->rmap->n;
    700:     for (i=0; i<m; i++) {
    701:       MatGetRow_MPIDense(mat,row,&nz,&cols,&vals);
    702:       MatSetValues_MPIDense(A,1,&row,nz,cols,vals,INSERT_VALUES);
    703:       MatRestoreRow_MPIDense(mat,row,&nz,&cols,&vals);
    704:       row++;
    705:     }

    707:     MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    708:     MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
    709:     PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
    710:     if (!rank) {
    711:       PetscObjectSetName((PetscObject)((Mat_MPIDense*)(A->data))->A,((PetscObject)mat)->name);
    712:       MatView_SeqDense(((Mat_MPIDense*)(A->data))->A,sviewer);
    713:     }
    714:     PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
    715:     PetscViewerFlush(viewer);
    716:     MatDestroy(&A);
    717:   }
    718:   return(0);
    719: }

    721: PetscErrorCode MatView_MPIDense(Mat mat,PetscViewer viewer)
    722: {
    724:   PetscBool      iascii,isbinary,isdraw,issocket;

    727:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
    728:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
    729:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSOCKET,&issocket);
    730:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);

    732:   if (iascii || issocket || isdraw) {
    733:     MatView_MPIDense_ASCIIorDraworSocket(mat,viewer);
    734:   } else if (isbinary) {
    735:     MatView_Dense_Binary(mat,viewer);
    736:   }
    737:   return(0);
    738: }

    740: PetscErrorCode MatGetInfo_MPIDense(Mat A,MatInfoType flag,MatInfo *info)
    741: {
    742:   Mat_MPIDense   *mat = (Mat_MPIDense*)A->data;
    743:   Mat            mdn  = mat->A;
    745:   PetscLogDouble isend[5],irecv[5];

    748:   info->block_size = 1.0;

    750:   MatGetInfo(mdn,MAT_LOCAL,info);

    752:   isend[0] = info->nz_used; isend[1] = info->nz_allocated; isend[2] = info->nz_unneeded;
    753:   isend[3] = info->memory;  isend[4] = info->mallocs;
    754:   if (flag == MAT_LOCAL) {
    755:     info->nz_used      = isend[0];
    756:     info->nz_allocated = isend[1];
    757:     info->nz_unneeded  = isend[2];
    758:     info->memory       = isend[3];
    759:     info->mallocs      = isend[4];
    760:   } else if (flag == MAT_GLOBAL_MAX) {
    761:     MPIU_Allreduce(isend,irecv,5,MPIU_PETSCLOGDOUBLE,MPI_MAX,PetscObjectComm((PetscObject)A));

    763:     info->nz_used      = irecv[0];
    764:     info->nz_allocated = irecv[1];
    765:     info->nz_unneeded  = irecv[2];
    766:     info->memory       = irecv[3];
    767:     info->mallocs      = irecv[4];
    768:   } else if (flag == MAT_GLOBAL_SUM) {
    769:     MPIU_Allreduce(isend,irecv,5,MPIU_PETSCLOGDOUBLE,MPI_SUM,PetscObjectComm((PetscObject)A));

    771:     info->nz_used      = irecv[0];
    772:     info->nz_allocated = irecv[1];
    773:     info->nz_unneeded  = irecv[2];
    774:     info->memory       = irecv[3];
    775:     info->mallocs      = irecv[4];
    776:   }
    777:   info->fill_ratio_given  = 0; /* no parallel LU/ILU/Cholesky */
    778:   info->fill_ratio_needed = 0;
    779:   info->factor_mallocs    = 0;
    780:   return(0);
    781: }

    783: PetscErrorCode MatSetOption_MPIDense(Mat A,MatOption op,PetscBool flg)
    784: {
    785:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    789:   switch (op) {
    790:   case MAT_NEW_NONZERO_LOCATIONS:
    791:   case MAT_NEW_NONZERO_LOCATION_ERR:
    792:   case MAT_NEW_NONZERO_ALLOCATION_ERR:
    793:     MatCheckPreallocated(A,1);
    794:     MatSetOption(a->A,op,flg);
    795:     break;
    796:   case MAT_ROW_ORIENTED:
    797:     MatCheckPreallocated(A,1);
    798:     a->roworiented = flg;
    799:     MatSetOption(a->A,op,flg);
    800:     break;
    801:   case MAT_FORCE_DIAGONAL_ENTRIES:
    802:   case MAT_KEEP_NONZERO_PATTERN:
    803:   case MAT_USE_HASH_TABLE:
    804:   case MAT_SORTED_FULL:
    805:     PetscInfo1(A,"Option %s ignored\n",MatOptions[op]);
    806:     break;
    807:   case MAT_IGNORE_OFF_PROC_ENTRIES:
    808:     a->donotstash = flg;
    809:     break;
    810:   case MAT_SYMMETRIC:
    811:   case MAT_STRUCTURALLY_SYMMETRIC:
    812:   case MAT_HERMITIAN:
    813:   case MAT_SYMMETRY_ETERNAL:
    814:   case MAT_IGNORE_LOWER_TRIANGULAR:
    815:   case MAT_IGNORE_ZERO_ENTRIES:
    816:     PetscInfo1(A,"Option %s ignored\n",MatOptions[op]);
    817:     break;
    818:   default:
    819:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"unknown option %s",MatOptions[op]);
    820:   }
    821:   return(0);
    822: }

    824: PetscErrorCode MatDiagonalScale_MPIDense(Mat A,Vec ll,Vec rr)
    825: {
    826:   Mat_MPIDense      *mdn = (Mat_MPIDense*)A->data;
    827:   const PetscScalar *l;
    828:   PetscScalar       x,*v,*vv,*r;
    829:   PetscErrorCode    ierr;
    830:   PetscInt          i,j,s2a,s3a,s2,s3,m=mdn->A->rmap->n,n=mdn->A->cmap->n,lda;

    833:   MatDenseGetArray(mdn->A,&vv);
    834:   MatDenseGetLDA(mdn->A,&lda);
    835:   MatGetLocalSize(A,&s2,&s3);
    836:   if (ll) {
    837:     VecGetLocalSize(ll,&s2a);
    838:     if (s2a != s2) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Left scaling vector non-conforming local size, %D != %D", s2a, s2);
    839:     VecGetArrayRead(ll,&l);
    840:     for (i=0; i<m; i++) {
    841:       x = l[i];
    842:       v = vv + i;
    843:       for (j=0; j<n; j++) { (*v) *= x; v+= lda;}
    844:     }
    845:     VecRestoreArrayRead(ll,&l);
    846:     PetscLogFlops(1.0*n*m);
    847:   }
    848:   if (rr) {
    849:     const PetscScalar *ar;

    851:     VecGetLocalSize(rr,&s3a);
    852:     if (s3a != s3) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Right scaling vec non-conforming local size, %d != %d.", s3a, s3);
    853:     VecGetArrayRead(rr,&ar);
    854:     VecGetArray(mdn->lvec,&r);
    855:     PetscSFBcastBegin(mdn->Mvctx,MPIU_SCALAR,ar,r,MPI_REPLACE);
    856:     PetscSFBcastEnd(mdn->Mvctx,MPIU_SCALAR,ar,r,MPI_REPLACE);
    857:     VecRestoreArrayRead(rr,&ar);
    858:     for (i=0; i<n; i++) {
    859:       x = r[i];
    860:       v = vv + i*lda;
    861:       for (j=0; j<m; j++) (*v++) *= x;
    862:     }
    863:     VecRestoreArray(mdn->lvec,&r);
    864:     PetscLogFlops(1.0*n*m);
    865:   }
    866:   MatDenseRestoreArray(mdn->A,&vv);
    867:   return(0);
    868: }

    870: PetscErrorCode MatNorm_MPIDense(Mat A,NormType type,PetscReal *nrm)
    871: {
    872:   Mat_MPIDense      *mdn = (Mat_MPIDense*)A->data;
    873:   PetscErrorCode    ierr;
    874:   PetscInt          i,j;
    875:   PetscMPIInt       size;
    876:   PetscReal         sum = 0.0;
    877:   const PetscScalar *av,*v;

    880:   MatDenseGetArrayRead(mdn->A,&av);
    881:   v    = av;
    882:   MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);
    883:   if (size == 1) {
    884:     MatNorm(mdn->A,type,nrm);
    885:   } else {
    886:     if (type == NORM_FROBENIUS) {
    887:       for (i=0; i<mdn->A->cmap->n*mdn->A->rmap->n; i++) {
    888:         sum += PetscRealPart(PetscConj(*v)*(*v)); v++;
    889:       }
    890:       MPIU_Allreduce(&sum,nrm,1,MPIU_REAL,MPIU_SUM,PetscObjectComm((PetscObject)A));
    891:       *nrm = PetscSqrtReal(*nrm);
    892:       PetscLogFlops(2.0*mdn->A->cmap->n*mdn->A->rmap->n);
    893:     } else if (type == NORM_1) {
    894:       PetscReal *tmp,*tmp2;
    895:       PetscCalloc2(A->cmap->N,&tmp,A->cmap->N,&tmp2);
    896:       *nrm = 0.0;
    897:       v    = av;
    898:       for (j=0; j<mdn->A->cmap->n; j++) {
    899:         for (i=0; i<mdn->A->rmap->n; i++) {
    900:           tmp[j] += PetscAbsScalar(*v);  v++;
    901:         }
    902:       }
    903:       MPIU_Allreduce(tmp,tmp2,A->cmap->N,MPIU_REAL,MPIU_SUM,PetscObjectComm((PetscObject)A));
    904:       for (j=0; j<A->cmap->N; j++) {
    905:         if (tmp2[j] > *nrm) *nrm = tmp2[j];
    906:       }
    907:       PetscFree2(tmp,tmp2);
    908:       PetscLogFlops(A->cmap->n*A->rmap->n);
    909:     } else if (type == NORM_INFINITY) { /* max row norm */
    910:       PetscReal ntemp;
    911:       MatNorm(mdn->A,type,&ntemp);
    912:       MPIU_Allreduce(&ntemp,nrm,1,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)A));
    913:     } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support for two norm");
    914:   }
    915:   MatDenseRestoreArrayRead(mdn->A,&av);
    916:   return(0);
    917: }

    919: PetscErrorCode MatTranspose_MPIDense(Mat A,MatReuse reuse,Mat *matout)
    920: {
    921:   Mat_MPIDense   *a    = (Mat_MPIDense*)A->data;
    922:   Mat            B;
    923:   PetscInt       M = A->rmap->N,N = A->cmap->N,m,n,*rwork,rstart = A->rmap->rstart;
    925:   PetscInt       j,i,lda;
    926:   PetscScalar    *v;

    929:   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
    930:     MatCreate(PetscObjectComm((PetscObject)A),&B);
    931:     MatSetSizes(B,A->cmap->n,A->rmap->n,N,M);
    932:     MatSetType(B,((PetscObject)A)->type_name);
    933:     MatMPIDenseSetPreallocation(B,NULL);
    934:   } else B = *matout;

    936:   m    = a->A->rmap->n; n = a->A->cmap->n;
    937:   MatDenseGetArrayRead(a->A,(const PetscScalar**)&v);
    938:   MatDenseGetLDA(a->A,&lda);
    939:   PetscMalloc1(m,&rwork);
    940:   for (i=0; i<m; i++) rwork[i] = rstart + i;
    941:   for (j=0; j<n; j++) {
    942:     MatSetValues(B,1,&j,m,rwork,v,INSERT_VALUES);
    943:     v   += lda;
    944:   }
    945:   MatDenseRestoreArrayRead(a->A,(const PetscScalar**)&v);
    946:   PetscFree(rwork);
    947:   MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
    948:   MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
    949:   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
    950:     *matout = B;
    951:   } else {
    952:     MatHeaderMerge(A,&B);
    953:   }
    954:   return(0);
    955: }

    957: static PetscErrorCode MatDuplicate_MPIDense(Mat,MatDuplicateOption,Mat*);
    958: PETSC_INTERN PetscErrorCode MatScale_MPIDense(Mat,PetscScalar);

    960: PetscErrorCode MatSetUp_MPIDense(Mat A)
    961: {

    965:   PetscLayoutSetUp(A->rmap);
    966:   PetscLayoutSetUp(A->cmap);
    967:   if (!A->preallocated) {
    968:     MatMPIDenseSetPreallocation(A,NULL);
    969:   }
    970:   return(0);
    971: }

    973: PetscErrorCode MatAXPY_MPIDense(Mat Y,PetscScalar alpha,Mat X,MatStructure str)
    974: {
    976:   Mat_MPIDense   *A = (Mat_MPIDense*)Y->data, *B = (Mat_MPIDense*)X->data;

    979:   MatAXPY(A->A,alpha,B->A,str);
    980:   return(0);
    981: }

    983: PetscErrorCode MatConjugate_MPIDense(Mat mat)
    984: {
    985:   Mat_MPIDense   *a = (Mat_MPIDense*)mat->data;

    989:   MatConjugate(a->A);
    990:   return(0);
    991: }

    993: PetscErrorCode MatRealPart_MPIDense(Mat A)
    994: {
    995:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    999:   MatRealPart(a->A);
    1000:   return(0);
    1001: }

    1003: PetscErrorCode MatImaginaryPart_MPIDense(Mat A)
    1004: {
    1005:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    1009:   MatImaginaryPart(a->A);
    1010:   return(0);
    1011: }

    1013: static PetscErrorCode MatGetColumnVector_MPIDense(Mat A,Vec v,PetscInt col)
    1014: {
    1016:   Mat_MPIDense   *a = (Mat_MPIDense*) A->data;

    1019:   if (!a->A) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Missing local matrix");
    1020:   if (!a->A->ops->getcolumnvector) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Missing get column operation");
    1021:   (*a->A->ops->getcolumnvector)(a->A,v,col);
    1022:   return(0);
    1023: }

    1025: PETSC_INTERN PetscErrorCode MatGetColumnNorms_SeqDense(Mat,NormType,PetscReal*);

    1027: PetscErrorCode MatGetColumnNorms_MPIDense(Mat A,NormType type,PetscReal *norms)
    1028: {
    1030:   PetscInt       i,n;
    1031:   Mat_MPIDense   *a = (Mat_MPIDense*) A->data;
    1032:   PetscReal      *work;

    1035:   MatGetSize(A,NULL,&n);
    1036:   PetscMalloc1(n,&work);
    1037:   MatGetColumnNorms_SeqDense(a->A,type,work);
    1038:   if (type == NORM_2) {
    1039:     for (i=0; i<n; i++) work[i] *= work[i];
    1040:   }
    1041:   if (type == NORM_INFINITY) {
    1042:     MPIU_Allreduce(work,norms,n,MPIU_REAL,MPIU_MAX,A->hdr.comm);
    1043:   } else {
    1044:     MPIU_Allreduce(work,norms,n,MPIU_REAL,MPIU_SUM,A->hdr.comm);
    1045:   }
    1046:   PetscFree(work);
    1047:   if (type == NORM_2) {
    1048:     for (i=0; i<n; i++) norms[i] = PetscSqrtReal(norms[i]);
    1049:   }
    1050:   return(0);
    1051: }

    1053: #if defined(PETSC_HAVE_CUDA)
    1054: static PetscErrorCode MatDenseGetColumnVec_MPIDenseCUDA(Mat A,PetscInt col,Vec *v)
    1055: {
    1056:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;
    1058:   PetscInt       lda;

    1061:   if (a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1062:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1063:   if (!a->cvec) {
    1064:     VecCreateMPICUDAWithArray(PetscObjectComm((PetscObject)A),A->rmap->bs,A->rmap->n,A->rmap->N,NULL,&a->cvec);
    1065:     PetscLogObjectParent((PetscObject)A,(PetscObject)a->cvec);
    1066:   }
    1067:   a->vecinuse = col + 1;
    1068:   MatDenseGetLDA(a->A,&lda);
    1069:   MatDenseCUDAGetArray(a->A,(PetscScalar**)&a->ptrinuse);
    1070:   VecCUDAPlaceArray(a->cvec,a->ptrinuse + (size_t)col * (size_t)lda);
    1071:   *v   = a->cvec;
    1072:   return(0);
    1073: }

    1075: static PetscErrorCode MatDenseRestoreColumnVec_MPIDenseCUDA(Mat A,PetscInt col,Vec *v)
    1076: {
    1077:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    1081:   if (!a->vecinuse) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Need to call MatDenseGetColumnVec() first");
    1082:   if (!a->cvec) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing internal column vector");
    1083:   a->vecinuse = 0;
    1084:   MatDenseCUDARestoreArray(a->A,(PetscScalar**)&a->ptrinuse);
    1085:   VecCUDAResetArray(a->cvec);
    1086:   *v   = NULL;
    1087:   return(0);
    1088: }

    1090: static PetscErrorCode MatDenseGetColumnVecRead_MPIDenseCUDA(Mat A,PetscInt col,Vec *v)
    1091: {
    1092:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;
    1093:   PetscInt       lda;

    1097:   if (a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1098:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1099:   if (!a->cvec) {
    1100:     VecCreateMPICUDAWithArray(PetscObjectComm((PetscObject)A),A->rmap->bs,A->rmap->n,A->rmap->N,NULL,&a->cvec);
    1101:     PetscLogObjectParent((PetscObject)A,(PetscObject)a->cvec);
    1102:   }
    1103:   a->vecinuse = col + 1;
    1104:   MatDenseGetLDA(a->A,&lda);
    1105:   MatDenseCUDAGetArrayRead(a->A,&a->ptrinuse);
    1106:   VecCUDAPlaceArray(a->cvec,a->ptrinuse + (size_t)col * (size_t)lda);
    1107:   VecLockReadPush(a->cvec);
    1108:   *v   = a->cvec;
    1109:   return(0);
    1110: }

    1112: static PetscErrorCode MatDenseRestoreColumnVecRead_MPIDenseCUDA(Mat A,PetscInt col,Vec *v)
    1113: {
    1114:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    1118:   if (!a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseGetColumnVec() first");
    1119:   if (!a->cvec) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing internal column vector");
    1120:   a->vecinuse = 0;
    1121:   MatDenseCUDARestoreArrayRead(a->A,&a->ptrinuse);
    1122:   VecLockReadPop(a->cvec);
    1123:   VecCUDAResetArray(a->cvec);
    1124:   *v   = NULL;
    1125:   return(0);
    1126: }

    1128: static PetscErrorCode MatDenseGetColumnVecWrite_MPIDenseCUDA(Mat A,PetscInt col,Vec *v)
    1129: {
    1130:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;
    1132:   PetscInt       lda;

    1135:   if (a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1136:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1137:   if (!a->cvec) {
    1138:     VecCreateMPICUDAWithArray(PetscObjectComm((PetscObject)A),A->rmap->bs,A->rmap->n,A->rmap->N,NULL,&a->cvec);
    1139:     PetscLogObjectParent((PetscObject)A,(PetscObject)a->cvec);
    1140:   }
    1141:   a->vecinuse = col + 1;
    1142:   MatDenseGetLDA(a->A,&lda);
    1143:   MatDenseCUDAGetArrayWrite(a->A,(PetscScalar**)&a->ptrinuse);
    1144:   VecCUDAPlaceArray(a->cvec,a->ptrinuse + (size_t)col * (size_t)lda);
    1145:   *v   = a->cvec;
    1146:   return(0);
    1147: }

    1149: static PetscErrorCode MatDenseRestoreColumnVecWrite_MPIDenseCUDA(Mat A,PetscInt col,Vec *v)
    1150: {
    1151:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    1155:   if (!a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseGetColumnVec() first");
    1156:   if (!a->cvec) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing internal column vector");
    1157:   a->vecinuse = 0;
    1158:   MatDenseCUDARestoreArrayWrite(a->A,(PetscScalar**)&a->ptrinuse);
    1159:   VecCUDAResetArray(a->cvec);
    1160:   *v   = NULL;
    1161:   return(0);
    1162: }

    1164: static PetscErrorCode MatDenseCUDAPlaceArray_MPIDenseCUDA(Mat A, const PetscScalar *a)
    1165: {
    1166:   Mat_MPIDense   *l = (Mat_MPIDense*) A->data;

    1170:   if (l->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1171:   if (l->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1172:   MatDenseCUDAPlaceArray(l->A,a);
    1173:   return(0);
    1174: }

    1176: static PetscErrorCode MatDenseCUDAResetArray_MPIDenseCUDA(Mat A)
    1177: {
    1178:   Mat_MPIDense   *l = (Mat_MPIDense*) A->data;

    1182:   if (l->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1183:   if (l->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1184:   MatDenseCUDAResetArray(l->A);
    1185:   return(0);
    1186: }

    1188: static PetscErrorCode MatDenseCUDAReplaceArray_MPIDenseCUDA(Mat A, const PetscScalar *a)
    1189: {
    1190:   Mat_MPIDense   *l = (Mat_MPIDense*) A->data;

    1194:   if (l->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1195:   if (l->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1196:   MatDenseCUDAReplaceArray(l->A,a);
    1197:   return(0);
    1198: }

    1200: static PetscErrorCode MatDenseCUDAGetArrayWrite_MPIDenseCUDA(Mat A, PetscScalar **a)
    1201: {
    1202:   Mat_MPIDense   *l = (Mat_MPIDense*) A->data;

    1206:   MatDenseCUDAGetArrayWrite(l->A,a);
    1207:   return(0);
    1208: }

    1210: static PetscErrorCode MatDenseCUDARestoreArrayWrite_MPIDenseCUDA(Mat A, PetscScalar **a)
    1211: {
    1212:   Mat_MPIDense   *l = (Mat_MPIDense*) A->data;

    1216:   MatDenseCUDARestoreArrayWrite(l->A,a);
    1217:   return(0);
    1218: }

    1220: static PetscErrorCode MatDenseCUDAGetArrayRead_MPIDenseCUDA(Mat A, const PetscScalar **a)
    1221: {
    1222:   Mat_MPIDense   *l = (Mat_MPIDense*) A->data;

    1226:   MatDenseCUDAGetArrayRead(l->A,a);
    1227:   return(0);
    1228: }

    1230: static PetscErrorCode MatDenseCUDARestoreArrayRead_MPIDenseCUDA(Mat A, const PetscScalar **a)
    1231: {
    1232:   Mat_MPIDense   *l = (Mat_MPIDense*) A->data;

    1236:   MatDenseCUDARestoreArrayRead(l->A,a);
    1237:   return(0);
    1238: }

    1240: static PetscErrorCode MatDenseCUDAGetArray_MPIDenseCUDA(Mat A, PetscScalar **a)
    1241: {
    1242:   Mat_MPIDense   *l = (Mat_MPIDense*) A->data;

    1246:   MatDenseCUDAGetArray(l->A,a);
    1247:   return(0);
    1248: }

    1250: static PetscErrorCode MatDenseCUDARestoreArray_MPIDenseCUDA(Mat A, PetscScalar **a)
    1251: {
    1252:   Mat_MPIDense   *l = (Mat_MPIDense*) A->data;

    1256:   MatDenseCUDARestoreArray(l->A,a);
    1257:   return(0);
    1258: }

    1260: static PetscErrorCode MatDenseGetColumnVecWrite_MPIDense(Mat,PetscInt,Vec*);
    1261: static PetscErrorCode MatDenseGetColumnVecRead_MPIDense(Mat,PetscInt,Vec*);
    1262: static PetscErrorCode MatDenseGetColumnVec_MPIDense(Mat,PetscInt,Vec*);
    1263: static PetscErrorCode MatDenseRestoreColumnVecWrite_MPIDense(Mat,PetscInt,Vec*);
    1264: static PetscErrorCode MatDenseRestoreColumnVecRead_MPIDense(Mat,PetscInt,Vec*);
    1265: static PetscErrorCode MatDenseRestoreColumnVec_MPIDense(Mat,PetscInt,Vec*);
    1266: static PetscErrorCode MatDenseRestoreSubMatrix_MPIDense(Mat,Mat*);

    1268: static PetscErrorCode MatBindToCPU_MPIDenseCUDA(Mat mat,PetscBool bind)
    1269: {
    1270:   Mat_MPIDense   *d = (Mat_MPIDense*)mat->data;

    1274:   if (d->vecinuse) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1275:   if (d->matinuse) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1276:   if (d->A) {
    1277:     MatBindToCPU(d->A,bind);
    1278:   }
    1279:   mat->boundtocpu = bind;
    1280:   if (!bind) {
    1281:     PetscBool iscuda;

    1283:     PetscObjectTypeCompare((PetscObject)d->cvec,VECMPICUDA,&iscuda);
    1284:     if (!iscuda) {
    1285:       VecDestroy(&d->cvec);
    1286:     }
    1287:     PetscObjectTypeCompare((PetscObject)d->cmat,MATMPIDENSECUDA,&iscuda);
    1288:     if (!iscuda) {
    1289:       MatDestroy(&d->cmat);
    1290:     }
    1291:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVec_C",MatDenseGetColumnVec_MPIDenseCUDA);
    1292:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVec_C",MatDenseRestoreColumnVec_MPIDenseCUDA);
    1293:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVecRead_C",MatDenseGetColumnVecRead_MPIDenseCUDA);
    1294:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVecRead_C",MatDenseRestoreColumnVecRead_MPIDenseCUDA);
    1295:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVecWrite_C",MatDenseGetColumnVecWrite_MPIDenseCUDA);
    1296:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVecWrite_C",MatDenseRestoreColumnVecWrite_MPIDenseCUDA);
    1297:   } else {
    1298:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVec_C",MatDenseGetColumnVec_MPIDense);
    1299:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVec_C",MatDenseRestoreColumnVec_MPIDense);
    1300:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVecRead_C",MatDenseGetColumnVecRead_MPIDense);
    1301:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVecRead_C",MatDenseRestoreColumnVecRead_MPIDense);
    1302:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVecWrite_C",MatDenseGetColumnVecWrite_MPIDense);
    1303:     PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVecWrite_C",MatDenseRestoreColumnVecWrite_MPIDense);
    1304:   }
    1305:   if (d->cmat) {
    1306:     MatBindToCPU(d->cmat,bind);
    1307:   }
    1308:   return(0);
    1309: }

    1311: PetscErrorCode MatMPIDenseCUDASetPreallocation(Mat A, PetscScalar *d_data)
    1312: {
    1313:   Mat_MPIDense   *d = (Mat_MPIDense*)A->data;
    1315:   PetscBool      iscuda;

    1319:   PetscObjectTypeCompare((PetscObject)A,MATMPIDENSECUDA,&iscuda);
    1320:   if (!iscuda) return(0);
    1321:   PetscLayoutSetUp(A->rmap);
    1322:   PetscLayoutSetUp(A->cmap);
    1323:   if (!d->A) {
    1324:     MatCreate(PETSC_COMM_SELF,&d->A);
    1325:     PetscLogObjectParent((PetscObject)A,(PetscObject)d->A);
    1326:     MatSetSizes(d->A,A->rmap->n,A->cmap->N,A->rmap->n,A->cmap->N);
    1327:   }
    1328:   MatSetType(d->A,MATSEQDENSECUDA);
    1329:   MatSeqDenseCUDASetPreallocation(d->A,d_data);
    1330:   A->preallocated = PETSC_TRUE;
    1331:   return(0);
    1332: }
    1333: #endif

    1335: static PetscErrorCode MatSetRandom_MPIDense(Mat x,PetscRandom rctx)
    1336: {
    1337:   Mat_MPIDense   *d = (Mat_MPIDense*)x->data;

    1341:   MatSetRandom(d->A,rctx);
    1342:   return(0);
    1343: }

    1345: static PetscErrorCode MatMissingDiagonal_MPIDense(Mat A,PetscBool  *missing,PetscInt *d)
    1346: {
    1348:   *missing = PETSC_FALSE;
    1349:   return(0);
    1350: }

    1352: static PetscErrorCode MatMatTransposeMultSymbolic_MPIDense_MPIDense(Mat,Mat,PetscReal,Mat);
    1353: static PetscErrorCode MatMatTransposeMultNumeric_MPIDense_MPIDense(Mat,Mat,Mat);
    1354: static PetscErrorCode MatTransposeMatMultNumeric_MPIDense_MPIDense(Mat,Mat,Mat);
    1355: static PetscErrorCode MatTransposeMatMultSymbolic_MPIDense_MPIDense(Mat,Mat,PetscReal,Mat);
    1356: static PetscErrorCode MatEqual_MPIDense(Mat,Mat,PetscBool*);
    1357: static PetscErrorCode MatLoad_MPIDense(Mat,PetscViewer);

    1359: /* -------------------------------------------------------------------*/
    1360: static struct _MatOps MatOps_Values = { MatSetValues_MPIDense,
    1361:                                         MatGetRow_MPIDense,
    1362:                                         MatRestoreRow_MPIDense,
    1363:                                         MatMult_MPIDense,
    1364:                                 /*  4*/ MatMultAdd_MPIDense,
    1365:                                         MatMultTranspose_MPIDense,
    1366:                                         MatMultTransposeAdd_MPIDense,
    1367:                                         NULL,
    1368:                                         NULL,
    1369:                                         NULL,
    1370:                                 /* 10*/ NULL,
    1371:                                         NULL,
    1372:                                         NULL,
    1373:                                         NULL,
    1374:                                         MatTranspose_MPIDense,
    1375:                                 /* 15*/ MatGetInfo_MPIDense,
    1376:                                         MatEqual_MPIDense,
    1377:                                         MatGetDiagonal_MPIDense,
    1378:                                         MatDiagonalScale_MPIDense,
    1379:                                         MatNorm_MPIDense,
    1380:                                 /* 20*/ MatAssemblyBegin_MPIDense,
    1381:                                         MatAssemblyEnd_MPIDense,
    1382:                                         MatSetOption_MPIDense,
    1383:                                         MatZeroEntries_MPIDense,
    1384:                                 /* 24*/ MatZeroRows_MPIDense,
    1385:                                         NULL,
    1386:                                         NULL,
    1387:                                         NULL,
    1388:                                         NULL,
    1389:                                 /* 29*/ MatSetUp_MPIDense,
    1390:                                         NULL,
    1391:                                         NULL,
    1392:                                         MatGetDiagonalBlock_MPIDense,
    1393:                                         NULL,
    1394:                                 /* 34*/ MatDuplicate_MPIDense,
    1395:                                         NULL,
    1396:                                         NULL,
    1397:                                         NULL,
    1398:                                         NULL,
    1399:                                 /* 39*/ MatAXPY_MPIDense,
    1400:                                         MatCreateSubMatrices_MPIDense,
    1401:                                         NULL,
    1402:                                         MatGetValues_MPIDense,
    1403:                                         MatCopy_MPIDense,
    1404:                                 /* 44*/ NULL,
    1405:                                         MatScale_MPIDense,
    1406:                                         MatShift_Basic,
    1407:                                         NULL,
    1408:                                         NULL,
    1409:                                 /* 49*/ MatSetRandom_MPIDense,
    1410:                                         NULL,
    1411:                                         NULL,
    1412:                                         NULL,
    1413:                                         NULL,
    1414:                                 /* 54*/ NULL,
    1415:                                         NULL,
    1416:                                         NULL,
    1417:                                         NULL,
    1418:                                         NULL,
    1419:                                 /* 59*/ MatCreateSubMatrix_MPIDense,
    1420:                                         MatDestroy_MPIDense,
    1421:                                         MatView_MPIDense,
    1422:                                         NULL,
    1423:                                         NULL,
    1424:                                 /* 64*/ NULL,
    1425:                                         NULL,
    1426:                                         NULL,
    1427:                                         NULL,
    1428:                                         NULL,
    1429:                                 /* 69*/ NULL,
    1430:                                         NULL,
    1431:                                         NULL,
    1432:                                         NULL,
    1433:                                         NULL,
    1434:                                 /* 74*/ NULL,
    1435:                                         NULL,
    1436:                                         NULL,
    1437:                                         NULL,
    1438:                                         NULL,
    1439:                                 /* 79*/ NULL,
    1440:                                         NULL,
    1441:                                         NULL,
    1442:                                         NULL,
    1443:                                 /* 83*/ MatLoad_MPIDense,
    1444:                                         NULL,
    1445:                                         NULL,
    1446:                                         NULL,
    1447:                                         NULL,
    1448:                                         NULL,
    1449:                                 /* 89*/ NULL,
    1450:                                         NULL,
    1451:                                         NULL,
    1452:                                         NULL,
    1453:                                         NULL,
    1454:                                 /* 94*/ NULL,
    1455:                                         NULL,
    1456:                                         MatMatTransposeMultSymbolic_MPIDense_MPIDense,
    1457:                                         MatMatTransposeMultNumeric_MPIDense_MPIDense,
    1458:                                         NULL,
    1459:                                 /* 99*/ MatProductSetFromOptions_MPIDense,
    1460:                                         NULL,
    1461:                                         NULL,
    1462:                                         MatConjugate_MPIDense,
    1463:                                         NULL,
    1464:                                 /*104*/ NULL,
    1465:                                         MatRealPart_MPIDense,
    1466:                                         MatImaginaryPart_MPIDense,
    1467:                                         NULL,
    1468:                                         NULL,
    1469:                                 /*109*/ NULL,
    1470:                                         NULL,
    1471:                                         NULL,
    1472:                                         MatGetColumnVector_MPIDense,
    1473:                                         MatMissingDiagonal_MPIDense,
    1474:                                 /*114*/ NULL,
    1475:                                         NULL,
    1476:                                         NULL,
    1477:                                         NULL,
    1478:                                         NULL,
    1479:                                 /*119*/ NULL,
    1480:                                         NULL,
    1481:                                         NULL,
    1482:                                         NULL,
    1483:                                         NULL,
    1484:                                 /*124*/ NULL,
    1485:                                         MatGetColumnNorms_MPIDense,
    1486:                                         NULL,
    1487:                                         NULL,
    1488:                                         NULL,
    1489:                                 /*129*/ NULL,
    1490:                                         NULL,
    1491:                                         MatTransposeMatMultSymbolic_MPIDense_MPIDense,
    1492:                                         MatTransposeMatMultNumeric_MPIDense_MPIDense,
    1493:                                         NULL,
    1494:                                 /*134*/ NULL,
    1495:                                         NULL,
    1496:                                         NULL,
    1497:                                         NULL,
    1498:                                         NULL,
    1499:                                 /*139*/ NULL,
    1500:                                         NULL,
    1501:                                         NULL,
    1502:                                         NULL,
    1503:                                         NULL,
    1504:                                         MatCreateMPIMatConcatenateSeqMat_MPIDense,
    1505:                                 /*145*/ NULL,
    1506:                                         NULL,
    1507:                                         NULL
    1508: };

    1510: PetscErrorCode  MatMPIDenseSetPreallocation_MPIDense(Mat mat,PetscScalar *data)
    1511: {
    1512:   Mat_MPIDense   *a = (Mat_MPIDense*)mat->data;
    1513:   PetscBool      iscuda;

    1517:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1518:   PetscLayoutSetUp(mat->rmap);
    1519:   PetscLayoutSetUp(mat->cmap);
    1520:   if (!a->A) {
    1521:     MatCreate(PETSC_COMM_SELF,&a->A);
    1522:     PetscLogObjectParent((PetscObject)mat,(PetscObject)a->A);
    1523:     MatSetSizes(a->A,mat->rmap->n,mat->cmap->N,mat->rmap->n,mat->cmap->N);
    1524:   }
    1525:   PetscObjectTypeCompare((PetscObject)mat,MATMPIDENSECUDA,&iscuda);
    1526:   MatSetType(a->A,iscuda ? MATSEQDENSECUDA : MATSEQDENSE);
    1527:   MatSeqDenseSetPreallocation(a->A,data);
    1528:   mat->preallocated = PETSC_TRUE;
    1529:   return(0);
    1530: }

    1532: PETSC_INTERN PetscErrorCode MatConvert_MPIAIJ_MPIDense(Mat A, MatType newtype,MatReuse reuse,Mat *newmat)
    1533: {
    1534:   Mat            B,C;

    1538:   MatMPIAIJGetLocalMat(A,MAT_INITIAL_MATRIX,&C);
    1539:   MatConvert_SeqAIJ_SeqDense(C,MATSEQDENSE,MAT_INITIAL_MATRIX,&B);
    1540:   MatDestroy(&C);
    1541:   if (reuse == MAT_REUSE_MATRIX) {
    1542:     C = *newmat;
    1543:   } else C = NULL;
    1544:   MatCreateMPIMatConcatenateSeqMat(PetscObjectComm((PetscObject)A),B,A->cmap->n,!C?MAT_INITIAL_MATRIX:MAT_REUSE_MATRIX,&C);
    1545:   MatDestroy(&B);
    1546:   if (reuse == MAT_INPLACE_MATRIX) {
    1547:     MatHeaderReplace(A,&C);
    1548:   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = C;
    1549:   return(0);
    1550: }

    1552: PetscErrorCode MatConvert_MPIDense_MPIAIJ(Mat A, MatType newtype,MatReuse reuse,Mat *newmat)
    1553: {
    1554:   Mat            B,C;

    1558:   MatDenseGetLocalMatrix(A,&C);
    1559:   MatConvert_SeqDense_SeqAIJ(C,MATSEQAIJ,MAT_INITIAL_MATRIX,&B);
    1560:   if (reuse == MAT_REUSE_MATRIX) {
    1561:     C = *newmat;
    1562:   } else C = NULL;
    1563:   MatCreateMPIMatConcatenateSeqMat(PetscObjectComm((PetscObject)A),B,A->cmap->n,!C?MAT_INITIAL_MATRIX:MAT_REUSE_MATRIX,&C);
    1564:   MatDestroy(&B);
    1565:   if (reuse == MAT_INPLACE_MATRIX) {
    1566:     MatHeaderReplace(A,&C);
    1567:   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = C;
    1568:   return(0);
    1569: }

    1571: #if defined(PETSC_HAVE_ELEMENTAL)
    1572: PETSC_INTERN PetscErrorCode MatConvert_MPIDense_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat)
    1573: {
    1574:   Mat            mat_elemental;
    1576:   PetscScalar    *v;
    1577:   PetscInt       m=A->rmap->n,N=A->cmap->N,rstart=A->rmap->rstart,i,*rows,*cols;

    1580:   if (reuse == MAT_REUSE_MATRIX) {
    1581:     mat_elemental = *newmat;
    1582:     MatZeroEntries(*newmat);
    1583:   } else {
    1584:     MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);
    1585:     MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,A->rmap->N,A->cmap->N);
    1586:     MatSetType(mat_elemental,MATELEMENTAL);
    1587:     MatSetUp(mat_elemental);
    1588:     MatSetOption(mat_elemental,MAT_ROW_ORIENTED,PETSC_FALSE);
    1589:   }

    1591:   PetscMalloc2(m,&rows,N,&cols);
    1592:   for (i=0; i<N; i++) cols[i] = i;
    1593:   for (i=0; i<m; i++) rows[i] = rstart + i;

    1595:   /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
    1596:   MatDenseGetArray(A,&v);
    1597:   MatSetValues(mat_elemental,m,rows,N,cols,v,ADD_VALUES);
    1598:   MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);
    1599:   MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);
    1600:   MatDenseRestoreArray(A,&v);
    1601:   PetscFree2(rows,cols);

    1603:   if (reuse == MAT_INPLACE_MATRIX) {
    1604:     MatHeaderReplace(A,&mat_elemental);
    1605:   } else {
    1606:     *newmat = mat_elemental;
    1607:   }
    1608:   return(0);
    1609: }
    1610: #endif

    1612: static PetscErrorCode MatDenseGetColumn_MPIDense(Mat A,PetscInt col,PetscScalar **vals)
    1613: {
    1614:   Mat_MPIDense   *mat = (Mat_MPIDense*)A->data;

    1618:   MatDenseGetColumn(mat->A,col,vals);
    1619:   return(0);
    1620: }

    1622: static PetscErrorCode MatDenseRestoreColumn_MPIDense(Mat A,PetscScalar **vals)
    1623: {
    1624:   Mat_MPIDense   *mat = (Mat_MPIDense*)A->data;

    1628:   MatDenseRestoreColumn(mat->A,vals);
    1629:   return(0);
    1630: }

    1632: PetscErrorCode MatCreateMPIMatConcatenateSeqMat_MPIDense(MPI_Comm comm,Mat inmat,PetscInt n,MatReuse scall,Mat *outmat)
    1633: {
    1635:   Mat_MPIDense   *mat;
    1636:   PetscInt       m,nloc,N;

    1639:   MatGetSize(inmat,&m,&N);
    1640:   MatGetLocalSize(inmat,NULL,&nloc);
    1641:   if (scall == MAT_INITIAL_MATRIX) { /* symbolic phase */
    1642:     PetscInt sum;

    1644:     if (n == PETSC_DECIDE) {
    1645:       PetscSplitOwnership(comm,&n,&N);
    1646:     }
    1647:     /* Check sum(n) = N */
    1648:     MPIU_Allreduce(&n,&sum,1,MPIU_INT,MPI_SUM,comm);
    1649:     if (sum != N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Sum of local columns %D != global columns %D",sum,N);

    1651:     MatCreateDense(comm,m,n,PETSC_DETERMINE,N,NULL,outmat);
    1652:     MatSetOption(*outmat,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);
    1653:   }

    1655:   /* numeric phase */
    1656:   mat = (Mat_MPIDense*)(*outmat)->data;
    1657:   MatCopy(inmat,mat->A,SAME_NONZERO_PATTERN);
    1658:   MatAssemblyBegin(*outmat,MAT_FINAL_ASSEMBLY);
    1659:   MatAssemblyEnd(*outmat,MAT_FINAL_ASSEMBLY);
    1660:   return(0);
    1661: }

    1663: #if defined(PETSC_HAVE_CUDA)
    1664: PetscErrorCode MatConvert_MPIDenseCUDA_MPIDense(Mat M,MatType type,MatReuse reuse,Mat *newmat)
    1665: {
    1666:   Mat            B;
    1667:   Mat_MPIDense   *m;

    1671:   if (reuse == MAT_INITIAL_MATRIX) {
    1672:     MatDuplicate(M,MAT_COPY_VALUES,newmat);
    1673:   } else if (reuse == MAT_REUSE_MATRIX) {
    1674:     MatCopy(M,*newmat,SAME_NONZERO_PATTERN);
    1675:   }

    1677:   B    = *newmat;
    1678:   MatBindToCPU_MPIDenseCUDA(B,PETSC_TRUE);
    1679:   PetscFree(B->defaultvectype);
    1680:   PetscStrallocpy(VECSTANDARD,&B->defaultvectype);
    1681:   PetscObjectChangeTypeName((PetscObject)B,MATMPIDENSE);
    1682:   PetscObjectComposeFunction((PetscObject)B,"MatConvert_mpidensecuda_mpidense_C",NULL);
    1683:   PetscObjectComposeFunction((PetscObject)B,"MatProductSetFromOptions_mpiaij_mpidensecuda_C",NULL);
    1684:   PetscObjectComposeFunction((PetscObject)B,"MatProductSetFromOptions_mpiaijcusparse_mpidensecuda_C",NULL);
    1685:   PetscObjectComposeFunction((PetscObject)B,"MatProductSetFromOptions_mpidensecuda_mpiaij_C",NULL);
    1686:   PetscObjectComposeFunction((PetscObject)B,"MatProductSetFromOptions_mpidensecuda_mpiaijcusparse_C",NULL);
    1687:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAGetArray_C",NULL);
    1688:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAGetArrayRead_C",NULL);
    1689:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAGetArrayWrite_C",NULL);
    1690:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDARestoreArray_C",NULL);
    1691:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDARestoreArrayRead_C",NULL);
    1692:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDARestoreArrayWrite_C",NULL);
    1693:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAPlaceArray_C",NULL);
    1694:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAResetArray_C",NULL);
    1695:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAReplaceArray_C",NULL);
    1696:   m    = (Mat_MPIDense*)(B)->data;
    1697:   if (m->A) {
    1698:     MatConvert(m->A,MATSEQDENSE,MAT_INPLACE_MATRIX,&m->A);
    1699:     MatSetUpMultiply_MPIDense(B);
    1700:   }
    1701:   B->ops->bindtocpu = NULL;
    1702:   B->offloadmask    = PETSC_OFFLOAD_CPU;
    1703:   return(0);
    1704: }

    1706: PetscErrorCode MatConvert_MPIDense_MPIDenseCUDA(Mat M,MatType type,MatReuse reuse,Mat *newmat)
    1707: {
    1708:   Mat            B;
    1709:   Mat_MPIDense   *m;

    1713:   if (reuse == MAT_INITIAL_MATRIX) {
    1714:     MatDuplicate(M,MAT_COPY_VALUES,newmat);
    1715:   } else if (reuse == MAT_REUSE_MATRIX) {
    1716:     MatCopy(M,*newmat,SAME_NONZERO_PATTERN);
    1717:   }

    1719:   B    = *newmat;
    1720:   PetscFree(B->defaultvectype);
    1721:   PetscStrallocpy(VECCUDA,&B->defaultvectype);
    1722:   PetscObjectChangeTypeName((PetscObject)B,MATMPIDENSECUDA);
    1723:   PetscObjectComposeFunction((PetscObject)B,"MatConvert_mpidensecuda_mpidense_C",                    MatConvert_MPIDenseCUDA_MPIDense);
    1724:   PetscObjectComposeFunction((PetscObject)B,"MatProductSetFromOptions_mpiaij_mpidensecuda_C",        MatProductSetFromOptions_MPIAIJ_MPIDense);
    1725:   PetscObjectComposeFunction((PetscObject)B,"MatProductSetFromOptions_mpiaijcusparse_mpidensecuda_C",MatProductSetFromOptions_MPIAIJ_MPIDense);
    1726:   PetscObjectComposeFunction((PetscObject)B,"MatProductSetFromOptions_mpidensecuda_mpiaij_C",        MatProductSetFromOptions_MPIDense_MPIAIJ);
    1727:   PetscObjectComposeFunction((PetscObject)B,"MatProductSetFromOptions_mpidensecuda_mpiaijcusparse_C",MatProductSetFromOptions_MPIDense_MPIAIJ);
    1728:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAGetArray_C",                                MatDenseCUDAGetArray_MPIDenseCUDA);
    1729:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAGetArrayRead_C",                            MatDenseCUDAGetArrayRead_MPIDenseCUDA);
    1730:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAGetArrayWrite_C",                           MatDenseCUDAGetArrayWrite_MPIDenseCUDA);
    1731:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDARestoreArray_C",                            MatDenseCUDARestoreArray_MPIDenseCUDA);
    1732:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDARestoreArrayRead_C",                        MatDenseCUDARestoreArrayRead_MPIDenseCUDA);
    1733:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDARestoreArrayWrite_C",                       MatDenseCUDARestoreArrayWrite_MPIDenseCUDA);
    1734:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAPlaceArray_C",                              MatDenseCUDAPlaceArray_MPIDenseCUDA);
    1735:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAResetArray_C",                              MatDenseCUDAResetArray_MPIDenseCUDA);
    1736:   PetscObjectComposeFunction((PetscObject)B,"MatDenseCUDAReplaceArray_C",                            MatDenseCUDAReplaceArray_MPIDenseCUDA);
    1737:   m    = (Mat_MPIDense*)(B->data);
    1738:   if (m->A) {
    1739:     MatConvert(m->A,MATSEQDENSECUDA,MAT_INPLACE_MATRIX,&m->A);
    1740:     MatSetUpMultiply_MPIDense(B);
    1741:     B->offloadmask = PETSC_OFFLOAD_BOTH;
    1742:   } else {
    1743:     B->offloadmask = PETSC_OFFLOAD_UNALLOCATED;
    1744:   }
    1745:   MatBindToCPU_MPIDenseCUDA(B,PETSC_FALSE);

    1747:   B->ops->bindtocpu = MatBindToCPU_MPIDenseCUDA;
    1748:   return(0);
    1749: }
    1750: #endif

    1752: PetscErrorCode MatDenseGetColumnVec_MPIDense(Mat A,PetscInt col,Vec *v)
    1753: {
    1754:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;
    1756:   PetscInt       lda;

    1759:   if (a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1760:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1761:   if (!a->cvec) {
    1762:     VecCreateMPIWithArray(PetscObjectComm((PetscObject)A),A->rmap->bs,A->rmap->n,A->rmap->N,NULL,&a->cvec);
    1763:   }
    1764:   a->vecinuse = col + 1;
    1765:   MatDenseGetLDA(a->A,&lda);
    1766:   MatDenseGetArray(a->A,(PetscScalar**)&a->ptrinuse);
    1767:   VecPlaceArray(a->cvec,a->ptrinuse + (size_t)col * (size_t)lda);
    1768:   *v   = a->cvec;
    1769:   return(0);
    1770: }

    1772: PetscErrorCode MatDenseRestoreColumnVec_MPIDense(Mat A,PetscInt col,Vec *v)
    1773: {
    1774:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    1778:   if (!a->vecinuse) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Need to call MatDenseGetColumnVec() first");
    1779:   if (!a->cvec) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing internal column vector");
    1780:   a->vecinuse = 0;
    1781:   MatDenseRestoreArray(a->A,(PetscScalar**)&a->ptrinuse);
    1782:   VecResetArray(a->cvec);
    1783:   *v   = NULL;
    1784:   return(0);
    1785: }

    1787: PetscErrorCode MatDenseGetColumnVecRead_MPIDense(Mat A,PetscInt col,Vec *v)
    1788: {
    1789:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;
    1791:   PetscInt       lda;

    1794:   if (a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1795:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1796:   if (!a->cvec) {
    1797:     VecCreateMPIWithArray(PetscObjectComm((PetscObject)A),A->rmap->bs,A->rmap->n,A->rmap->N,NULL,&a->cvec);
    1798:   }
    1799:   a->vecinuse = col + 1;
    1800:   MatDenseGetLDA(a->A,&lda);
    1801:   MatDenseGetArrayRead(a->A,&a->ptrinuse);
    1802:   VecPlaceArray(a->cvec,a->ptrinuse + (size_t)col * (size_t)lda);
    1803:   VecLockReadPush(a->cvec);
    1804:   *v   = a->cvec;
    1805:   return(0);
    1806: }

    1808: PetscErrorCode MatDenseRestoreColumnVecRead_MPIDense(Mat A,PetscInt col,Vec *v)
    1809: {
    1810:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    1814:   if (!a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseGetColumnVec() first");
    1815:   if (!a->cvec) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing internal column vector");
    1816:   a->vecinuse = 0;
    1817:   MatDenseRestoreArrayRead(a->A,&a->ptrinuse);
    1818:   VecLockReadPop(a->cvec);
    1819:   VecResetArray(a->cvec);
    1820:   *v   = NULL;
    1821:   return(0);
    1822: }

    1824: PetscErrorCode MatDenseGetColumnVecWrite_MPIDense(Mat A,PetscInt col,Vec *v)
    1825: {
    1826:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;
    1828:   PetscInt       lda;

    1831:   if (a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1832:   if (a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1833:   if (!a->cvec) {
    1834:     VecCreateMPIWithArray(PetscObjectComm((PetscObject)A),A->rmap->bs,A->rmap->n,A->rmap->N,NULL,&a->cvec);
    1835:   }
    1836:   a->vecinuse = col + 1;
    1837:   MatDenseGetLDA(a->A,&lda);
    1838:   MatDenseGetArrayWrite(a->A,(PetscScalar**)&a->ptrinuse);
    1839:   VecPlaceArray(a->cvec,a->ptrinuse + (size_t)col * (size_t)lda);
    1840:   *v   = a->cvec;
    1841:   return(0);
    1842: }

    1844: PetscErrorCode MatDenseRestoreColumnVecWrite_MPIDense(Mat A,PetscInt col,Vec *v)
    1845: {
    1846:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;

    1850:   if (!a->vecinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseGetColumnVec() first");
    1851:   if (!a->cvec) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing internal column vector");
    1852:   a->vecinuse = 0;
    1853:   MatDenseRestoreArrayWrite(a->A,(PetscScalar**)&a->ptrinuse);
    1854:   VecResetArray(a->cvec);
    1855:   *v   = NULL;
    1856:   return(0);
    1857: }

    1859: PetscErrorCode MatDenseGetSubMatrix_MPIDense(Mat A,PetscInt cbegin,PetscInt cend,Mat *v)
    1860: {
    1861:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;
    1862:   Mat_MPIDense   *c;
    1864:   MPI_Comm       comm;
    1865:   PetscBool      setup = PETSC_FALSE;

    1868:   PetscObjectGetComm((PetscObject)A,&comm);
    1869:   if (a->vecinuse) SETERRQ(comm,PETSC_ERR_ORDER,"Need to call MatDenseRestoreColumnVec() first");
    1870:   if (a->matinuse) SETERRQ(comm,PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1871:   if (!a->cmat) {
    1872:     setup = PETSC_TRUE;
    1873:     MatCreate(comm,&a->cmat);
    1874:     PetscLogObjectParent((PetscObject)A,(PetscObject)a->cmat);
    1875:     MatSetType(a->cmat,((PetscObject)A)->type_name);
    1876:     PetscLayoutReference(A->rmap,&a->cmat->rmap);
    1877:     PetscLayoutSetSize(a->cmat->cmap,cend-cbegin);
    1878:     PetscLayoutSetUp(a->cmat->cmap);
    1879:   } else if (cend-cbegin != a->cmat->cmap->N) {
    1880:     setup = PETSC_TRUE;
    1881:     PetscLayoutDestroy(&a->cmat->cmap);
    1882:     PetscLayoutCreate(comm,&a->cmat->cmap);
    1883:     PetscLayoutSetSize(a->cmat->cmap,cend-cbegin);
    1884:     PetscLayoutSetUp(a->cmat->cmap);
    1885:   }
    1886:   c = (Mat_MPIDense*)a->cmat->data;
    1887:   if (c->A) SETERRQ(comm,PETSC_ERR_ORDER,"Need to call MatDenseRestoreSubMatrix() first");
    1888:   MatDenseGetSubMatrix(a->A,cbegin,cend,&c->A);
    1889:   if (setup) { /* do we really need this? */
    1890:     MatSetUpMultiply_MPIDense(a->cmat);
    1891:   }
    1892:   a->cmat->preallocated = PETSC_TRUE;
    1893:   a->cmat->assembled = PETSC_TRUE;
    1894:   a->matinuse = cbegin + 1;
    1895:   *v = a->cmat;
    1896:   return(0);
    1897: }

    1899: PetscErrorCode MatDenseRestoreSubMatrix_MPIDense(Mat A,Mat *v)
    1900: {
    1901:   Mat_MPIDense   *a = (Mat_MPIDense*)A->data;
    1902:   Mat_MPIDense   *c;

    1906:   if (!a->matinuse) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to call MatDenseGetSubMatrix() first");
    1907:   if (!a->cmat) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing internal matrix");
    1908:   if (*v != a->cmat) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Not the matrix obtained from MatDenseGetSubMatrix()");
    1909:   a->matinuse = 0;
    1910:   c    = (Mat_MPIDense*)a->cmat->data;
    1911:   MatDenseRestoreSubMatrix(a->A,&c->A);
    1912:   *v   = NULL;
    1913:   return(0);
    1914: }

    1916: /*MC
    1917:    MATMPIDENSE - MATMPIDENSE = "mpidense" - A matrix type to be used for distributed dense matrices.

    1919:    Options Database Keys:
    1920: . -mat_type mpidense - sets the matrix type to "mpidense" during a call to MatSetFromOptions()

    1922:   Level: beginner

    1924: .seealso: MatCreateDense()

    1926: M*/
    1927: PETSC_EXTERN PetscErrorCode MatCreate_MPIDense(Mat mat)
    1928: {
    1929:   Mat_MPIDense   *a;

    1933:   PetscNewLog(mat,&a);
    1934:   mat->data = (void*)a;
    1935:   PetscMemcpy(mat->ops,&MatOps_Values,sizeof(struct _MatOps));

    1937:   mat->insertmode = NOT_SET_VALUES;

    1939:   /* build cache for off array entries formed */
    1940:   a->donotstash = PETSC_FALSE;

    1942:   MatStashCreate_Private(PetscObjectComm((PetscObject)mat),1,&mat->stash);

    1944:   /* stuff used for matrix vector multiply */
    1945:   a->lvec        = NULL;
    1946:   a->Mvctx       = NULL;
    1947:   a->roworiented = PETSC_TRUE;

    1949:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetLDA_C",MatDenseGetLDA_MPIDense);
    1950:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseSetLDA_C",MatDenseSetLDA_MPIDense);
    1951:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetArray_C",MatDenseGetArray_MPIDense);
    1952:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreArray_C",MatDenseRestoreArray_MPIDense);
    1953:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetArrayRead_C",MatDenseGetArrayRead_MPIDense);
    1954:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreArrayRead_C",MatDenseRestoreArrayRead_MPIDense);
    1955:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetArrayWrite_C",MatDenseGetArrayWrite_MPIDense);
    1956:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreArrayWrite_C",MatDenseRestoreArrayWrite_MPIDense);
    1957:   PetscObjectComposeFunction((PetscObject)mat,"MatDensePlaceArray_C",MatDensePlaceArray_MPIDense);
    1958:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseResetArray_C",MatDenseResetArray_MPIDense);
    1959:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseReplaceArray_C",MatDenseReplaceArray_MPIDense);
    1960:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVec_C",MatDenseGetColumnVec_MPIDense);
    1961:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVec_C",MatDenseRestoreColumnVec_MPIDense);
    1962:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVecRead_C",MatDenseGetColumnVecRead_MPIDense);
    1963:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVecRead_C",MatDenseRestoreColumnVecRead_MPIDense);
    1964:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumnVecWrite_C",MatDenseGetColumnVecWrite_MPIDense);
    1965:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumnVecWrite_C",MatDenseRestoreColumnVecWrite_MPIDense);
    1966:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetSubMatrix_C",MatDenseGetSubMatrix_MPIDense);
    1967:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreSubMatrix_C",MatDenseRestoreSubMatrix_MPIDense);
    1968:   PetscObjectComposeFunction((PetscObject)mat,"MatConvert_mpiaij_mpidense_C",MatConvert_MPIAIJ_MPIDense);
    1969:   PetscObjectComposeFunction((PetscObject)mat,"MatConvert_mpidense_mpiaij_C",MatConvert_MPIDense_MPIAIJ);
    1970: #if defined(PETSC_HAVE_ELEMENTAL)
    1971:   PetscObjectComposeFunction((PetscObject)mat,"MatConvert_mpidense_elemental_C",MatConvert_MPIDense_Elemental);
    1972: #endif
    1973: #if defined(PETSC_HAVE_SCALAPACK)
    1974:   PetscObjectComposeFunction((PetscObject)mat,"MatConvert_mpidense_scalapack_C",MatConvert_Dense_ScaLAPACK);
    1975: #endif
    1976: #if defined(PETSC_HAVE_CUDA)
    1977:   PetscObjectComposeFunction((PetscObject)mat,"MatConvert_mpidense_mpidensecuda_C",MatConvert_MPIDense_MPIDenseCUDA);
    1978: #endif
    1979:   PetscObjectComposeFunction((PetscObject)mat,"MatMPIDenseSetPreallocation_C",MatMPIDenseSetPreallocation_MPIDense);
    1980:   PetscObjectComposeFunction((PetscObject)mat,"MatProductSetFromOptions_mpiaij_mpidense_C",MatProductSetFromOptions_MPIAIJ_MPIDense);
    1981:   PetscObjectComposeFunction((PetscObject)mat,"MatProductSetFromOptions_mpidense_mpiaij_C",MatProductSetFromOptions_MPIDense_MPIAIJ);
    1982: #if defined(PETSC_HAVE_CUDA)
    1983:   PetscObjectComposeFunction((PetscObject)mat,"MatProductSetFromOptions_mpiaijcusparse_mpidense_C",MatProductSetFromOptions_MPIAIJ_MPIDense);
    1984:   PetscObjectComposeFunction((PetscObject)mat,"MatProductSetFromOptions_mpidense_mpiaijcusparse_C",MatProductSetFromOptions_MPIDense_MPIAIJ);
    1985: #endif

    1987:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseGetColumn_C",MatDenseGetColumn_MPIDense);
    1988:   PetscObjectComposeFunction((PetscObject)mat,"MatDenseRestoreColumn_C",MatDenseRestoreColumn_MPIDense);
    1989:   PetscObjectChangeTypeName((PetscObject)mat,MATMPIDENSE);
    1990:   return(0);
    1991: }

    1993: /*MC
    1994:    MATMPIDENSECUDA - MATMPIDENSECUDA = "mpidensecuda" - A matrix type to be used for distributed dense matrices on GPUs.

    1996:    Options Database Keys:
    1997: . -mat_type mpidensecuda - sets the matrix type to "mpidensecuda" during a call to MatSetFromOptions()

    1999:   Level: beginner

    2001: .seealso:

    2003: M*/
    2004: #if defined(PETSC_HAVE_CUDA)
    2005: PETSC_EXTERN PetscErrorCode MatCreate_MPIDenseCUDA(Mat B)
    2006: {

    2010:   PetscCUDAInitializeCheck();
    2011:   MatCreate_MPIDense(B);
    2012:   MatConvert_MPIDense_MPIDenseCUDA(B,MATMPIDENSECUDA,MAT_INPLACE_MATRIX,&B);
    2013:   return(0);
    2014: }
    2015: #endif

    2017: /*MC
    2018:    MATDENSE - MATDENSE = "dense" - A matrix type to be used for dense matrices.

    2020:    This matrix type is identical to MATSEQDENSE when constructed with a single process communicator,
    2021:    and MATMPIDENSE otherwise.

    2023:    Options Database Keys:
    2024: . -mat_type dense - sets the matrix type to "dense" during a call to MatSetFromOptions()

    2026:   Level: beginner

    2029: .seealso: MATSEQDENSE,MATMPIDENSE,MATDENSECUDA
    2030: M*/

    2032: /*MC
    2033:    MATDENSECUDA - MATDENSECUDA = "densecuda" - A matrix type to be used for dense matrices on GPUs.

    2035:    This matrix type is identical to MATSEQDENSECUDA when constructed with a single process communicator,
    2036:    and MATMPIDENSECUDA otherwise.

    2038:    Options Database Keys:
    2039: . -mat_type densecuda - sets the matrix type to "densecuda" during a call to MatSetFromOptions()

    2041:   Level: beginner

    2043: .seealso: MATSEQDENSECUDA,MATMPIDENSECUDA,MATDENSE
    2044: M*/

    2046: /*@C
    2047:    MatMPIDenseSetPreallocation - Sets the array used to store the matrix entries

    2049:    Collective

    2051:    Input Parameters:
    2052: .  B - the matrix
    2053: -  data - optional location of matrix data.  Set data=NULL for PETSc
    2054:    to control all matrix memory allocation.

    2056:    Notes:
    2057:    The dense format is fully compatible with standard Fortran 77
    2058:    storage by columns.

    2060:    The data input variable is intended primarily for Fortran programmers
    2061:    who wish to allocate their own matrix memory space.  Most users should
    2062:    set data=NULL.

    2064:    Level: intermediate

    2066: .seealso: MatCreate(), MatCreateSeqDense(), MatSetValues()
    2067: @*/
    2068: PetscErrorCode  MatMPIDenseSetPreallocation(Mat B,PetscScalar *data)
    2069: {

    2074:   PetscTryMethod(B,"MatMPIDenseSetPreallocation_C",(Mat,PetscScalar*),(B,data));
    2075:   return(0);
    2076: }

    2078: /*@
    2079:    MatDensePlaceArray - Allows one to replace the array in a dense matrix with an
    2080:    array provided by the user. This is useful to avoid copying an array
    2081:    into a matrix

    2083:    Not Collective

    2085:    Input Parameters:
    2086: +  mat - the matrix
    2087: -  array - the array in column major order

    2089:    Notes:
    2090:    You can return to the original array with a call to MatDenseResetArray(). The user is responsible for freeing this array; it will not be
    2091:    freed when the matrix is destroyed.

    2093:    Level: developer

    2095: .seealso: MatDenseGetArray(), MatDenseResetArray(), VecPlaceArray(), VecGetArray(), VecRestoreArray(), VecReplaceArray(), VecResetArray()

    2097: @*/
    2098: PetscErrorCode  MatDensePlaceArray(Mat mat,const PetscScalar *array)
    2099: {

    2104:   PetscUseMethod(mat,"MatDensePlaceArray_C",(Mat,const PetscScalar*),(mat,array));
    2105:   PetscObjectStateIncrease((PetscObject)mat);
    2106: #if defined(PETSC_HAVE_CUDA)
    2107:   mat->offloadmask = PETSC_OFFLOAD_CPU;
    2108: #endif
    2109:   return(0);
    2110: }

    2112: /*@
    2113:    MatDenseResetArray - Resets the matrix array to that it previously had before the call to MatDensePlaceArray()

    2115:    Not Collective

    2117:    Input Parameters:
    2118: .  mat - the matrix

    2120:    Notes:
    2121:    You can only call this after a call to MatDensePlaceArray()

    2123:    Level: developer

    2125: .seealso: MatDenseGetArray(), MatDensePlaceArray(), VecPlaceArray(), VecGetArray(), VecRestoreArray(), VecReplaceArray(), VecResetArray()

    2127: @*/
    2128: PetscErrorCode  MatDenseResetArray(Mat mat)
    2129: {

    2134:   PetscUseMethod(mat,"MatDenseResetArray_C",(Mat),(mat));
    2135:   PetscObjectStateIncrease((PetscObject)mat);
    2136:   return(0);
    2137: }

    2139: /*@
    2140:    MatDenseReplaceArray - Allows one to replace the array in a dense matrix with an
    2141:    array provided by the user. This is useful to avoid copying an array
    2142:    into a matrix

    2144:    Not Collective

    2146:    Input Parameters:
    2147: +  mat - the matrix
    2148: -  array - the array in column major order

    2150:    Notes:
    2151:    The memory passed in MUST be obtained with PetscMalloc() and CANNOT be
    2152:    freed by the user. It will be freed when the matrix is destroyed.

    2154:    Level: developer

    2156: .seealso: MatDenseGetArray(), VecReplaceArray()
    2157: @*/
    2158: PetscErrorCode  MatDenseReplaceArray(Mat mat,const PetscScalar *array)
    2159: {

    2164:   PetscUseMethod(mat,"MatDenseReplaceArray_C",(Mat,const PetscScalar*),(mat,array));
    2165:   PetscObjectStateIncrease((PetscObject)mat);
    2166: #if defined(PETSC_HAVE_CUDA)
    2167:   mat->offloadmask = PETSC_OFFLOAD_CPU;
    2168: #endif
    2169:   return(0);
    2170: }

    2172: #if defined(PETSC_HAVE_CUDA)
    2173: /*@C
    2174:    MatDenseCUDAPlaceArray - Allows one to replace the GPU array in a dense matrix with an
    2175:    array provided by the user. This is useful to avoid copying an array
    2176:    into a matrix

    2178:    Not Collective

    2180:    Input Parameters:
    2181: +  mat - the matrix
    2182: -  array - the array in column major order

    2184:    Notes:
    2185:    You can return to the original array with a call to MatDenseCUDAResetArray(). The user is responsible for freeing this array; it will not be
    2186:    freed when the matrix is destroyed. The array must have been allocated with cudaMalloc().

    2188:    Level: developer

    2190: .seealso: MatDenseCUDAGetArray(), MatDenseCUDAResetArray()
    2191: @*/
    2192: PetscErrorCode  MatDenseCUDAPlaceArray(Mat mat,const PetscScalar *array)
    2193: {

    2198:   PetscUseMethod(mat,"MatDenseCUDAPlaceArray_C",(Mat,const PetscScalar*),(mat,array));
    2199:   PetscObjectStateIncrease((PetscObject)mat);
    2200:   mat->offloadmask = PETSC_OFFLOAD_GPU;
    2201:   return(0);
    2202: }

    2204: /*@C
    2205:    MatDenseCUDAResetArray - Resets the matrix array to that it previously had before the call to MatDenseCUDAPlaceArray()

    2207:    Not Collective

    2209:    Input Parameters:
    2210: .  mat - the matrix

    2212:    Notes:
    2213:    You can only call this after a call to MatDenseCUDAPlaceArray()

    2215:    Level: developer

    2217: .seealso: MatDenseCUDAGetArray(), MatDenseCUDAPlaceArray()

    2219: @*/
    2220: PetscErrorCode  MatDenseCUDAResetArray(Mat mat)
    2221: {

    2226:   PetscUseMethod(mat,"MatDenseCUDAResetArray_C",(Mat),(mat));
    2227:   PetscObjectStateIncrease((PetscObject)mat);
    2228:   return(0);
    2229: }

    2231: /*@C
    2232:    MatDenseCUDAReplaceArray - Allows one to replace the GPU array in a dense matrix with an
    2233:    array provided by the user. This is useful to avoid copying an array
    2234:    into a matrix

    2236:    Not Collective

    2238:    Input Parameters:
    2239: +  mat - the matrix
    2240: -  array - the array in column major order

    2242:    Notes:
    2243:    This permanently replaces the GPU array and frees the memory associated with the old GPU array.
    2244:    The memory passed in CANNOT be freed by the user. It will be freed
    2245:    when the matrix is destroyed. The array should respect the matrix leading dimension.

    2247:    Level: developer

    2249: .seealso: MatDenseCUDAGetArray(), MatDenseCUDAPlaceArray(), MatDenseCUDAResetArray()
    2250: @*/
    2251: PetscErrorCode  MatDenseCUDAReplaceArray(Mat mat,const PetscScalar *array)
    2252: {

    2257:   PetscUseMethod(mat,"MatDenseCUDAReplaceArray_C",(Mat,const PetscScalar*),(mat,array));
    2258:   PetscObjectStateIncrease((PetscObject)mat);
    2259:   mat->offloadmask = PETSC_OFFLOAD_GPU;
    2260:   return(0);
    2261: }

    2263: /*@C
    2264:    MatDenseCUDAGetArrayWrite - Provides write access to the CUDA buffer inside a dense matrix.

    2266:    Not Collective

    2268:    Input Parameters:
    2269: .  A - the matrix

    2271:    Output Parameters
    2272: .  array - the GPU array in column major order

    2274:    Notes:
    2275:    The data on the GPU may not be updated due to operations done on the CPU. If you need updated data, use MatDenseCUDAGetArray(). The array must be restored with MatDenseCUDARestoreArrayWrite() when no longer needed.

    2277:    Level: developer

    2279: .seealso: MatDenseCUDAGetArray(), MatDenseCUDARestoreArray(), MatDenseCUDARestoreArrayWrite(), MatDenseCUDAGetArrayRead(), MatDenseCUDARestoreArrayRead()
    2280: @*/
    2281: PetscErrorCode MatDenseCUDAGetArrayWrite(Mat A, PetscScalar **a)
    2282: {

    2287:   PetscUseMethod(A,"MatDenseCUDAGetArrayWrite_C",(Mat,PetscScalar**),(A,a));
    2288:   PetscObjectStateIncrease((PetscObject)A);
    2289:   return(0);
    2290: }

    2292: /*@C
    2293:    MatDenseCUDARestoreArrayWrite - Restore write access to the CUDA buffer inside a dense matrix previously obtained with MatDenseCUDAGetArrayWrite().

    2295:    Not Collective

    2297:    Input Parameters:
    2298: +  A - the matrix
    2299: -  array - the GPU array in column major order

    2301:    Notes:

    2303:    Level: developer

    2305: .seealso: MatDenseCUDAGetArray(), MatDenseCUDARestoreArray(), MatDenseCUDAGetArrayWrite(), MatDenseCUDARestoreArrayRead(), MatDenseCUDAGetArrayRead()
    2306: @*/
    2307: PetscErrorCode MatDenseCUDARestoreArrayWrite(Mat A, PetscScalar **a)
    2308: {

    2313:   PetscUseMethod(A,"MatDenseCUDARestoreArrayWrite_C",(Mat,PetscScalar**),(A,a));
    2314:   PetscObjectStateIncrease((PetscObject)A);
    2315:   A->offloadmask = PETSC_OFFLOAD_GPU;
    2316:   return(0);
    2317: }

    2319: /*@C
    2320:    MatDenseCUDAGetArrayRead - Provides read-only access to the CUDA buffer inside a dense matrix. The array must be restored with MatDenseCUDARestoreArrayRead() when no longer needed.

    2322:    Not Collective

    2324:    Input Parameters:
    2325: .  A - the matrix

    2327:    Output Parameters
    2328: .  array - the GPU array in column major order

    2330:    Notes:
    2331:    Data can be copied to the GPU due to operations done on the CPU. If you need write only access, use MatDenseCUDAGetArrayWrite().

    2333:    Level: developer

    2335: .seealso: MatDenseCUDAGetArray(), MatDenseCUDARestoreArray(), MatDenseCUDARestoreArrayWrite(), MatDenseCUDAGetArrayWrite(), MatDenseCUDARestoreArrayRead()
    2336: @*/
    2337: PetscErrorCode MatDenseCUDAGetArrayRead(Mat A, const PetscScalar **a)
    2338: {

    2343:   PetscUseMethod(A,"MatDenseCUDAGetArrayRead_C",(Mat,const PetscScalar**),(A,a));
    2344:   return(0);
    2345: }

    2347: /*@C
    2348:    MatDenseCUDARestoreArrayRead - Restore read-only access to the CUDA buffer inside a dense matrix previously obtained with a call to MatDenseCUDAGetArrayRead().

    2350:    Not Collective

    2352:    Input Parameters:
    2353: +  A - the matrix
    2354: -  array - the GPU array in column major order

    2356:    Notes:
    2357:    Data can be copied to the GPU due to operations done on the CPU. If you need write only access, use MatDenseCUDAGetArrayWrite().

    2359:    Level: developer

    2361: .seealso: MatDenseCUDAGetArray(), MatDenseCUDARestoreArray(), MatDenseCUDARestoreArrayWrite(), MatDenseCUDAGetArrayWrite(), MatDenseCUDAGetArrayRead()
    2362: @*/
    2363: PetscErrorCode MatDenseCUDARestoreArrayRead(Mat A, const PetscScalar **a)
    2364: {

    2368:   PetscUseMethod(A,"MatDenseCUDARestoreArrayRead_C",(Mat,const PetscScalar**),(A,a));
    2369:   return(0);
    2370: }

    2372: /*@C
    2373:    MatDenseCUDAGetArray - Provides access to the CUDA buffer inside a dense matrix. The array must be restored with MatDenseCUDARestoreArray() when no longer needed.

    2375:    Not Collective

    2377:    Input Parameters:
    2378: .  A - the matrix

    2380:    Output Parameters
    2381: .  array - the GPU array in column major order

    2383:    Notes:
    2384:    Data can be copied to the GPU due to operations done on the CPU. If you need write only access, use MatDenseCUDAGetArrayWrite(). For read-only access, use MatDenseCUDAGetArrayRead().

    2386:    Level: developer

    2388: .seealso: MatDenseCUDAGetArrayRead(), MatDenseCUDARestoreArray(), MatDenseCUDARestoreArrayWrite(), MatDenseCUDAGetArrayWrite(), MatDenseCUDARestoreArrayRead()
    2389: @*/
    2390: PetscErrorCode MatDenseCUDAGetArray(Mat A, PetscScalar **a)
    2391: {

    2396:   PetscUseMethod(A,"MatDenseCUDAGetArray_C",(Mat,PetscScalar**),(A,a));
    2397:   PetscObjectStateIncrease((PetscObject)A);
    2398:   return(0);
    2399: }

    2401: /*@C
    2402:    MatDenseCUDARestoreArray - Restore access to the CUDA buffer inside a dense matrix previously obtained with MatDenseCUDAGetArray().

    2404:    Not Collective

    2406:    Input Parameters:
    2407: +  A - the matrix
    2408: -  array - the GPU array in column major order

    2410:    Notes:

    2412:    Level: developer

    2414: .seealso: MatDenseCUDAGetArray(), MatDenseCUDARestoreArrayWrite(), MatDenseCUDAGetArrayWrite(), MatDenseCUDARestoreArrayRead(), MatDenseCUDAGetArrayRead()
    2415: @*/
    2416: PetscErrorCode MatDenseCUDARestoreArray(Mat A, PetscScalar **a)
    2417: {

    2422:   PetscUseMethod(A,"MatDenseCUDARestoreArray_C",(Mat,PetscScalar**),(A,a));
    2423:   PetscObjectStateIncrease((PetscObject)A);
    2424:   A->offloadmask = PETSC_OFFLOAD_GPU;
    2425:   return(0);
    2426: }
    2427: #endif

    2429: /*@C
    2430:    MatCreateDense - Creates a matrix in dense format.

    2432:    Collective

    2434:    Input Parameters:
    2435: +  comm - MPI communicator
    2436: .  m - number of local rows (or PETSC_DECIDE to have calculated if M is given)
    2437: .  n - number of local columns (or PETSC_DECIDE to have calculated if N is given)
    2438: .  M - number of global rows (or PETSC_DECIDE to have calculated if m is given)
    2439: .  N - number of global columns (or PETSC_DECIDE to have calculated if n is given)
    2440: -  data - optional location of matrix data.  Set data=NULL (PETSC_NULL_SCALAR for Fortran users) for PETSc
    2441:    to control all matrix memory allocation.

    2443:    Output Parameter:
    2444: .  A - the matrix

    2446:    Notes:
    2447:    The dense format is fully compatible with standard Fortran 77
    2448:    storage by columns.
    2449:    Note that, although local portions of the matrix are stored in column-major
    2450:    order, the matrix is partitioned across MPI ranks by row.

    2452:    The data input variable is intended primarily for Fortran programmers
    2453:    who wish to allocate their own matrix memory space.  Most users should
    2454:    set data=NULL (PETSC_NULL_SCALAR for Fortran users).

    2456:    The user MUST specify either the local or global matrix dimensions
    2457:    (possibly both).

    2459:    Level: intermediate

    2461: .seealso: MatCreate(), MatCreateSeqDense(), MatSetValues()
    2462: @*/
    2463: PetscErrorCode  MatCreateDense(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,PetscScalar *data,Mat *A)
    2464: {
    2466:   PetscMPIInt    size;

    2469:   MatCreate(comm,A);
    2470:   MatSetSizes(*A,m,n,M,N);
    2471:   MPI_Comm_size(comm,&size);
    2472:   if (size > 1) {
    2473:     PetscBool havedata = (PetscBool)!!data;

    2475:     MatSetType(*A,MATMPIDENSE);
    2476:     MatMPIDenseSetPreallocation(*A,data);
    2477:     MPIU_Allreduce(MPI_IN_PLACE,&havedata,1,MPIU_BOOL,MPI_LOR,comm);
    2478:     if (havedata) {  /* user provided data array, so no need to assemble */
    2479:       MatSetUpMultiply_MPIDense(*A);
    2480:       (*A)->assembled = PETSC_TRUE;
    2481:     }
    2482:   } else {
    2483:     MatSetType(*A,MATSEQDENSE);
    2484:     MatSeqDenseSetPreallocation(*A,data);
    2485:   }
    2486:   return(0);
    2487: }

    2489: #if defined(PETSC_HAVE_CUDA)
    2490: /*@C
    2491:    MatCreateDenseCUDA - Creates a matrix in dense format using CUDA.

    2493:    Collective

    2495:    Input Parameters:
    2496: +  comm - MPI communicator
    2497: .  m - number of local rows (or PETSC_DECIDE to have calculated if M is given)
    2498: .  n - number of local columns (or PETSC_DECIDE to have calculated if N is given)
    2499: .  M - number of global rows (or PETSC_DECIDE to have calculated if m is given)
    2500: .  N - number of global columns (or PETSC_DECIDE to have calculated if n is given)
    2501: -  data - optional location of GPU matrix data.  Set data=NULL for PETSc
    2502:    to control matrix memory allocation.

    2504:    Output Parameter:
    2505: .  A - the matrix

    2507:    Notes:

    2509:    Level: intermediate

    2511: .seealso: MatCreate(), MatCreateDense()
    2512: @*/
    2513: PetscErrorCode  MatCreateDenseCUDA(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,PetscScalar *data,Mat *A)
    2514: {
    2516:   PetscMPIInt    size;

    2519:   MatCreate(comm,A);
    2521:   MatSetSizes(*A,m,n,M,N);
    2522:   MPI_Comm_size(comm,&size);
    2523:   if (size > 1) {
    2524:     MatSetType(*A,MATMPIDENSECUDA);
    2525:     MatMPIDenseCUDASetPreallocation(*A,data);
    2526:     if (data) {  /* user provided data array, so no need to assemble */
    2527:       MatSetUpMultiply_MPIDense(*A);
    2528:       (*A)->assembled = PETSC_TRUE;
    2529:     }
    2530:   } else {
    2531:     MatSetType(*A,MATSEQDENSECUDA);
    2532:     MatSeqDenseCUDASetPreallocation(*A,data);
    2533:   }
    2534:   return(0);
    2535: }
    2536: #endif

    2538: static PetscErrorCode MatDuplicate_MPIDense(Mat A,MatDuplicateOption cpvalues,Mat *newmat)
    2539: {
    2540:   Mat            mat;
    2541:   Mat_MPIDense   *a,*oldmat = (Mat_MPIDense*)A->data;

    2545:   *newmat = NULL;
    2546:   MatCreate(PetscObjectComm((PetscObject)A),&mat);
    2547:   MatSetSizes(mat,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
    2548:   MatSetType(mat,((PetscObject)A)->type_name);
    2549:   a       = (Mat_MPIDense*)mat->data;

    2551:   mat->factortype   = A->factortype;
    2552:   mat->assembled    = PETSC_TRUE;
    2553:   mat->preallocated = PETSC_TRUE;

    2555:   mat->insertmode = NOT_SET_VALUES;
    2556:   a->donotstash   = oldmat->donotstash;

    2558:   PetscLayoutReference(A->rmap,&mat->rmap);
    2559:   PetscLayoutReference(A->cmap,&mat->cmap);

    2561:   MatDuplicate(oldmat->A,cpvalues,&a->A);
    2562:   PetscLogObjectParent((PetscObject)mat,(PetscObject)a->A);
    2563:   MatSetUpMultiply_MPIDense(mat);

    2565:   *newmat = mat;
    2566:   return(0);
    2567: }

    2569: PetscErrorCode MatLoad_MPIDense(Mat newMat, PetscViewer viewer)
    2570: {
    2572:   PetscBool      isbinary;
    2573: #if defined(PETSC_HAVE_HDF5)
    2574:   PetscBool      ishdf5;
    2575: #endif

    2580:   /* force binary viewer to load .info file if it has not yet done so */
    2581:   PetscViewerSetUp(viewer);
    2582:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
    2583: #if defined(PETSC_HAVE_HDF5)
    2584:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,  &ishdf5);
    2585: #endif
    2586:   if (isbinary) {
    2587:     MatLoad_Dense_Binary(newMat,viewer);
    2588: #if defined(PETSC_HAVE_HDF5)
    2589:   } else if (ishdf5) {
    2590:     MatLoad_Dense_HDF5(newMat,viewer);
    2591: #endif
    2592:   } else SETERRQ2(PetscObjectComm((PetscObject)newMat),PETSC_ERR_SUP,"Viewer type %s not yet supported for reading %s matrices",((PetscObject)viewer)->type_name,((PetscObject)newMat)->type_name);
    2593:   return(0);
    2594: }

    2596: static PetscErrorCode MatEqual_MPIDense(Mat A,Mat B,PetscBool  *flag)
    2597: {
    2598:   Mat_MPIDense   *matB = (Mat_MPIDense*)B->data,*matA = (Mat_MPIDense*)A->data;
    2599:   Mat            a,b;
    2600:   PetscBool      flg;

    2604:   a    = matA->A;
    2605:   b    = matB->A;
    2606:   MatEqual(a,b,&flg);
    2607:   MPIU_Allreduce(&flg,flag,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));
    2608:   return(0);
    2609: }

    2611: PetscErrorCode MatDestroy_MatTransMatMult_MPIDense_MPIDense(void *data)
    2612: {
    2613:   PetscErrorCode        ierr;
    2614:   Mat_TransMatMultDense *atb = (Mat_TransMatMultDense *)data;

    2617:   PetscFree2(atb->sendbuf,atb->recvcounts);
    2618:   MatDestroy(&atb->atb);
    2619:   PetscFree(atb);
    2620:   return(0);
    2621: }

    2623: PetscErrorCode MatDestroy_MatMatTransMult_MPIDense_MPIDense(void *data)
    2624: {
    2625:   PetscErrorCode        ierr;
    2626:   Mat_MatTransMultDense *abt = (Mat_MatTransMultDense *)data;

    2629:   PetscFree2(abt->buf[0],abt->buf[1]);
    2630:   PetscFree2(abt->recvcounts,abt->recvdispls);
    2631:   PetscFree(abt);
    2632:   return(0);
    2633: }

    2635: static PetscErrorCode MatTransposeMatMultNumeric_MPIDense_MPIDense(Mat A,Mat B,Mat C)
    2636: {
    2637:   Mat_MPIDense          *a=(Mat_MPIDense*)A->data, *b=(Mat_MPIDense*)B->data, *c=(Mat_MPIDense*)C->data;
    2638:   Mat_TransMatMultDense *atb;
    2639:   PetscErrorCode        ierr;
    2640:   MPI_Comm              comm;
    2641:   PetscMPIInt           size,*recvcounts;
    2642:   PetscScalar           *carray,*sendbuf;
    2643:   const PetscScalar     *atbarray;
    2644:   PetscInt              i,cN=C->cmap->N,cM=C->rmap->N,proc,k,j;
    2645:   const PetscInt        *ranges;

    2648:   MatCheckProduct(C,3);
    2649:   if (!C->product->data) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data empty");
    2650:   atb = (Mat_TransMatMultDense *)C->product->data;
    2651:   recvcounts = atb->recvcounts;
    2652:   sendbuf = atb->sendbuf;

    2654:   PetscObjectGetComm((PetscObject)A,&comm);
    2655:   MPI_Comm_size(comm,&size);

    2657:   /* compute atbarray = aseq^T * bseq */
    2658:   MatTransposeMatMult(a->A,b->A,atb->atb ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX,PETSC_DEFAULT,&atb->atb);

    2660:   MatGetOwnershipRanges(C,&ranges);

    2662:   /* arrange atbarray into sendbuf */
    2663:   MatDenseGetArrayRead(atb->atb,&atbarray);
    2664:   for (proc=0, k=0; proc<size; proc++) {
    2665:     for (j=0; j<cN; j++) {
    2666:       for (i=ranges[proc]; i<ranges[proc+1]; i++) sendbuf[k++] = atbarray[i+j*cM];
    2667:     }
    2668:   }
    2669:   MatDenseRestoreArrayRead(atb->atb,&atbarray);

    2671:   /* sum all atbarray to local values of C */
    2672:   MatDenseGetArrayWrite(c->A,&carray);
    2673:   MPI_Reduce_scatter(sendbuf,carray,recvcounts,MPIU_SCALAR,MPIU_SUM,comm);
    2674:   MatDenseRestoreArrayWrite(c->A,&carray);
    2675:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
    2676:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
    2677:   return(0);
    2678: }

    2680: static PetscErrorCode MatTransposeMatMultSymbolic_MPIDense_MPIDense(Mat A,Mat B,PetscReal fill,Mat C)
    2681: {
    2682:   PetscErrorCode        ierr;
    2683:   MPI_Comm              comm;
    2684:   PetscMPIInt           size;
    2685:   PetscInt              cm=A->cmap->n,cM,cN=B->cmap->N;
    2686:   Mat_TransMatMultDense *atb;
    2687:   PetscBool             cisdense;
    2688:   PetscInt              i;
    2689:   const PetscInt        *ranges;

    2692:   MatCheckProduct(C,3);
    2693:   if (C->product->data) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data not empty");
    2694:   PetscObjectGetComm((PetscObject)A,&comm);
    2695:   if (A->rmap->rstart != B->rmap->rstart || A->rmap->rend != B->rmap->rend) {
    2696:     SETERRQ4(comm,PETSC_ERR_ARG_SIZ,"Matrix local dimensions are incompatible, A (%D, %D) != B (%D,%D)",A->rmap->rstart,A->rmap->rend,B->rmap->rstart,B->rmap->rend);
    2697:   }

    2699:   /* create matrix product C */
    2700:   MatSetSizes(C,cm,B->cmap->n,A->cmap->N,B->cmap->N);
    2701:   PetscObjectTypeCompareAny((PetscObject)C,&cisdense,MATMPIDENSE,MATMPIDENSECUDA,"");
    2702:   if (!cisdense) {
    2703:     MatSetType(C,((PetscObject)A)->type_name);
    2704:   }
    2705:   MatSetUp(C);

    2707:   /* create data structure for reuse C */
    2708:   MPI_Comm_size(comm,&size);
    2709:   PetscNew(&atb);
    2710:   cM   = C->rmap->N;
    2711:   PetscMalloc2((size_t)cM*(size_t)cN,&atb->sendbuf,size,&atb->recvcounts);
    2712:   MatGetOwnershipRanges(C,&ranges);
    2713:   for (i=0; i<size; i++) atb->recvcounts[i] = (ranges[i+1] - ranges[i])*cN;

    2715:   C->product->data    = atb;
    2716:   C->product->destroy = MatDestroy_MatTransMatMult_MPIDense_MPIDense;
    2717:   return(0);
    2718: }

    2720: static PetscErrorCode MatMatTransposeMultSymbolic_MPIDense_MPIDense(Mat A, Mat B, PetscReal fill, Mat C)
    2721: {
    2722:   PetscErrorCode        ierr;
    2723:   MPI_Comm              comm;
    2724:   PetscMPIInt           i, size;
    2725:   PetscInt              maxRows, bufsiz;
    2726:   PetscMPIInt           tag;
    2727:   PetscInt              alg;
    2728:   Mat_MatTransMultDense *abt;
    2729:   Mat_Product           *product = C->product;
    2730:   PetscBool             flg;

    2733:   MatCheckProduct(C,4);
    2734:   if (C->product->data) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data not empty");
    2735:   /* check local size of A and B */
    2736:   if (A->cmap->n != B->cmap->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Matrix local column dimensions are incompatible, A (%D) != B (%D)",A->cmap->n,B->cmap->n);

    2738:   PetscStrcmp(product->alg,"allgatherv",&flg);
    2739:   alg  = flg ? 0 : 1;

    2741:   /* setup matrix product C */
    2742:   MatSetSizes(C,A->rmap->n,B->rmap->n,A->rmap->N,B->rmap->N);
    2743:   MatSetType(C,MATMPIDENSE);
    2744:   MatSetUp(C);
    2745:   PetscObjectGetNewTag((PetscObject)C,&tag);

    2747:   /* create data structure for reuse C */
    2748:   PetscObjectGetComm((PetscObject)C,&comm);
    2749:   MPI_Comm_size(comm,&size);
    2750:   PetscNew(&abt);
    2751:   abt->tag = tag;
    2752:   abt->alg = alg;
    2753:   switch (alg) {
    2754:   case 1: /* alg: "cyclic" */
    2755:     for (maxRows = 0, i = 0; i < size; i++) maxRows = PetscMax(maxRows, (B->rmap->range[i + 1] - B->rmap->range[i]));
    2756:     bufsiz = A->cmap->N * maxRows;
    2757:     PetscMalloc2(bufsiz,&(abt->buf[0]),bufsiz,&(abt->buf[1]));
    2758:     break;
    2759:   default: /* alg: "allgatherv" */
    2760:     PetscMalloc2(B->rmap->n * B->cmap->N, &(abt->buf[0]), B->rmap->N * B->cmap->N, &(abt->buf[1]));
    2761:     PetscMalloc2(size,&(abt->recvcounts),size+1,&(abt->recvdispls));
    2762:     for (i = 0; i <= size; i++) abt->recvdispls[i] = B->rmap->range[i] * A->cmap->N;
    2763:     for (i = 0; i < size; i++) abt->recvcounts[i] = abt->recvdispls[i + 1] - abt->recvdispls[i];
    2764:     break;
    2765:   }

    2767:   C->product->data    = abt;
    2768:   C->product->destroy = MatDestroy_MatMatTransMult_MPIDense_MPIDense;
    2769:   C->ops->mattransposemultnumeric = MatMatTransposeMultNumeric_MPIDense_MPIDense;
    2770:   return(0);
    2771: }

    2773: static PetscErrorCode MatMatTransposeMultNumeric_MPIDense_MPIDense_Cyclic(Mat A, Mat B, Mat C)
    2774: {
    2775:   Mat_MPIDense          *a=(Mat_MPIDense*)A->data, *b=(Mat_MPIDense*)B->data, *c=(Mat_MPIDense*)C->data;
    2776:   Mat_MatTransMultDense *abt;
    2777:   PetscErrorCode        ierr;
    2778:   MPI_Comm              comm;
    2779:   PetscMPIInt           rank,size, sendsiz, recvsiz, sendto, recvfrom, recvisfrom;
    2780:   PetscScalar           *sendbuf, *recvbuf=NULL, *cv;
    2781:   PetscInt              i,cK=A->cmap->N,k,j,bn;
    2782:   PetscScalar           _DOne=1.0,_DZero=0.0;
    2783:   const PetscScalar     *av,*bv;
    2784:   PetscBLASInt          cm, cn, ck, alda, blda = 0, clda;
    2785:   MPI_Request           reqs[2];
    2786:   const PetscInt        *ranges;

    2789:   MatCheckProduct(C,3);
    2790:   if (!C->product->data) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data empty");
    2791:   abt  = (Mat_MatTransMultDense*)C->product->data;
    2792:   PetscObjectGetComm((PetscObject)C,&comm);
    2793:   MPI_Comm_rank(comm,&rank);
    2794:   MPI_Comm_size(comm,&size);
    2795:   MatDenseGetArrayRead(a->A,&av);
    2796:   MatDenseGetArrayRead(b->A,&bv);
    2797:   MatDenseGetArrayWrite(c->A,&cv);
    2798:   MatDenseGetLDA(a->A,&i);
    2799:   PetscBLASIntCast(i,&alda);
    2800:   MatDenseGetLDA(b->A,&i);
    2801:   PetscBLASIntCast(i,&blda);
    2802:   MatDenseGetLDA(c->A,&i);
    2803:   PetscBLASIntCast(i,&clda);
    2804:   MatGetOwnershipRanges(B,&ranges);
    2805:   bn   = B->rmap->n;
    2806:   if (blda == bn) {
    2807:     sendbuf = (PetscScalar*)bv;
    2808:   } else {
    2809:     sendbuf = abt->buf[0];
    2810:     for (k = 0, i = 0; i < cK; i++) {
    2811:       for (j = 0; j < bn; j++, k++) {
    2812:         sendbuf[k] = bv[i * blda + j];
    2813:       }
    2814:     }
    2815:   }
    2816:   if (size > 1) {
    2817:     sendto = (rank + size - 1) % size;
    2818:     recvfrom = (rank + size + 1) % size;
    2819:   } else {
    2820:     sendto = recvfrom = 0;
    2821:   }
    2822:   PetscBLASIntCast(cK,&ck);
    2823:   PetscBLASIntCast(c->A->rmap->n,&cm);
    2824:   recvisfrom = rank;
    2825:   for (i = 0; i < size; i++) {
    2826:     /* we have finished receiving in sending, bufs can be read/modified */
    2827:     PetscInt nextrecvisfrom = (recvisfrom + 1) % size; /* which process the next recvbuf will originate on */
    2828:     PetscInt nextbn = ranges[nextrecvisfrom + 1] - ranges[nextrecvisfrom];

    2830:     if (nextrecvisfrom != rank) {
    2831:       /* start the cyclic sends from sendbuf, to recvbuf (which will switch to sendbuf) */
    2832:       sendsiz = cK * bn;
    2833:       recvsiz = cK * nextbn;
    2834:       recvbuf = (i & 1) ? abt->buf[0] : abt->buf[1];
    2835:       MPI_Isend(sendbuf, sendsiz, MPIU_SCALAR, sendto, abt->tag, comm, &reqs[0]);
    2836:       MPI_Irecv(recvbuf, recvsiz, MPIU_SCALAR, recvfrom, abt->tag, comm, &reqs[1]);
    2837:     }

    2839:     /* local aseq * sendbuf^T */
    2840:     PetscBLASIntCast(ranges[recvisfrom + 1] - ranges[recvisfrom], &cn);
    2841:     if (cm && cn && ck) PetscStackCallBLAS("BLASgemm",BLASgemm_("N","T",&cm,&cn,&ck,&_DOne,av,&alda,sendbuf,&cn,&_DZero,cv + clda * ranges[recvisfrom],&clda));

    2843:     if (nextrecvisfrom != rank) {
    2844:       /* wait for the sends and receives to complete, swap sendbuf and recvbuf */
    2845:       MPI_Waitall(2, reqs, MPI_STATUSES_IGNORE);
    2846:     }
    2847:     bn = nextbn;
    2848:     recvisfrom = nextrecvisfrom;
    2849:     sendbuf = recvbuf;
    2850:   }
    2851:   MatDenseRestoreArrayRead(a->A,&av);
    2852:   MatDenseRestoreArrayRead(b->A,&bv);
    2853:   MatDenseRestoreArrayWrite(c->A,&cv);
    2854:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
    2855:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
    2856:   return(0);
    2857: }

    2859: static PetscErrorCode MatMatTransposeMultNumeric_MPIDense_MPIDense_Allgatherv(Mat A, Mat B, Mat C)
    2860: {
    2861:   Mat_MPIDense          *a=(Mat_MPIDense*)A->data, *b=(Mat_MPIDense*)B->data, *c=(Mat_MPIDense*)C->data;
    2862:   Mat_MatTransMultDense *abt;
    2863:   PetscErrorCode        ierr;
    2864:   MPI_Comm              comm;
    2865:   PetscMPIInt           size;
    2866:   PetscScalar           *cv, *sendbuf, *recvbuf;
    2867:   const PetscScalar     *av,*bv;
    2868:   PetscInt              blda,i,cK=A->cmap->N,k,j,bn;
    2869:   PetscScalar           _DOne=1.0,_DZero=0.0;
    2870:   PetscBLASInt          cm, cn, ck, alda, clda;

    2873:   MatCheckProduct(C,3);
    2874:   if (!C->product->data) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data empty");
    2875:   abt  = (Mat_MatTransMultDense*)C->product->data;
    2876:   PetscObjectGetComm((PetscObject)A,&comm);
    2877:   MPI_Comm_size(comm,&size);
    2878:   MatDenseGetArrayRead(a->A,&av);
    2879:   MatDenseGetArrayRead(b->A,&bv);
    2880:   MatDenseGetArrayWrite(c->A,&cv);
    2881:   MatDenseGetLDA(a->A,&i);
    2882:   PetscBLASIntCast(i,&alda);
    2883:   MatDenseGetLDA(b->A,&blda);
    2884:   MatDenseGetLDA(c->A,&i);
    2885:   PetscBLASIntCast(i,&clda);
    2886:   /* copy transpose of B into buf[0] */
    2887:   bn      = B->rmap->n;
    2888:   sendbuf = abt->buf[0];
    2889:   recvbuf = abt->buf[1];
    2890:   for (k = 0, j = 0; j < bn; j++) {
    2891:     for (i = 0; i < cK; i++, k++) {
    2892:       sendbuf[k] = bv[i * blda + j];
    2893:     }
    2894:   }
    2895:   MatDenseRestoreArrayRead(b->A,&bv);
    2896:   MPI_Allgatherv(sendbuf, bn * cK, MPIU_SCALAR, recvbuf, abt->recvcounts, abt->recvdispls, MPIU_SCALAR, comm);
    2897:   PetscBLASIntCast(cK,&ck);
    2898:   PetscBLASIntCast(c->A->rmap->n,&cm);
    2899:   PetscBLASIntCast(c->A->cmap->n,&cn);
    2900:   if (cm && cn && ck) PetscStackCallBLAS("BLASgemm",BLASgemm_("N","N",&cm,&cn,&ck,&_DOne,av,&alda,recvbuf,&ck,&_DZero,cv,&clda));
    2901:   MatDenseRestoreArrayRead(a->A,&av);
    2902:   MatDenseRestoreArrayRead(b->A,&bv);
    2903:   MatDenseRestoreArrayWrite(c->A,&cv);
    2904:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
    2905:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
    2906:   return(0);
    2907: }

    2909: static PetscErrorCode MatMatTransposeMultNumeric_MPIDense_MPIDense(Mat A, Mat B, Mat C)
    2910: {
    2911:   Mat_MatTransMultDense *abt;
    2912:   PetscErrorCode        ierr;

    2915:   MatCheckProduct(C,3);
    2916:   if (!C->product->data) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data empty");
    2917:   abt = (Mat_MatTransMultDense*)C->product->data;
    2918:   switch (abt->alg) {
    2919:   case 1:
    2920:     MatMatTransposeMultNumeric_MPIDense_MPIDense_Cyclic(A, B, C);
    2921:     break;
    2922:   default:
    2923:     MatMatTransposeMultNumeric_MPIDense_MPIDense_Allgatherv(A, B, C);
    2924:     break;
    2925:   }
    2926:   return(0);
    2927: }

    2929: PetscErrorCode MatDestroy_MatMatMult_MPIDense_MPIDense(void *data)
    2930: {
    2931:   PetscErrorCode   ierr;
    2932:   Mat_MatMultDense *ab = (Mat_MatMultDense*)data;

    2935:   MatDestroy(&ab->Ce);
    2936:   MatDestroy(&ab->Ae);
    2937:   MatDestroy(&ab->Be);
    2938:   PetscFree(ab);
    2939:   return(0);
    2940: }

    2942: #if defined(PETSC_HAVE_ELEMENTAL)
    2943: PetscErrorCode MatMatMultNumeric_MPIDense_MPIDense(Mat A,Mat B,Mat C)
    2944: {
    2945:   PetscErrorCode   ierr;
    2946:   Mat_MatMultDense *ab;

    2949:   MatCheckProduct(C,3);
    2950:   if (!C->product->data) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing product data");
    2951:   ab   = (Mat_MatMultDense*)C->product->data;
    2952:   MatConvert_MPIDense_Elemental(A,MATELEMENTAL,MAT_REUSE_MATRIX, &ab->Ae);
    2953:   MatConvert_MPIDense_Elemental(B,MATELEMENTAL,MAT_REUSE_MATRIX, &ab->Be);
    2954:   MatMatMultNumeric_Elemental(ab->Ae,ab->Be,ab->Ce);
    2955:   MatConvert(ab->Ce,MATMPIDENSE,MAT_REUSE_MATRIX,&C);
    2956:   return(0);
    2957: }

    2959: static PetscErrorCode MatMatMultSymbolic_MPIDense_MPIDense(Mat A,Mat B,PetscReal fill,Mat C)
    2960: {
    2961:   PetscErrorCode   ierr;
    2962:   Mat              Ae,Be,Ce;
    2963:   Mat_MatMultDense *ab;

    2966:   MatCheckProduct(C,4);
    2967:   if (C->product->data) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data not empty");
    2968:   /* check local size of A and B */
    2969:   if (A->cmap->rstart != B->rmap->rstart || A->cmap->rend != B->rmap->rend) {
    2970:     SETERRQ4(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Matrix local dimensions are incompatible, A (%D, %D) != B (%D,%D)",A->rmap->rstart,A->rmap->rend,B->rmap->rstart,B->rmap->rend);
    2971:   }

    2973:   /* create elemental matrices Ae and Be */
    2974:   MatCreate(PetscObjectComm((PetscObject)A), &Ae);
    2975:   MatSetSizes(Ae,PETSC_DECIDE,PETSC_DECIDE,A->rmap->N,A->cmap->N);
    2976:   MatSetType(Ae,MATELEMENTAL);
    2977:   MatSetUp(Ae);
    2978:   MatSetOption(Ae,MAT_ROW_ORIENTED,PETSC_FALSE);

    2980:   MatCreate(PetscObjectComm((PetscObject)B), &Be);
    2981:   MatSetSizes(Be,PETSC_DECIDE,PETSC_DECIDE,B->rmap->N,B->cmap->N);
    2982:   MatSetType(Be,MATELEMENTAL);
    2983:   MatSetUp(Be);
    2984:   MatSetOption(Be,MAT_ROW_ORIENTED,PETSC_FALSE);

    2986:   /* compute symbolic Ce = Ae*Be */
    2987:   MatCreate(PetscObjectComm((PetscObject)C),&Ce);
    2988:   MatMatMultSymbolic_Elemental(Ae,Be,fill,Ce);

    2990:   /* setup C */
    2991:   MatSetSizes(C,A->rmap->n,B->cmap->n,PETSC_DECIDE,PETSC_DECIDE);
    2992:   MatSetType(C,MATDENSE);
    2993:   MatSetUp(C);

    2995:   /* create data structure for reuse Cdense */
    2996:   PetscNew(&ab);
    2997:   ab->Ae = Ae;
    2998:   ab->Be = Be;
    2999:   ab->Ce = Ce;

    3001:   C->product->data    = ab;
    3002:   C->product->destroy = MatDestroy_MatMatMult_MPIDense_MPIDense;
    3003:   C->ops->matmultnumeric = MatMatMultNumeric_MPIDense_MPIDense;
    3004:   return(0);
    3005: }
    3006: #endif
    3007: /* ----------------------------------------------- */
    3008: #if defined(PETSC_HAVE_ELEMENTAL)
    3009: static PetscErrorCode MatProductSetFromOptions_MPIDense_AB(Mat C)
    3010: {
    3012:   C->ops->matmultsymbolic = MatMatMultSymbolic_MPIDense_MPIDense;
    3013:   C->ops->productsymbolic = MatProductSymbolic_AB;
    3014:   return(0);
    3015: }
    3016: #endif

    3018: static PetscErrorCode MatProductSetFromOptions_MPIDense_AtB(Mat C)
    3019: {
    3020:   Mat_Product *product = C->product;
    3021:   Mat         A = product->A,B=product->B;

    3024:   if (A->rmap->rstart != B->rmap->rstart || A->rmap->rend != B->rmap->rend)
    3025:     SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Matrix local dimensions are incompatible, (%D, %D) != (%D,%D)",A->rmap->rstart,A->rmap->rend,B->rmap->rstart,B->rmap->rend);
    3026:   C->ops->transposematmultsymbolic = MatTransposeMatMultSymbolic_MPIDense_MPIDense;
    3027:   C->ops->productsymbolic = MatProductSymbolic_AtB;
    3028:   return(0);
    3029: }

    3031: static PetscErrorCode MatProductSetFromOptions_MPIDense_ABt(Mat C)
    3032: {
    3034:   Mat_Product    *product = C->product;
    3035:   const char     *algTypes[2] = {"allgatherv","cyclic"};
    3036:   PetscInt       alg,nalg = 2;
    3037:   PetscBool      flg = PETSC_FALSE;

    3040:   /* Set default algorithm */
    3041:   alg = 0; /* default is allgatherv */
    3042:   PetscStrcmp(product->alg,"default",&flg);
    3043:   if (flg) {
    3044:     MatProductSetAlgorithm(C,(MatProductAlgorithm)algTypes[alg]);
    3045:   }

    3047:   /* Get runtime option */
    3048:   if (product->api_user) {
    3049:     PetscOptionsBegin(PetscObjectComm((PetscObject)C),((PetscObject)C)->prefix,"MatMatTransposeMult","Mat");
    3050:     PetscOptionsEList("-matmattransmult_mpidense_mpidense_via","Algorithmic approach","MatMatTransposeMult",algTypes,nalg,algTypes[alg],&alg,&flg);
    3051:     PetscOptionsEnd();
    3052:   } else {
    3053:     PetscOptionsBegin(PetscObjectComm((PetscObject)C),((PetscObject)C)->prefix,"MatProduct_ABt","Mat");
    3054:     PetscOptionsEList("-matproduct_abt_mpidense_mpidense_via","Algorithmic approach","MatProduct_ABt",algTypes,nalg,algTypes[alg],&alg,&flg);
    3055:     PetscOptionsEnd();
    3056:   }
    3057:   if (flg) {
    3058:     MatProductSetAlgorithm(C,(MatProductAlgorithm)algTypes[alg]);
    3059:   }

    3061:   C->ops->mattransposemultsymbolic = MatMatTransposeMultSymbolic_MPIDense_MPIDense;
    3062:   C->ops->productsymbolic          = MatProductSymbolic_ABt;
    3063:   return(0);
    3064: }

    3066: PETSC_INTERN PetscErrorCode MatProductSetFromOptions_MPIDense(Mat C)
    3067: {
    3069:   Mat_Product    *product = C->product;

    3072:   switch (product->type) {
    3073: #if defined(PETSC_HAVE_ELEMENTAL)
    3074:   case MATPRODUCT_AB:
    3075:     MatProductSetFromOptions_MPIDense_AB(C);
    3076:     break;
    3077: #endif
    3078:   case MATPRODUCT_AtB:
    3079:     MatProductSetFromOptions_MPIDense_AtB(C);
    3080:     break;
    3081:   case MATPRODUCT_ABt:
    3082:     MatProductSetFromOptions_MPIDense_ABt(C);
    3083:     break;
    3084:   default:
    3085:     break;
    3086:   }
    3087:   return(0);
    3088: }