Date: 2023-11-27T17:19:22+00:00

Actual source code: contig.c
slepc-3.20.1 2023-11-27
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

      6:    This file is part of SLEPc.
      7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
      8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9: */
     10: /*
     11:    BV implemented as an array of Vecs sharing a contiguous array for elements
     12: */

     14: #include <slepc/private/bvimpl.h>

     16: typedef struct {
     17:   Vec         *V;
     18:   PetscScalar *array;
     19:   PetscBool   mpi;
     20: } BV_CONTIGUOUS;

     22: static PetscErrorCode BVMult_Contiguous(BV Y,PetscScalar alpha,PetscScalar beta,BV X,Mat Q)
     23: {
     24:   BV_CONTIGUOUS     *y = (BV_CONTIGUOUS*)Y->data,*x = (BV_CONTIGUOUS*)X->data;
     25:   const PetscScalar *q;
     26:   PetscInt          ldq;

     28:   PetscFunctionBegin;
     29:   if (Q) {
     30:     PetscCall(MatDenseGetLDA(Q,&ldq));
     31:     PetscCall(MatDenseGetArrayRead(Q,&q));
     32:     PetscCall(BVMult_BLAS_Private(Y,Y->n,Y->k-Y->l,X->k-X->l,alpha,x->array+(X->nc+X->l)*X->ld,X->ld,q+Y->l*ldq+X->l,ldq,beta,y->array+(Y->nc+Y->l)*Y->ld,Y->ld));
     33:     PetscCall(MatDenseRestoreArrayRead(Q,&q));
     34:   } else PetscCall(BVAXPY_BLAS_Private(Y,Y->n,Y->k-Y->l,alpha,x->array+(X->nc+X->l)*X->ld,X->ld,beta,y->array+(Y->nc+Y->l)*Y->ld,Y->ld));
     35:   PetscFunctionReturn(PETSC_SUCCESS);
     36: }

     38: static PetscErrorCode BVMultVec_Contiguous(BV X,PetscScalar alpha,PetscScalar beta,Vec y,PetscScalar *q)
     39: {
     40:   BV_CONTIGUOUS  *x = (BV_CONTIGUOUS*)X->data;
     41:   PetscScalar    *py,*qq=q;

     43:   PetscFunctionBegin;
     44:   PetscCall(VecGetArray(y,&py));
     45:   if (!q) PetscCall(VecGetArray(X->buffer,&qq));
     46:   PetscCall(BVMultVec_BLAS_Private(X,X->n,X->k-X->l,alpha,x->array+(X->nc+X->l)*X->ld,X->ld,qq,beta,py));
     47:   if (!q) PetscCall(VecRestoreArray(X->buffer,&qq));
     48:   PetscCall(VecRestoreArray(y,&py));
     49:   PetscFunctionReturn(PETSC_SUCCESS);
     50: }

     52: static PetscErrorCode BVMultInPlace_Contiguous(BV V,Mat Q,PetscInt s,PetscInt e)
     53: {
     54:   BV_CONTIGUOUS     *ctx = (BV_CONTIGUOUS*)V->data;
     55:   const PetscScalar *q;
     56:   PetscInt          ldq;

     58:   PetscFunctionBegin;
     59:   if (s>=e || !V->n) PetscFunctionReturn(PETSC_SUCCESS);
     60:   PetscCall(MatDenseGetLDA(Q,&ldq));
     61:   PetscCall(MatDenseGetArrayRead(Q,&q));
     62:   PetscCall(BVMultInPlace_BLAS_Private(V,V->n,V->k-V->l,s-V->l,e-V->l,ctx->array+(V->nc+V->l)*V->ld,V->ld,q+V->l*ldq+V->l,ldq,PETSC_FALSE));
     63:   PetscCall(MatDenseRestoreArrayRead(Q,&q));
     64:   PetscFunctionReturn(PETSC_SUCCESS);
     65: }

     67: static PetscErrorCode BVMultInPlaceHermitianTranspose_Contiguous(BV V,Mat Q,PetscInt s,PetscInt e)
     68: {
     69:   BV_CONTIGUOUS     *ctx = (BV_CONTIGUOUS*)V->data;
     70:   const PetscScalar *q;
     71:   PetscInt          ldq;

     73:   PetscFunctionBegin;
     74:   if (s>=e || !V->n) PetscFunctionReturn(PETSC_SUCCESS);
     75:   PetscCall(MatDenseGetLDA(Q,&ldq));
     76:   PetscCall(MatDenseGetArrayRead(Q,&q));
     77:   PetscCall(BVMultInPlace_BLAS_Private(V,V->n,V->k-V->l,s-V->l,e-V->l,ctx->array+(V->nc+V->l)*V->ld,V->ld,q+V->l*ldq+V->l,ldq,PETSC_TRUE));
     78:   PetscCall(MatDenseRestoreArrayRead(Q,&q));
     79:   PetscFunctionReturn(PETSC_SUCCESS);
     80: }

     82: static PetscErrorCode BVDot_Contiguous(BV X,BV Y,Mat M)
     83: {
     84:   BV_CONTIGUOUS  *x = (BV_CONTIGUOUS*)X->data,*y = (BV_CONTIGUOUS*)Y->data;
     85:   PetscScalar    *m;
     86:   PetscInt       ldm;

     88:   PetscFunctionBegin;
     89:   PetscCall(MatDenseGetLDA(M,&ldm));
     90:   PetscCall(MatDenseGetArray(M,&m));
     91:   PetscCall(BVDot_BLAS_Private(X,Y->k-Y->l,X->k-X->l,X->n,y->array+(Y->nc+Y->l)*Y->ld,Y->ld,x->array+(X->nc+X->l)*X->ld,X->ld,m+X->l*ldm+Y->l,ldm,x->mpi));
     92:   PetscCall(MatDenseRestoreArray(M,&m));
     93:   PetscFunctionReturn(PETSC_SUCCESS);
     94: }

     96: static PetscErrorCode BVDotVec_Contiguous(BV X,Vec y,PetscScalar *q)
     97: {
     98:   BV_CONTIGUOUS     *x = (BV_CONTIGUOUS*)X->data;
     99:   const PetscScalar *py;
    100:   PetscScalar       *qq=q;
    101:   Vec               z = y;

    103:   PetscFunctionBegin;
    104:   if (PetscUnlikely(X->matrix)) {
    105:     PetscCall(BV_IPMatMult(X,y));
    106:     z = X->Bx;
    107:   }
    108:   PetscCall(VecGetArrayRead(z,&py));
    109:   if (!q) PetscCall(VecGetArray(X->buffer,&qq));
    110:   PetscCall(BVDotVec_BLAS_Private(X,X->n,X->k-X->l,x->array+(X->nc+X->l)*X->ld,X->ld,py,qq,x->mpi));
    111:   if (!q) PetscCall(VecRestoreArray(X->buffer,&qq));
    112:   PetscCall(VecRestoreArrayRead(z,&py));
    113:   PetscFunctionReturn(PETSC_SUCCESS);
    114: }

    116: static PetscErrorCode BVDotVec_Local_Contiguous(BV X,Vec y,PetscScalar *m)
    117: {
    118:   BV_CONTIGUOUS  *x = (BV_CONTIGUOUS*)X->data;
    119:   PetscScalar    *py;
    120:   Vec            z = y;

    122:   PetscFunctionBegin;
    123:   if (PetscUnlikely(X->matrix)) {
    124:     PetscCall(BV_IPMatMult(X,y));
    125:     z = X->Bx;
    126:   }
    127:   PetscCall(VecGetArray(z,&py));
    128:   PetscCall(BVDotVec_BLAS_Private(X,X->n,X->k-X->l,x->array+(X->nc+X->l)*X->ld,X->ld,py,m,PETSC_FALSE));
    129:   PetscCall(VecRestoreArray(z,&py));
    130:   PetscFunctionReturn(PETSC_SUCCESS);
    131: }

    133: static PetscErrorCode BVScale_Contiguous(BV bv,PetscInt j,PetscScalar alpha)
    134: {
    135:   BV_CONTIGUOUS  *ctx = (BV_CONTIGUOUS*)bv->data;

    137:   PetscFunctionBegin;
    138:   if (!bv->n) PetscFunctionReturn(PETSC_SUCCESS);
    139:   if (PetscUnlikely(j<0)) PetscCall(BVScale_BLAS_Private(bv,(bv->k-bv->l)*bv->ld,ctx->array+(bv->nc+bv->l)*bv->ld,alpha));
    140:   else PetscCall(BVScale_BLAS_Private(bv,bv->n,ctx->array+(bv->nc+j)*bv->ld,alpha));
    141:   PetscFunctionReturn(PETSC_SUCCESS);
    142: }

    144: static PetscErrorCode BVNorm_Contiguous(BV bv,PetscInt j,NormType type,PetscReal *val)
    145: {
    146:   BV_CONTIGUOUS  *ctx = (BV_CONTIGUOUS*)bv->data;

    148:   PetscFunctionBegin;
    149:   if (PetscUnlikely(j<0)) PetscCall(BVNorm_LAPACK_Private(bv,bv->n,bv->k-bv->l,ctx->array+(bv->nc+bv->l)*bv->ld,bv->ld,type,val,ctx->mpi));
    150:   else PetscCall(BVNorm_LAPACK_Private(bv,bv->n,1,ctx->array+(bv->nc+j)*bv->ld,bv->ld,type,val,ctx->mpi));
    151:   PetscFunctionReturn(PETSC_SUCCESS);
    152: }

    154: static PetscErrorCode BVNorm_Local_Contiguous(BV bv,PetscInt j,NormType type,PetscReal *val)
    155: {
    156:   BV_CONTIGUOUS  *ctx = (BV_CONTIGUOUS*)bv->data;

    158:   PetscFunctionBegin;
    159:   if (PetscUnlikely(j<0)) PetscCall(BVNorm_LAPACK_Private(bv,bv->n,bv->k-bv->l,ctx->array+(bv->nc+bv->l)*bv->ld,bv->ld,type,val,PETSC_FALSE));
    160:   else PetscCall(BVNorm_LAPACK_Private(bv,bv->n,1,ctx->array+(bv->nc+j)*bv->ld,bv->ld,type,val,PETSC_FALSE));
    161:   PetscFunctionReturn(PETSC_SUCCESS);
    162: }

    164: static PetscErrorCode BVNormalize_Contiguous(BV bv,PetscScalar *eigi)
    165: {
    166:   BV_CONTIGUOUS  *ctx = (BV_CONTIGUOUS*)bv->data;
    167:   PetscScalar    *wi=NULL;

    169:   PetscFunctionBegin;
    170:   if (eigi) wi = eigi+bv->l;
    171:   PetscCall(BVNormalize_LAPACK_Private(bv,bv->n,bv->k-bv->l,ctx->array+(bv->nc+bv->l)*bv->ld,bv->ld,wi,ctx->mpi));
    172:   PetscFunctionReturn(PETSC_SUCCESS);
    173: }

    175: static PetscErrorCode BVMatMult_Contiguous(BV V,Mat A,BV W)
    176: {
    177:   BV_CONTIGUOUS  *v = (BV_CONTIGUOUS*)V->data,*w = (BV_CONTIGUOUS*)W->data;
    178:   PetscInt       j;
    179:   Mat            Vmat,Wmat;

    181:   PetscFunctionBegin;
    182:   if (V->vmm) {
    183:     PetscCall(BVGetMat(V,&Vmat));
    184:     PetscCall(BVGetMat(W,&Wmat));
    185:     PetscCall(MatProductCreateWithMat(A,Vmat,NULL,Wmat));
    186:     PetscCall(MatProductSetType(Wmat,MATPRODUCT_AB));
    187:     PetscCall(MatProductSetFromOptions(Wmat));
    188:     PetscCall(MatProductSymbolic(Wmat));
    189:     PetscCall(MatProductNumeric(Wmat));
    190:     PetscCall(MatProductClear(Wmat));
    191:     PetscCall(BVRestoreMat(V,&Vmat));
    192:     PetscCall(BVRestoreMat(W,&Wmat));
    193:   } else {
    194:     for (j=0;j<V->k-V->l;j++) PetscCall(MatMult(A,v->V[V->nc+V->l+j],w->V[W->nc+W->l+j]));
    195:   }
    196:   PetscFunctionReturn(PETSC_SUCCESS);
    197: }

    199: static PetscErrorCode BVCopy_Contiguous(BV V,BV W)
    200: {
    201:   BV_CONTIGUOUS  *v = (BV_CONTIGUOUS*)V->data,*w = (BV_CONTIGUOUS*)W->data;
    202:   PetscInt       j;

    204:   PetscFunctionBegin;
    205:   for (j=0;j<V->k-V->l;j++) PetscCall(PetscArraycpy(w->array+(W->nc+W->l+j)*W->ld,v->array+(V->nc+V->l+j)*V->ld,V->n));
    206:   PetscFunctionReturn(PETSC_SUCCESS);
    207: }

    209: static PetscErrorCode BVCopyColumn_Contiguous(BV V,PetscInt j,PetscInt i)
    210: {
    211:   BV_CONTIGUOUS  *v = (BV_CONTIGUOUS*)V->data;

    213:   PetscFunctionBegin;
    214:   PetscCall(PetscArraycpy(v->array+(V->nc+i)*V->ld,v->array+(V->nc+j)*V->ld,V->n));
    215:   PetscFunctionReturn(PETSC_SUCCESS);
    216: }

    218: static PetscErrorCode BVResize_Contiguous(BV bv,PetscInt m,PetscBool copy)
    219: {
    220:   BV_CONTIGUOUS  *ctx = (BV_CONTIGUOUS*)bv->data;
    221:   PetscInt       j,bs;
    222:   PetscScalar    *newarray;
    223:   Vec            *newV;
    224:   char           str[50];

    226:   PetscFunctionBegin;
    227:   PetscCall(VecGetBlockSize(bv->t,&bs));
    228:   PetscCall(PetscCalloc1(m*bv->ld,&newarray));
    229:   PetscCall(PetscMalloc1(m,&newV));
    230:   for (j=0;j<m;j++) {
    231:     if (ctx->mpi) PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)bv->t),bs,bv->n,PETSC_DECIDE,newarray+j*bv->ld,newV+j));
    232:     else PetscCall(VecCreateSeqWithArray(PetscObjectComm((PetscObject)bv->t),bs,bv->n,newarray+j*bv->ld,newV+j));
    233:   }
    234:   if (((PetscObject)bv)->name) {
    235:     for (j=0;j<m;j++) {
    236:       PetscCall(PetscSNPrintf(str,sizeof(str),"%s_%" PetscInt_FMT,((PetscObject)bv)->name,j));
    237:       PetscCall(PetscObjectSetName((PetscObject)newV[j],str));
    238:     }
    239:   }
    240:   if (copy) PetscCall(PetscArraycpy(newarray,ctx->array,PetscMin(m,bv->m)*bv->ld));
    241:   PetscCall(VecDestroyVecs(bv->m,&ctx->V));
    242:   ctx->V = newV;
    243:   PetscCall(PetscFree(ctx->array));
    244:   ctx->array = newarray;
    245:   PetscFunctionReturn(PETSC_SUCCESS);
    246: }

    248: static PetscErrorCode BVGetColumn_Contiguous(BV bv,PetscInt j,Vec *v)
    249: {
    250:   BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
    251:   PetscInt      l;

    253:   PetscFunctionBegin;
    254:   l = BVAvailableVec;
    255:   bv->cv[l] = ctx->V[bv->nc+j];
    256:   PetscFunctionReturn(PETSC_SUCCESS);
    257: }

    259: static PetscErrorCode BVRestoreColumn_Contiguous(BV bv,PetscInt j,Vec *v)
    260: {
    261:   PetscInt l;

    263:   PetscFunctionBegin;
    264:   l = (j==bv->ci[0])? 0: 1;
    265:   bv->cv[l] = NULL;
    266:   PetscFunctionReturn(PETSC_SUCCESS);
    267: }

    269: static PetscErrorCode BVGetArray_Contiguous(BV bv,PetscScalar **a)
    270: {
    271:   BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;

    273:   PetscFunctionBegin;
    274:   *a = ctx->array;
    275:   PetscFunctionReturn(PETSC_SUCCESS);
    276: }

    278: static PetscErrorCode BVGetArrayRead_Contiguous(BV bv,const PetscScalar **a)
    279: {
    280:   BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;

    282:   PetscFunctionBegin;
    283:   *a = ctx->array;
    284:   PetscFunctionReturn(PETSC_SUCCESS);
    285: }

    287: static PetscErrorCode BVDestroy_Contiguous(BV bv)
    288: {
    289:   BV_CONTIGUOUS  *ctx = (BV_CONTIGUOUS*)bv->data;

    291:   PetscFunctionBegin;
    292:   if (!bv->issplit) {
    293:     PetscCall(VecDestroyVecs(bv->nc+bv->m,&ctx->V));
    294:     PetscCall(PetscFree(ctx->array));
    295:   }
    296:   PetscCall(PetscFree(bv->data));
    297:   PetscFunctionReturn(PETSC_SUCCESS);
    298: }

    300: static PetscErrorCode BVView_Contiguous(BV bv,PetscViewer viewer)
    301: {
    302:   PetscInt          j;
    303:   Vec               v;
    304:   PetscViewerFormat format;
    305:   PetscBool         isascii,ismatlab=PETSC_FALSE;
    306:   const char        *bvname,*name;

    308:   PetscFunctionBegin;
    309:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    310:   if (isascii) {
    311:     PetscCall(PetscViewerGetFormat(viewer,&format));
    312:     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(PETSC_SUCCESS);
    313:     if (format == PETSC_VIEWER_ASCII_MATLAB) ismatlab = PETSC_TRUE;
    314:   }
    315:   if (ismatlab) {
    316:     PetscCall(PetscObjectGetName((PetscObject)bv,&bvname));
    317:     PetscCall(PetscViewerASCIIPrintf(viewer,"%s=[];\n",bvname));
    318:   }
    319:   for (j=0;j<bv->m;j++) {
    320:     PetscCall(BVGetColumn(bv,j,&v));
    321:     PetscCall(VecView(v,viewer));
    322:     if (ismatlab) {
    323:       PetscCall(PetscObjectGetName((PetscObject)v,&name));
    324:       PetscCall(PetscViewerASCIIPrintf(viewer,"%s=[%s,%s];clear %s\n",bvname,bvname,name,name));
    325:     }
    326:     PetscCall(BVRestoreColumn(bv,j,&v));
    327:   }
    328:   PetscFunctionReturn(PETSC_SUCCESS);
    329: }

    331: SLEPC_EXTERN PetscErrorCode BVCreate_Contiguous(BV bv)
    332: {
    333:   BV_CONTIGUOUS  *ctx;
    334:   PetscInt       j,nloc,bs,lsplit,lda;
    335:   PetscBool      seq,isdense;
    336:   PetscScalar    *aa;
    337:   char           str[50];
    338:   PetscScalar    *array;
    339:   BV             parent;
    340:   Vec            *Vpar;
    341:   MatType        mtype;

    343:   PetscFunctionBegin;
    344:   PetscCall(PetscNew(&ctx));
    345:   bv->data = (void*)ctx;

    347:   PetscCall(PetscObjectTypeCompare((PetscObject)bv->t,VECMPI,&ctx->mpi));
    348:   if (!ctx->mpi) {
    349:     PetscCall(PetscObjectTypeCompare((PetscObject)bv->t,VECSEQ,&seq));
    350:     PetscCheck(seq,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Cannot create a contiguous BV from a non-standard template vector");
    351:   }

    353:   PetscCall(VecGetLocalSize(bv->t,&nloc));
    354:   PetscCall(VecGetBlockSize(bv->t,&bs));
    355:   PetscCall(BV_SetDefaultLD(bv,nloc));

    357:   if (PetscUnlikely(bv->issplit)) {
    358:     /* split BV: share memory and Vecs of the parent BV */
    359:     parent = bv->splitparent;
    360:     lsplit = parent->lsplit;
    361:     Vpar   = ((BV_CONTIGUOUS*)parent->data)->V;
    362:     ctx->V = (bv->issplit==1)? Vpar: Vpar+lsplit;
    363:     array  = ((BV_CONTIGUOUS*)parent->data)->array;
    364:     ctx->array = (bv->issplit==1)? array: array+lsplit*bv->ld;
    365:   } else {
    366:     /* regular BV: allocate memory and Vecs for the BV entries */
    367:     PetscCall(PetscCalloc1(bv->m*bv->ld,&ctx->array));
    368:     PetscCall(PetscMalloc1(bv->m,&ctx->V));
    369:     for (j=0;j<bv->m;j++) {
    370:       if (ctx->mpi) PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)bv->t),bs,nloc,PETSC_DECIDE,ctx->array+j*bv->ld,ctx->V+j));
    371:       else PetscCall(VecCreateSeqWithArray(PetscObjectComm((PetscObject)bv->t),bs,nloc,ctx->array+j*bv->ld,ctx->V+j));
    372:     }
    373:   }
    374:   if (((PetscObject)bv)->name) {
    375:     for (j=0;j<bv->m;j++) {
    376:       PetscCall(PetscSNPrintf(str,sizeof(str),"%s_%" PetscInt_FMT,((PetscObject)bv)->name,j));
    377:       PetscCall(PetscObjectSetName((PetscObject)ctx->V[j],str));
    378:     }
    379:   }

    381:   if (PetscUnlikely(bv->Acreate)) {
    382:     PetscCall(MatGetType(bv->Acreate,&mtype));
    383:     PetscCall(PetscStrcmpAny(mtype,&isdense,MATSEQDENSE,MATMPIDENSE,""));
    384:     PetscCheck(isdense,PetscObjectComm((PetscObject)bv->Acreate),PETSC_ERR_SUP,"BVCONTIGUOUS requires a dense matrix in BVCreateFromMat()\n");
    385:     PetscCall(MatDenseGetArray(bv->Acreate,&aa));
    386:     PetscCall(MatDenseGetLDA(bv->Acreate,&lda));
    387:     for (j=0;j<bv->m;j++) PetscCall(PetscArraycpy(ctx->array+j*bv->ld,aa+j*lda,bv->n));
    388:     PetscCall(MatDenseRestoreArray(bv->Acreate,&aa));
    389:     PetscCall(MatDestroy(&bv->Acreate));
    390:   }

    392:   bv->ops->mult             = BVMult_Contiguous;
    393:   bv->ops->multvec          = BVMultVec_Contiguous;
    394:   bv->ops->multinplace      = BVMultInPlace_Contiguous;
    395:   bv->ops->multinplacetrans = BVMultInPlaceHermitianTranspose_Contiguous;
    396:   bv->ops->dot              = BVDot_Contiguous;
    397:   bv->ops->dotvec           = BVDotVec_Contiguous;
    398:   bv->ops->dotvec_local     = BVDotVec_Local_Contiguous;
    399:   bv->ops->scale            = BVScale_Contiguous;
    400:   bv->ops->norm             = BVNorm_Contiguous;
    401:   bv->ops->norm_local       = BVNorm_Local_Contiguous;
    402:   bv->ops->normalize        = BVNormalize_Contiguous;
    403:   bv->ops->matmult          = BVMatMult_Contiguous;
    404:   bv->ops->copy             = BVCopy_Contiguous;
    405:   bv->ops->copycolumn       = BVCopyColumn_Contiguous;
    406:   bv->ops->resize           = BVResize_Contiguous;
    407:   bv->ops->getcolumn        = BVGetColumn_Contiguous;
    408:   bv->ops->restorecolumn    = BVRestoreColumn_Contiguous;
    409:   bv->ops->getarray         = BVGetArray_Contiguous;
    410:   bv->ops->getarrayread     = BVGetArrayRead_Contiguous;
    411:   bv->ops->getmat           = BVGetMat_Default;
    412:   bv->ops->restoremat       = BVRestoreMat_Default;
    413:   bv->ops->destroy          = BVDestroy_Contiguous;
    414:   bv->ops->view             = BVView_Contiguous;
    415:   PetscFunctionReturn(PETSC_SUCCESS);
    416: }