Actual source code: aijcusp.cu
petsc-3.7.1 2016-05-15
Report Typos and Errors

      1: /*
      2:   Defines the basic matrix operations for the AIJ (compressed row)
      3:   matrix storage format.
      4: */
      5: #define PETSC_SKIP_COMPLEX
      6: #define PETSC_SKIP_SPINLOCK

      8: #include <petscconf.h>
      9: #include <../src/mat/impls/aij/seq/aij.h>          /*I "petscmat.h" I*/
     10: #include <petscbt.h>
     11: #include <../src/vec/vec/impls/dvecimpl.h>
     12: #include <petsc/private/vecimpl.h>
     13: #undef VecType
     14: #include <../src/mat/impls/aij/seq/seqcusp/cuspmatimpl.h>
     15: #include <../src/vec/vec/impls/seq/seqcusp/cuspvecimpl.h>

     17: const char *const MatCUSPStorageFormats[] = {"CSR","DIA","ELL","MatCUSPStorageFormat","MAT_CUSP_",0};

     21: PetscErrorCode MatCUSPSetStream(Mat A,const cudaStream_t stream)
     22: {
     23:   Mat_SeqAIJCUSP *cuspstruct = (Mat_SeqAIJCUSP*)A->spptr;

     26:   cuspstruct->stream = stream;
     27:   return(0);
     28: }

     32: PetscErrorCode MatCUSPSetFormat_SeqAIJCUSP(Mat A,MatCUSPFormatOperation op,MatCUSPStorageFormat format)
     33: {
     34:   Mat_SeqAIJCUSP *cuspMat = (Mat_SeqAIJCUSP*)A->spptr;

     37:   switch (op) {
     38:   case MAT_CUSP_MULT:
     39:     cuspMat->format = format;
     40:     break;
     41:   case MAT_CUSP_ALL:
     42:     cuspMat->format = format;
     43:     break;
     44:   default:
     45:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"unsupported operation %d for MatCUSPFormatOperation. Only MAT_CUSP_MULT and MAT_CUSP_ALL are currently supported.",op);
     46:   }
     47:   return(0);
     48: }

     50: /*@
     51:    MatCUSPSetFormat - Sets the storage format of CUSP matrices for a particular
     52:    operation. Only the MatMult operation can use different GPU storage formats
     53:    for AIJCUSP matrices.

     55:    Not Collective

     57:    Input Parameters:
     58: +  A - Matrix of type SEQAIJCUSP
     59: .  op - MatCUSPFormatOperation. SEQAIJCUSP matrices support MAT_CUSP_MULT and MAT_CUSP_ALL. MPIAIJCUSP matrices support MAT_CUSP_MULT_DIAG, MAT_CUSP_MULT_OFFDIAG, and MAT_CUSP_ALL.
     60: -  format - MatCUSPStorageFormat (one of MAT_CUSP_CSR, MAT_CUSP_DIA, MAT_CUSP_ELL)

     62:    Output Parameter:

     64:    Level: intermediate

     66: .seealso: MatCUSPStorageFormat, MatCUSPFormatOperation
     67: @*/
     70: PetscErrorCode MatCUSPSetFormat(Mat A,MatCUSPFormatOperation op,MatCUSPStorageFormat format)
     71: {

     76:   PetscTryMethod(A, "MatCUSPSetFormat_C",(Mat,MatCUSPFormatOperation,MatCUSPStorageFormat),(A,op,format));
     77:   return(0);
     78: }

     82: PetscErrorCode MatSetFromOptions_SeqAIJCUSP(PetscOptionItems *PetscOptionsObject,Mat A)
     83: {
     84:   Mat_SeqAIJCUSP       *cuspMat = (Mat_SeqAIJCUSP*)A->spptr;
     85:   PetscErrorCode       ierr;
     86:   MatCUSPStorageFormat format;
     87:   PetscBool            flg;

     90:   PetscOptionsHead(PetscOptionsObject,"SeqAIJCUSP options");
     91:   PetscObjectOptionsBegin((PetscObject)A);
     92:   PetscOptionsEnum("-mat_cusp_mult_storage_format","sets storage format of (seq)aijcusp gpu matrices for SpMV",
     93:                           "MatCUSPSetFormat",MatCUSPStorageFormats,(PetscEnum)cuspMat->format,(PetscEnum*)&format,&flg);
     94:   if (flg) {
     95:     MatCUSPSetFormat(A,MAT_CUSP_MULT,format);
     96:   }
     97:   PetscOptionsEnum("-mat_cusp_storage_format","sets storage format of (seq)aijcusp gpu matrices for SpMV",
     98:                           "MatCUSPSetFormat",MatCUSPStorageFormats,(PetscEnum)cuspMat->format,(PetscEnum*)&format,&flg);
     99:   if (flg) {
    100:     MatCUSPSetFormat(A,MAT_CUSP_ALL,format);
    101:   }
    102:   PetscOptionsEnd();
    103:   return(0);

    105: }

    110: PetscErrorCode MatCUSPCopyToGPU(Mat A)
    111: {

    113:   Mat_SeqAIJCUSP *cuspstruct = (Mat_SeqAIJCUSP*)A->spptr;
    114:   Mat_SeqAIJ     *a          = (Mat_SeqAIJ*)A->data;
    115:   PetscInt       m           = A->rmap->n,*ii,*ridx;
    116:   CUSPMATRIX     *mat;

    120:   if (A->valid_GPU_matrix == PETSC_CUSP_UNALLOCATED || A->valid_GPU_matrix == PETSC_CUSP_CPU) {
    121:     PetscLogEventBegin(MAT_CUSPCopyToGPU,A,0,0,0);
    122:     /*
    123:       It may be possible to reuse nonzero structure with new matrix values but
    124:       for simplicity and insured correctness we delete and build a new matrix on
    125:       the GPU. Likely a very small performance hit.
    126:     */
    127:     if (cuspstruct->mat) {
    128:       try {
    129:         if (cuspstruct->format==MAT_CUSP_ELL)
    130:           delete (CUSPMATRIXELL *) cuspstruct->mat;
    131:         else if (cuspstruct->format==MAT_CUSP_DIA)
    132:           delete (CUSPMATRIXDIA *) cuspstruct->mat;
    133:         else
    134:           delete (CUSPMATRIX *) cuspstruct->mat;
    135:       } catch(char *ex) {
    136:         SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"CUSP error: %s", ex);
    137:       }
    138:     }
    139:     try {
    140:       cuspstruct->nonzerorow=0;
    141:       for (int j = 0; j<m; j++) cuspstruct->nonzerorow += ((a->i[j+1]-a->i[j])>0);
    142:       if (a->compressedrow.use) {
    143:         m    = a->compressedrow.nrows;
    144:         ii   = a->compressedrow.i;
    145:         ridx = a->compressedrow.rindex;
    146:       } else {
    147:         /* Forcing compressed row on the GPU */
    148:         int k=0;
    149:         PetscMalloc1(cuspstruct->nonzerorow+1, &ii);
    150:         PetscMalloc1(cuspstruct->nonzerorow, &ridx);
    151:         ii[0]=0;
    152:         for (int j = 0; j<m; j++) {
    153:           if ((a->i[j+1]-a->i[j])>0) {
    154:             ii[k]  = a->i[j];
    155:             ridx[k]= j;
    156:             k++;
    157:           }
    158:         }
    159:         ii[cuspstruct->nonzerorow] = a->nz;
    160:         m = cuspstruct->nonzerorow;
    161:       }

    163:       /* now build matrix */
    164:       mat = new CUSPMATRIX;
    165:       mat->resize(m,A->cmap->n,a->nz);
    166:       mat->row_offsets.assign(ii,ii+m+1);
    167:       mat->column_indices.assign(a->j,a->j+a->nz);
    168:       mat->values.assign(a->a,a->a+a->nz);

    170:       /* convert to other formats if selected */
    171:       if (a->compressedrow.use || cuspstruct->format==MAT_CUSP_CSR) {
    172:         cuspstruct->mat = mat;
    173:         cuspstruct->format = MAT_CUSP_CSR;
    174:       } else {
    175:         if (cuspstruct->format==MAT_CUSP_ELL) {
    176:           CUSPMATRIXELL *ellMat = new CUSPMATRIXELL(*mat);
    177:           cuspstruct->mat = ellMat;
    178:         } else {
    179:           CUSPMATRIXDIA *diaMat = new CUSPMATRIXDIA(*mat);
    180:           cuspstruct->mat = diaMat;
    181:         }
    182:         delete (CUSPMATRIX*) mat;
    183:       }

    185:       /* assign the compressed row indices */
    186:       if (cuspstruct->indices) delete (CUSPINTARRAYGPU*)cuspstruct->indices;
    187:       cuspstruct->indices = new CUSPINTARRAYGPU;
    188:       cuspstruct->indices->assign(ridx,ridx+m);

    190:       /* free the temporaries */
    191:       if (!a->compressedrow.use) {
    192:         PetscFree(ii);
    193:         PetscFree(ridx);
    194:       }
    195:       if (cuspstruct->tempvec) delete (CUSPARRAY*)cuspstruct->tempvec;
    196:       cuspstruct->tempvec = new CUSPARRAY;
    197:       cuspstruct->tempvec->resize(m);
    198:     } catch(char *ex) {
    199:       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"CUSP error: %s", ex);
    200:     }
    201:     WaitForGPU();CHKERRCUSP(ierr);

    203:     A->valid_GPU_matrix = PETSC_CUSP_BOTH;

    205:     PetscLogEventEnd(MAT_CUSPCopyToGPU,A,0,0,0);
    206:   }
    207:   return(0);
    208: }

    212: PetscErrorCode MatCUSPCopyFromGPU(Mat A, CUSPMATRIX *Agpu)
    213: {
    214:   Mat_SeqAIJCUSP *cuspstruct = (Mat_SeqAIJCUSP*) A->spptr;
    215:   Mat_SeqAIJ     *a          = (Mat_SeqAIJ*) A->data;
    216:   PetscInt       m           = A->rmap->n;
    217:   CUSPMATRIX *mat;

    221:   /* if the data is stored in non-CSR format, create a temporary */
    222:   if (cuspstruct->format==MAT_CUSP_ELL) {
    223:     mat = new CUSPMATRIX(*((CUSPMATRIXELL*)cuspstruct->mat));
    224:   } else if (cuspstruct->format==MAT_CUSP_DIA) {
    225:     mat = new CUSPMATRIX(*((CUSPMATRIXDIA*)cuspstruct->mat));
    226:   } else {
    227:     mat = (CUSPMATRIX*) cuspstruct->mat;
    228:   }

    230:   if (A->valid_GPU_matrix == PETSC_CUSP_UNALLOCATED) {
    231:     if (A->valid_GPU_matrix == PETSC_CUSP_UNALLOCATED) {
    232:       try {
    233:         mat = Agpu;
    234:         if (a->compressedrow.use) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Cannot handle row compression for GPU matrices");
    235:         else {
    236:           PetscInt i;

    238:           if (m+1 != (PetscInt) mat->row_offsets.size()) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ, "GPU matrix has %d rows, should be %d", mat->row_offsets.size()-1, m);
    239:           a->nz           = mat->values.size();
    240:           a->maxnz        = a->nz; /* Since we allocate exactly the right amount */
    241:           A->preallocated = PETSC_TRUE;
    242:           if (a->singlemalloc) {
    243:             if (a->a) {PetscFree3(a->a,a->j,a->i);}
    244:           } else {
    245:             if (a->i) {PetscFree(a->i);}
    246:             if (a->j) {PetscFree(a->j);}
    247:             if (a->a) {PetscFree(a->a);}
    248:           }
    249:           PetscMalloc3(a->nz,&a->a,a->nz,&a->j,m+1,&a->i);
    250:           PetscLogObjectMemory((PetscObject)A, a->nz*(sizeof(PetscScalar)+sizeof(PetscInt))+(m+1)*sizeof(PetscInt));

    252:           a->singlemalloc = PETSC_TRUE;
    253:           thrust::copy(mat->row_offsets.begin(), mat->row_offsets.end(), a->i);
    254:           thrust::copy(mat->column_indices.begin(), mat->column_indices.end(), a->j);
    255:           thrust::copy(mat->values.begin(), mat->values.end(), a->a);
    256:           /* Setup row lengths */
    257:           if (a->imax) {PetscFree2(a->imax,a->ilen);}
    258:           PetscMalloc2(m,&a->imax,m,&a->ilen);
    259:           PetscLogObjectMemory((PetscObject)A, 2*m*sizeof(PetscInt));
    260:           for (i = 0; i < m; ++i) a->imax[i] = a->ilen[i] = a->i[i+1] - a->i[i];
    261:           /* a->diag?*/
    262:         }
    263:         cuspstruct->tempvec = new CUSPARRAY;
    264:         cuspstruct->tempvec->resize(m);
    265:       } catch(char *ex) {
    266:         SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "CUSP error: %s", ex);
    267:       }
    268:     }
    269:     /* This assembly prevents resetting the flag to PETSC_CUSP_CPU and recopying */
    270:     MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
    271:     MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);

    273:     A->valid_GPU_matrix = PETSC_CUSP_BOTH;

    275:     /* delete the temporary */
    276:     if (cuspstruct->format==MAT_CUSP_ELL || cuspstruct->format==MAT_CUSP_DIA)
    277:       delete (CUSPMATRIX*) mat;
    278:   } else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Only valid for unallocated GPU matrices");
    279:   return(0);
    280: }

    284: PetscErrorCode MatCreateVecs_SeqAIJCUSP(Mat mat, Vec *right, Vec *left)
    285: {
    287:   PetscInt rbs,cbs;

    290:   MatGetBlockSizes(mat,&rbs,&cbs);
    291:   if (right) {
    292:     VecCreate(PetscObjectComm((PetscObject)mat),right);
    293:     VecSetSizes(*right,mat->cmap->n,PETSC_DETERMINE);
    294:     VecSetBlockSize(*right,cbs);
    295:     VecSetType(*right,VECSEQCUSP);
    296:     PetscLayoutReference(mat->cmap,&(*right)->map);
    297:   }
    298:   if (left) {
    299:     VecCreate(PetscObjectComm((PetscObject)mat),left);
    300:     VecSetSizes(*left,mat->rmap->n,PETSC_DETERMINE);
    301:     VecSetBlockSize(*left,rbs);
    302:     VecSetType(*left,VECSEQCUSP);
    303:     PetscLayoutReference(mat->rmap,&(*left)->map);
    304:   }
    305:   return(0);
    306: }

    310: PetscErrorCode MatMult_SeqAIJCUSP(Mat A,Vec xx,Vec yy)
    311: {
    312:   Mat_SeqAIJ       *a = (Mat_SeqAIJ*)A->data;
    313:   PetscErrorCode   ierr;
    314:   Mat_SeqAIJCUSP   *cuspstruct = (Mat_SeqAIJCUSP*)A->spptr;
    315:   PetscBool        usecprow = a->compressedrow.use;
    316:   CUSPARRAY        *xarray=NULL,*yarray=NULL;
    317:   static PetscBool cite = PETSC_FALSE;

    320:   /*
    321:     DM 1/28/2014: As of version 0.4.0 cusp does not handle the case of
    322:     zero matrices well.  It produces segfaults on some platforms.
    323:     Therefore we manually check for the case of a zero matrix here.
    324:   */
    325:   if (a->nz == 0) {
    326:     return(0);
    327:   }
    328:   PetscCitationsRegister("@incollection{msk2013,\n  author = {Victor Minden and Barry F. Smith and Matthew G. Knepley},\n  title = {Preliminary Implementation of {PETSc} Using {GPUs}},\n  booktitle = {GPU Solutions to Multi-scale Problems in Science and Engineering},\n  series = {Lecture Notes in Earth System Sciences},\n  editor = {David A. Yuen and Long Wang and Xuebin Chi and Lennart Johnsson and Wei Ge and Yaolin Shi},\n  publisher = {Springer Berlin Heidelberg},\n  pages = {131--140},\n  year = {2013},\n}\n",&cite);
    329:   VecCUSPGetArrayRead(xx,&xarray);
    330:   VecCUSPGetArrayWrite(yy,&yarray);
    331:   try {
    332:     if (usecprow) {
    333:       /* use compressed row format */
    334:       CUSPMATRIX *mat = (CUSPMATRIX*)cuspstruct->mat;
    335:       cusp::multiply(*mat,*xarray,*cuspstruct->tempvec);
    336:       VecSet_SeqCUSP(yy,0.0);
    337:       thrust::copy(cuspstruct->tempvec->begin(),cuspstruct->tempvec->end(),thrust::make_permutation_iterator(yarray->begin(),cuspstruct->indices->begin()));
    338:     } else {
    339:       /* do not use compressed row format */
    340:       if (cuspstruct->format==MAT_CUSP_ELL) {
    341:         CUSPMATRIXELL *mat = (CUSPMATRIXELL*)cuspstruct->mat;
    342:         cusp::multiply(*mat,*xarray,*yarray);
    343:       } else if (cuspstruct->format==MAT_CUSP_DIA) {
    344:         CUSPMATRIXDIA *mat = (CUSPMATRIXDIA*)cuspstruct->mat;
    345:         cusp::multiply(*mat,*xarray,*yarray);
    346:       } else {
    347:         CUSPMATRIX *mat = (CUSPMATRIX*)cuspstruct->mat;
    348:         cusp::multiply(*mat,*xarray,*yarray);
    349:       }
    350:     }

    352:   } catch (char *ex) {
    353:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"CUSP error: %s", ex);
    354:   }
    355:   VecCUSPRestoreArrayRead(xx,&xarray);
    356:   VecCUSPRestoreArrayWrite(yy,&yarray);
    357:   if (!cuspstruct->stream) {
    358:     WaitForGPU();CHKERRCUSP(ierr);
    359:   }
    360:   PetscLogFlops(2.0*a->nz - cuspstruct->nonzerorow);
    361:   return(0);
    362: }

    365: struct VecCUSPPlusEquals
    366: {
    367:   template <typename Tuple>
    368:   __host__ __device__
    369:   void operator()(Tuple t)
    370:   {
    371:     thrust::get<1>(t) = thrust::get<1>(t) + thrust::get<0>(t);
    372:   }
    373: };

    377: PetscErrorCode MatMultAdd_SeqAIJCUSP(Mat A,Vec xx,Vec yy,Vec zz)
    378: {
    379:   Mat_SeqAIJ     *a = (Mat_SeqAIJ*)A->data;
    381:   PetscBool      usecprow = a->compressedrow.use;
    382:   Mat_SeqAIJCUSP *cuspstruct = (Mat_SeqAIJCUSP*)A->spptr;
    383:   CUSPARRAY      *xarray     = NULL,*yarray=NULL,*zarray=NULL;

    386:   /*
    387:     DM 1/28/2014: As of version 0.4.0 cusp does not handle the case of
    388:     zero matrices well.  It produces segfaults on some platforms.
    389:     Therefore we manually check for the case of a zero matrix here.
    390:   */
    391:   if (a->nz == 0) {
    392:     return(0);
    393:   }
    394:   try {
    395:     VecCopy_SeqCUSP(yy,zz);
    396:     VecCUSPGetArrayRead(xx,&xarray);
    397:     VecCUSPGetArrayRead(yy,&yarray);
    398:     VecCUSPGetArrayWrite(zz,&zarray);

    400:     if (usecprow) {
    401:       /* use compressed row format */
    402:       CUSPMATRIX *mat = (CUSPMATRIX*)cuspstruct->mat;
    403:       cusp::multiply(*mat,*xarray,*cuspstruct->tempvec);
    404:       thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(cuspstruct->tempvec->begin(),
    405:                                                                     thrust::make_permutation_iterator(zarray->begin(), cuspstruct->indices->begin()))),
    406:                        thrust::make_zip_iterator(thrust::make_tuple(cuspstruct->tempvec->end(),
    407:                                                                     thrust::make_permutation_iterator(zarray->end(),cuspstruct->indices->end()))),
    408:                        VecCUSPPlusEquals());
    409:     } else {

    411:       if (cuspstruct->format==MAT_CUSP_ELL) {
    412:         CUSPMATRIXELL *mat = (CUSPMATRIXELL*)cuspstruct->mat;
    413:         cusp::multiply(*mat,*xarray,*cuspstruct->tempvec);
    414:       } else if (cuspstruct->format==MAT_CUSP_DIA) {
    415:         CUSPMATRIXDIA *mat = (CUSPMATRIXDIA*)cuspstruct->mat;
    416:         cusp::multiply(*mat,*xarray,*cuspstruct->tempvec);
    417:       } else {
    418:         CUSPMATRIX *mat = (CUSPMATRIX*)cuspstruct->mat;
    419:         cusp::multiply(*mat,*xarray,*cuspstruct->tempvec);
    420:       }

    422:       if (zarray->size() == cuspstruct->indices->size()) {
    423:         thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(cuspstruct->tempvec->begin(),zarray->begin())),
    424:             thrust::make_zip_iterator(thrust::make_tuple(cuspstruct->tempvec->end(),zarray->end())),
    425:             VecCUSPPlusEquals());
    426:       } else {
    427:         thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(cuspstruct->tempvec->begin(),
    428:                 thrust::make_permutation_iterator(zarray->begin(), cuspstruct->indices->begin()))),
    429:             thrust::make_zip_iterator(thrust::make_tuple(cuspstruct->tempvec->end(),
    430:                 thrust::make_permutation_iterator(zarray->end(),cuspstruct->indices->end()))),
    431:             VecCUSPPlusEquals());
    432:       }
    433:     }
    434:     VecCUSPRestoreArrayRead(xx,&xarray);
    435:     VecCUSPRestoreArrayRead(yy,&yarray);
    436:     VecCUSPRestoreArrayWrite(zz,&zarray);

    438:   } catch(char *ex) {
    439:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"CUSP error: %s", ex);
    440:   }
    441:   WaitForGPU();CHKERRCUSP(ierr);
    442:   PetscLogFlops(2.0*a->nz);
    443:   return(0);
    444: }

    448: PetscErrorCode MatAssemblyEnd_SeqAIJCUSP(Mat A,MatAssemblyType mode)
    449: {

    453:   MatAssemblyEnd_SeqAIJ(A,mode);
    454:   MatCUSPCopyToGPU(A);
    455:   if (mode == MAT_FLUSH_ASSEMBLY) return(0);
    456:   A->ops->mult    = MatMult_SeqAIJCUSP;
    457:   A->ops->multadd = MatMultAdd_SeqAIJCUSP;
    458:   return(0);
    459: }

    461: /* --------------------------------------------------------------------------------*/
    464: /*@
    465:    MatCreateSeqAIJCUSP - Creates a sparse matrix in AIJ (compressed row) format
    466:    (the default parallel PETSc format).  This matrix will ultimately pushed down
    467:    to NVidia GPUs and use the CUSP library for calculations. For good matrix
    468:    assembly performance the user should preallocate the matrix storage by setting
    469:    the parameter nz (or the array nnz).  By setting these parameters accurately,
    470:    performance during matrix assembly can be increased by more than a factor of 50.

    473:    Collective on MPI_Comm

    475:    Input Parameters:
    476: +  comm - MPI communicator, set to PETSC_COMM_SELF
    477: .  m - number of rows
    478: .  n - number of columns
    479: .  nz - number of nonzeros per row (same for all rows)
    480: -  nnz - array containing the number of nonzeros in the various rows
    481:          (possibly different for each row) or NULL

    483:    Output Parameter:
    484: .  A - the matrix

    486:    It is recommended that one use the MatCreate(), MatSetType() and/or MatSetFromOptions(),
    487:    MatXXXXSetPreallocation() paradigm instead of this routine directly.
    488:    [MatXXXXSetPreallocation() is, for example, MatSeqAIJSetPreallocation]

    490:    Notes:
    491:    If nnz is given then nz is ignored

    493:    The AIJ format (also called the Yale sparse matrix format or
    494:    compressed row storage), is fully compatible with standard Fortran 77
    495:    storage.  That is, the stored row and column indices can begin at
    496:    either one (as in Fortran) or zero.  See the users' manual for details.

    498:    Specify the preallocated storage with either nz or nnz (not both).
    499:    Set nz=PETSC_DEFAULT and nnz=NULL for PETSc to control dynamic memory
    500:    allocation.  For large problems you MUST preallocate memory or you
    501:    will get TERRIBLE performance, see the users' manual chapter on matrices.

    503:    By default, this format uses inodes (identical nodes) when possible, to
    504:    improve numerical efficiency of matrix-vector products and solves. We
    505:    search for consecutive rows with the same nonzero structure, thereby
    506:    reusing matrix information to achieve increased efficiency.

    508:    Level: intermediate

    510: .seealso: MatCreate(), MatCreateAIJ(), MatSetValues(), MatSeqAIJSetColumnIndices(), MatCreateSeqAIJWithArrays(), MatCreateAIJ()

    512: @*/
    513: PetscErrorCode  MatCreateSeqAIJCUSP(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt nz,const PetscInt nnz[],Mat *A)
    514: {

    518:   MatCreate(comm,A);
    519:   MatSetSizes(*A,m,n,m,n);
    520:   MatSetType(*A,MATSEQAIJCUSP);
    521:   MatSeqAIJSetPreallocation_SeqAIJ(*A,nz,(PetscInt*)nnz);
    522:   return(0);
    523: }

    527: PetscErrorCode MatDestroy_SeqAIJCUSP(Mat A)
    528: {
    530:   Mat_SeqAIJCUSP *cuspcontainer = (Mat_SeqAIJCUSP*)A->spptr;

    533:   try {
    534:     if (A->valid_GPU_matrix != PETSC_CUSP_UNALLOCATED) {
    535:       if (cuspcontainer->format==MAT_CUSP_ELL) {
    536:         delete (CUSPMATRIXELL*)(cuspcontainer->mat);
    537:       } else if (cuspcontainer->format==MAT_CUSP_DIA) {
    538:         delete (CUSPMATRIXDIA*)(cuspcontainer->mat);
    539:       } else {
    540:         delete (CUSPMATRIX*)(cuspcontainer->mat);
    541:       }
    542:       if (cuspcontainer->indices) delete (CUSPINTARRAYGPU*)cuspcontainer->indices;
    543:       if (cuspcontainer->tempvec) delete (CUSPARRAY*)cuspcontainer->tempvec;
    544:     }
    545:     delete cuspcontainer;
    546:     A->valid_GPU_matrix = PETSC_CUSP_UNALLOCATED;
    547:   } catch(char *ex) {
    548:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"CUSP error: %s", ex);
    549:   }
    550:   /*this next line is because MatDestroy tries to PetscFree spptr if it is not zero, and PetscFree only works if the memory was allocated with PetscNew or PetscMalloc, which don't call the constructor */
    551:   A->spptr = 0;
    552:   MatDestroy_SeqAIJ(A);
    553:   return(0);
    554: }

    556: extern PetscErrorCode MatSetValuesBatch_SeqAIJCUSP(Mat, PetscInt, PetscInt, PetscInt*,const PetscScalar*);

    560: PETSC_EXTERN PetscErrorCode MatCreate_SeqAIJCUSP(Mat B)
    561: {
    563:   Mat_SeqAIJ     *aij;

    566:   MatCreate_SeqAIJ(B);
    567:   aij             = (Mat_SeqAIJ*)B->data;
    568:   aij->inode.use  = PETSC_FALSE;
    569:   B->ops->mult    = MatMult_SeqAIJCUSP;
    570:   B->ops->multadd = MatMultAdd_SeqAIJCUSP;
    571:   B->spptr        = new Mat_SeqAIJCUSP;

    573:   if (B->factortype==MAT_FACTOR_NONE) {
    574:     ((Mat_SeqAIJCUSP*)B->spptr)->mat     = 0;
    575:     ((Mat_SeqAIJCUSP*)B->spptr)->tempvec = 0;
    576:     ((Mat_SeqAIJCUSP*)B->spptr)->indices = 0;
    577:     ((Mat_SeqAIJCUSP*)B->spptr)->nonzerorow = 0;
    578:     ((Mat_SeqAIJCUSP*)B->spptr)->stream = 0;
    579:     ((Mat_SeqAIJCUSP*)B->spptr)->format = MAT_CUSP_CSR;
    580:   }

    582:   B->ops->assemblyend    = MatAssemblyEnd_SeqAIJCUSP;
    583:   B->ops->destroy        = MatDestroy_SeqAIJCUSP;
    584:   B->ops->getvecs        = MatCreateVecs_SeqAIJCUSP;
    585:   B->ops->setvaluesbatch = MatSetValuesBatch_SeqAIJCUSP;
    586:   B->ops->setfromoptions = MatSetFromOptions_SeqAIJCUSP;

    588:   PetscObjectComposeFunction((PetscObject)B,"MatCUSPSetFormat_C", MatCUSPSetFormat_SeqAIJCUSP);
    589:   PetscObjectChangeTypeName((PetscObject)B,MATSEQAIJCUSP);

    591:   B->valid_GPU_matrix = PETSC_CUSP_UNALLOCATED;
    592:   return(0);
    593: }

    595: /*M
    596:    MATSEQAIJCUSP - MATAIJCUSP = "aijcusp" = "seqaijcusp" - A matrix type to be used for sparse matrices.

    598:    A matrix type type whose data resides on Nvidia GPUs. These matrices are in CSR format by
    599:    default. All matrix calculations are performed using the CUSP library. DIA and ELL formats are
    600:    also available.

    602:    Options Database Keys:
    603: +  -mat_type aijcusp - sets the matrix type to "seqaijcusp" during a call to MatSetFromOptions()
    604: .  -mat_cusp_storage_format csr - sets the storage format of matrices for MatMult during a call to MatSetFromOptions(). Other options include dia (diagonal) or ell (ellpack).
    605: -  -mat_cusp_mult_storage_format csr - sets the storage format of matrices for MatMult during a call to MatSetFromOptions(). Other options include dia (diagonal) or ell (ellpack).

    607:   Level: beginner

    609: .seealso: MatCreateSeqAIJCUSP(), MATAIJCUSP, MatCreateAIJCUSP(), MatCUSPSetFormat(), MatCUSPStorageFormat, MatCUSPFormatOperation
    610: M*/