Actual source code: vecs.c

      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 independent Vecs
     12: */

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

     16: typedef struct {
     17:   Vec      *V;
     18:   PetscInt vmip;   /* Version of BVMultInPlace:
     19:        0: memory-efficient version, uses VecGetArray (default in CPU)
     20:        1: version that allocates (e-s) work vectors in every call (default in GPU) */
     21: } BV_VECS;

     23: static PetscErrorCode BVMult_Vecs(BV Y,PetscScalar alpha,PetscScalar beta,BV X,Mat Q)
     24: {
     25:   BV_VECS           *y = (BV_VECS*)Y->data,*x = (BV_VECS*)X->data;
     26:   PetscScalar       *s=NULL;
     27:   const PetscScalar *q;
     28:   PetscInt          i,j,ldq;
     29:   PetscBool         trivial=(alpha==1.0)?PETSC_TRUE:PETSC_FALSE;

     31:   PetscFunctionBegin;
     32:   if (Q) {
     33:     PetscCall(MatDenseGetLDA(Q,&ldq));
     34:     if (!trivial) {
     35:       PetscCall(BVAllocateWork_Private(Y,X->k-X->l));
     36:       s = Y->work;
     37:     }
     38:     PetscCall(MatDenseGetArrayRead(Q,&q));
     39:     for (j=Y->l;j<Y->k;j++) {
     40:       PetscCall(VecScale(y->V[Y->nc+j],beta));
     41:       if (!trivial) {
     42:         for (i=X->l;i<X->k;i++) s[i-X->l] = alpha*q[i+j*ldq];
     43:       } else s = (PetscScalar*)(q+j*ldq+X->l);
     44:       PetscCall(VecMAXPY(y->V[Y->nc+j],X->k-X->l,s,x->V+X->nc+X->l));
     45:     }
     46:     PetscCall(MatDenseRestoreArrayRead(Q,&q));
     47:   } else {
     48:     for (j=0;j<Y->k-Y->l;j++) {
     49:       PetscCall(VecScale(y->V[Y->nc+Y->l+j],beta));
     50:       PetscCall(VecAXPY(y->V[Y->nc+Y->l+j],alpha,x->V[X->nc+X->l+j]));
     51:     }
     52:   }
     53:   PetscFunctionReturn(PETSC_SUCCESS);
     54: }

     56: static PetscErrorCode BVMultVec_Vecs(BV X,PetscScalar alpha,PetscScalar beta,Vec y,PetscScalar *q)
     57: {
     58:   BV_VECS        *x = (BV_VECS*)X->data;
     59:   PetscScalar    *s=NULL,*qq=q;
     60:   PetscInt       i;
     61:   PetscBool      trivial=(alpha==1.0)?PETSC_TRUE:PETSC_FALSE;

     63:   PetscFunctionBegin;
     64:   if (!trivial) {
     65:     PetscCall(BVAllocateWork_Private(X,X->k-X->l));
     66:     s = X->work;
     67:   }
     68:   if (!q) PetscCall(VecGetArray(X->buffer,&qq));
     69:   PetscCall(VecScale(y,beta));
     70:   if (!trivial) {
     71:     for (i=0;i<X->k-X->l;i++) s[i] = alpha*qq[i];
     72:   } else s = qq;
     73:   PetscCall(VecMAXPY(y,X->k-X->l,s,x->V+X->nc+X->l));
     74:   if (!q) PetscCall(VecRestoreArray(X->buffer,&qq));
     75:   PetscFunctionReturn(PETSC_SUCCESS);
     76: }

     78: /*
     79:    BVMultInPlace_Vecs_ME - V(:,s:e-1) = V*Q(:,s:e-1) for regular vectors.

     81:    Memory-efficient version, uses VecGetArray (default in CPU)

     83:    Writing V = [ V1 V2 V3 ] and Q(:,s:e-1) = [ Q1 Q2 Q3 ]', where V2
     84:    corresponds to the columns s:e-1, the computation is done as
     85:                   V2 := V2*Q2 + V1*Q1 + V3*Q3
     86: */
     87: static PetscErrorCode BVMultInPlace_Vecs_ME(BV V,Mat Q,PetscInt s,PetscInt e)
     88: {
     89:   BV_VECS           *ctx = (BV_VECS*)V->data;
     90:   const PetscScalar *q;
     91:   PetscInt          i,ldq;

     93:   PetscFunctionBegin;
     94:   PetscCall(MatDenseGetLDA(Q,&ldq));
     95:   PetscCall(MatDenseGetArrayRead(Q,&q));
     96:   /* V2 := V2*Q2 */
     97:   PetscCall(BVMultInPlace_Vecs_Private(V,V->n,e-s,ldq,ctx->V+V->nc+s,q+s*ldq+s,PETSC_FALSE));
     98:   /* V2 += V1*Q1 + V3*Q3 */
     99:   for (i=s;i<e;i++) {
    100:     if (PetscUnlikely(s>V->l)) PetscCall(VecMAXPY(ctx->V[V->nc+i],s-V->l,q+i*ldq+V->l,ctx->V+V->nc+V->l));
    101:     if (V->k>e) PetscCall(VecMAXPY(ctx->V[V->nc+i],V->k-e,q+i*ldq+e,ctx->V+V->nc+e));
    102:   }
    103:   PetscCall(MatDenseRestoreArrayRead(Q,&q));
    104:   PetscFunctionReturn(PETSC_SUCCESS);
    105: }

    107: /*
    108:    BVMultInPlace_Vecs_Alloc - V(:,s:e-1) = V*Q(:,s:e-1) for regular vectors.

    110:    Version that allocates (e-s) work vectors in every call (default in GPU)
    111: */
    112: static PetscErrorCode BVMultInPlace_Vecs_Alloc(BV V,Mat Q,PetscInt s,PetscInt e)
    113: {
    114:   BV_VECS           *ctx = (BV_VECS*)V->data;
    115:   const PetscScalar *q;
    116:   PetscInt          i,ldq;
    117:   Vec               *W,z;

    119:   PetscFunctionBegin;
    120:   PetscCall(MatDenseGetLDA(Q,&ldq));
    121:   PetscCall(MatDenseGetArrayRead(Q,&q));
    122:   PetscCall(BVCreateVec(V,&z));
    123:   PetscCall(VecDuplicateVecs(z,e-s,&W));
    124:   PetscCall(VecDestroy(&z));
    125:   for (i=s;i<e;i++) PetscCall(VecMAXPY(W[i-s],V->k-V->l,q+i*ldq+V->l,ctx->V+V->nc+V->l));
    126:   for (i=s;i<e;i++) PetscCall(VecCopy(W[i-s],ctx->V[V->nc+i]));
    127:   PetscCall(VecDestroyVecs(e-s,&W));
    128:   PetscCall(MatDenseRestoreArrayRead(Q,&q));
    129:   PetscFunctionReturn(PETSC_SUCCESS);
    130: }

    132: /*
    133:    BVMultInPlaceHermitianTranspose_Vecs - V(:,s:e-1) = V*Q'(:,s:e-1) for regular vectors.
    134: */
    135: static PetscErrorCode BVMultInPlaceHermitianTranspose_Vecs(BV V,Mat Q,PetscInt s,PetscInt e)
    136: {
    137:   BV_VECS           *ctx = (BV_VECS*)V->data;
    138:   const PetscScalar *q;
    139:   PetscInt          i,j,ldq,n;

    141:   PetscFunctionBegin;
    142:   PetscCall(MatGetSize(Q,NULL,&n));
    143:   PetscCall(MatDenseGetLDA(Q,&ldq));
    144:   PetscCall(MatDenseGetArrayRead(Q,&q));
    145:   /* V2 := V2*Q2' */
    146:   PetscCall(BVMultInPlace_Vecs_Private(V,V->n,e-s,ldq,ctx->V+V->nc+s,q+s*ldq+s,PETSC_TRUE));
    147:   /* V2 += V1*Q1' + V3*Q3' */
    148:   for (i=s;i<e;i++) {
    149:     for (j=V->l;j<s;j++) PetscCall(VecAXPY(ctx->V[V->nc+i],q[i+j*ldq],ctx->V[V->nc+j]));
    150:     for (j=e;j<n;j++) PetscCall(VecAXPY(ctx->V[V->nc+i],q[i+j*ldq],ctx->V[V->nc+j]));
    151:   }
    152:   PetscCall(MatDenseRestoreArrayRead(Q,&q));
    153:   PetscFunctionReturn(PETSC_SUCCESS);
    154: }

    156: static PetscErrorCode BVDot_Vecs(BV X,BV Y,Mat M)
    157: {
    158:   BV_VECS        *x = (BV_VECS*)X->data,*y = (BV_VECS*)Y->data;
    159:   PetscScalar    *m;
    160:   PetscInt       j,ldm;

    162:   PetscFunctionBegin;
    163:   PetscCall(MatDenseGetLDA(M,&ldm));
    164:   PetscCall(MatDenseGetArray(M,&m));
    165:   for (j=X->l;j<X->k;j++) PetscCall(VecMDot(x->V[X->nc+j],Y->k-Y->l,y->V+Y->nc+Y->l,m+j*ldm+Y->l));
    166:   PetscCall(MatDenseRestoreArray(M,&m));
    167:   PetscFunctionReturn(PETSC_SUCCESS);
    168: }

    170: static PetscErrorCode BVDotVec_Vecs(BV X,Vec y,PetscScalar *q)
    171: {
    172:   BV_VECS        *x = (BV_VECS*)X->data;
    173:   Vec            z = y;
    174:   PetscScalar    *qq=q;

    176:   PetscFunctionBegin;
    177:   if (PetscUnlikely(X->matrix)) {
    178:     PetscCall(BV_IPMatMult(X,y));
    179:     z = X->Bx;
    180:   }
    181:   if (!q) PetscCall(VecGetArray(X->buffer,&qq));
    182:   PetscCall(VecMDot(z,X->k-X->l,x->V+X->nc+X->l,qq));
    183:   if (!q) PetscCall(VecRestoreArray(X->buffer,&qq));
    184:   PetscFunctionReturn(PETSC_SUCCESS);
    185: }

    187: static PetscErrorCode BVDotVec_Begin_Vecs(BV X,Vec y,PetscScalar *m)
    188: {
    189:   BV_VECS        *x = (BV_VECS*)X->data;
    190:   Vec            z = y;

    192:   PetscFunctionBegin;
    193:   if (PetscUnlikely(X->matrix)) {
    194:     PetscCall(BV_IPMatMult(X,y));
    195:     z = X->Bx;
    196:   }
    197:   PetscCall(VecMDotBegin(z,X->k-X->l,x->V+X->nc+X->l,m));
    198:   PetscFunctionReturn(PETSC_SUCCESS);
    199: }

    201: static PetscErrorCode BVDotVec_End_Vecs(BV X,Vec y,PetscScalar *m)
    202: {
    203:   BV_VECS        *x = (BV_VECS*)X->data;

    205:   PetscFunctionBegin;
    206:   PetscCall(VecMDotEnd(y,X->k-X->l,x->V+X->nc+X->l,m));
    207:   PetscFunctionReturn(PETSC_SUCCESS);
    208: }

    210: static PetscErrorCode BVScale_Vecs(BV bv,PetscInt j,PetscScalar alpha)
    211: {
    212:   PetscInt       i;
    213:   BV_VECS        *ctx = (BV_VECS*)bv->data;

    215:   PetscFunctionBegin;
    216:   if (PetscUnlikely(j<0)) {
    217:     for (i=bv->l;i<bv->k;i++) PetscCall(VecScale(ctx->V[bv->nc+i],alpha));
    218:   } else PetscCall(VecScale(ctx->V[bv->nc+j],alpha));
    219:   PetscFunctionReturn(PETSC_SUCCESS);
    220: }

    222: static PetscErrorCode BVNorm_Vecs(BV bv,PetscInt j,NormType type,PetscReal *val)
    223: {
    224:   PetscInt       i;
    225:   PetscReal      nrm;
    226:   BV_VECS        *ctx = (BV_VECS*)bv->data;

    228:   PetscFunctionBegin;
    229:   if (PetscUnlikely(j<0)) {
    230:     PetscCheck(type==NORM_FROBENIUS,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not implemented in BVVECS");
    231:     *val = 0.0;
    232:     for (i=bv->l;i<bv->k;i++) {
    233:       PetscCall(VecNorm(ctx->V[bv->nc+i],NORM_2,&nrm));
    234:       *val += nrm*nrm;
    235:     }
    236:     *val = PetscSqrtReal(*val);
    237:   } else PetscCall(VecNorm(ctx->V[bv->nc+j],type,val));
    238:   PetscFunctionReturn(PETSC_SUCCESS);
    239: }

    241: static PetscErrorCode BVNorm_Begin_Vecs(BV bv,PetscInt j,NormType type,PetscReal *val)
    242: {
    243:   BV_VECS        *ctx = (BV_VECS*)bv->data;

    245:   PetscFunctionBegin;
    246:   PetscCheck(j>=0,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not implemented in BVVECS");
    247:   PetscCall(VecNormBegin(ctx->V[bv->nc+j],type,val));
    248:   PetscFunctionReturn(PETSC_SUCCESS);
    249: }

    251: static PetscErrorCode BVNorm_End_Vecs(BV bv,PetscInt j,NormType type,PetscReal *val)
    252: {
    253:   BV_VECS        *ctx = (BV_VECS*)bv->data;

    255:   PetscFunctionBegin;
    256:   PetscCheck(j>=0,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not implemented in BVVECS");
    257:   PetscCall(VecNormEnd(ctx->V[bv->nc+j],type,val));
    258:   PetscFunctionReturn(PETSC_SUCCESS);
    259: }

    261: static PetscErrorCode BVNormalize_Vecs(BV bv,PetscScalar *eigi)
    262: {
    263:   BV_VECS  *ctx = (BV_VECS*)bv->data;
    264:   PetscInt i;

    266:   PetscFunctionBegin;
    267:   for (i=bv->l;i<bv->k;i++) {
    268: #if !defined(PETSC_USE_COMPLEX)
    269:     if (eigi && eigi[i] != 0.0) {
    270:       PetscCall(VecNormalizeComplex(ctx->V[bv->nc+i],ctx->V[bv->nc+i+1],PETSC_TRUE,NULL));
    271:       i++;
    272:     } else
    273: #endif
    274:     {
    275:       PetscCall(VecNormalize(ctx->V[bv->nc+i],NULL));
    276:     }
    277:   }
    278:   PetscFunctionReturn(PETSC_SUCCESS);
    279: }

    281: static PetscErrorCode BVMatMult_Vecs(BV V,Mat A,BV W)
    282: {
    283:   BV_VECS        *v = (BV_VECS*)V->data,*w = (BV_VECS*)W->data;
    284:   PetscInt       j;
    285:   Mat            Vmat,Wmat;

    287:   PetscFunctionBegin;
    288:   if (V->vmm) {
    289:     PetscCall(BVGetMat(V,&Vmat));
    290:     PetscCall(BVGetMat(W,&Wmat));
    291:     PetscCall(MatProductCreateWithMat(A,Vmat,NULL,Wmat));
    292:     PetscCall(MatProductSetType(Wmat,MATPRODUCT_AB));
    293:     PetscCall(MatProductSetFromOptions(Wmat));
    294:     PetscCall(MatProductSymbolic(Wmat));
    295:     PetscCall(MatProductNumeric(Wmat));
    296:     PetscCall(MatProductClear(Wmat));
    297:     PetscCall(BVRestoreMat(V,&Vmat));
    298:     PetscCall(BVRestoreMat(W,&Wmat));
    299:   } else {
    300:     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]));
    301:   }
    302:   PetscFunctionReturn(PETSC_SUCCESS);
    303: }

    305: static PetscErrorCode BVCopy_Vecs(BV V,BV W)
    306: {
    307:   BV_VECS        *v = (BV_VECS*)V->data,*w = (BV_VECS*)W->data;
    308:   PetscInt       j;

    310:   PetscFunctionBegin;
    311:   for (j=0;j<V->k-V->l;j++) PetscCall(VecCopy(v->V[V->nc+V->l+j],w->V[W->nc+W->l+j]));
    312:   PetscFunctionReturn(PETSC_SUCCESS);
    313: }

    315: static PetscErrorCode BVCopyColumn_Vecs(BV V,PetscInt j,PetscInt i)
    316: {
    317:   BV_VECS        *v = (BV_VECS*)V->data;

    319:   PetscFunctionBegin;
    320:   PetscCall(VecCopy(v->V[V->nc+j],v->V[V->nc+i]));
    321:   PetscFunctionReturn(PETSC_SUCCESS);
    322: }

    324: static PetscErrorCode BVResize_Vecs(BV bv,PetscInt m,PetscBool copy)
    325: {
    326:   BV_VECS        *ctx = (BV_VECS*)bv->data;
    327:   Vec            *newV,z;
    328:   PetscInt       j;
    329:   char           str[50];

    331:   PetscFunctionBegin;
    332:   PetscCall(BVCreateVec(bv,&z));
    333:   PetscCall(VecDuplicateVecs(z,m,&newV));
    334:   PetscCall(VecDestroy(&z));
    335:   if (((PetscObject)bv)->name) {
    336:     for (j=0;j<m;j++) {
    337:       PetscCall(PetscSNPrintf(str,sizeof(str),"%s_%" PetscInt_FMT,((PetscObject)bv)->name,j));
    338:       PetscCall(PetscObjectSetName((PetscObject)newV[j],str));
    339:     }
    340:   }
    341:   if (copy) {
    342:     for (j=0;j<PetscMin(m,bv->m);j++) PetscCall(VecCopy(ctx->V[j],newV[j]));
    343:   }
    344:   PetscCall(VecDestroyVecs(bv->m,&ctx->V));
    345:   ctx->V = newV;
    346:   PetscFunctionReturn(PETSC_SUCCESS);
    347: }

    349: static PetscErrorCode BVGetColumn_Vecs(BV bv,PetscInt j,Vec *v)
    350: {
    351:   BV_VECS  *ctx = (BV_VECS*)bv->data;
    352:   PetscInt l;

    354:   PetscFunctionBegin;
    355:   l = BVAvailableVec;
    356:   bv->cv[l] = ctx->V[bv->nc+j];
    357:   PetscFunctionReturn(PETSC_SUCCESS);
    358: }

    360: static PetscErrorCode BVRestoreColumn_Vecs(BV bv,PetscInt j,Vec *v)
    361: {
    362:   PetscInt l;

    364:   PetscFunctionBegin;
    365:   l = (j==bv->ci[0])? 0: 1;
    366:   bv->cv[l] = NULL;
    367:   PetscFunctionReturn(PETSC_SUCCESS);
    368: }

    370: static PetscErrorCode BVGetArray_Vecs(BV bv,PetscScalar **a)
    371: {
    372:   BV_VECS           *ctx = (BV_VECS*)bv->data;
    373:   PetscInt          j;
    374:   const PetscScalar *p;

    376:   PetscFunctionBegin;
    377:   PetscCall(PetscMalloc1((bv->nc+bv->m)*bv->n,a));
    378:   for (j=0;j<bv->nc+bv->m;j++) {
    379:     PetscCall(VecGetArrayRead(ctx->V[j],&p));
    380:     PetscCall(PetscArraycpy(*a+j*bv->n,p,bv->n));
    381:     PetscCall(VecRestoreArrayRead(ctx->V[j],&p));
    382:   }
    383:   PetscFunctionReturn(PETSC_SUCCESS);
    384: }

    386: static PetscErrorCode BVRestoreArray_Vecs(BV bv,PetscScalar **a)
    387: {
    388:   BV_VECS        *ctx = (BV_VECS*)bv->data;
    389:   PetscInt       j;
    390:   PetscScalar    *p;

    392:   PetscFunctionBegin;
    393:   for (j=0;j<bv->nc+bv->m;j++) {
    394:     PetscCall(VecGetArray(ctx->V[j],&p));
    395:     PetscCall(PetscArraycpy(p,*a+j*bv->n,bv->n));
    396:     PetscCall(VecRestoreArray(ctx->V[j],&p));
    397:   }
    398:   PetscCall(PetscFree(*a));
    399:   PetscFunctionReturn(PETSC_SUCCESS);
    400: }

    402: static PetscErrorCode BVGetArrayRead_Vecs(BV bv,const PetscScalar **a)
    403: {
    404:   BV_VECS           *ctx = (BV_VECS*)bv->data;
    405:   PetscInt          j;
    406:   const PetscScalar *p;

    408:   PetscFunctionBegin;
    409:   PetscCall(PetscMalloc1((bv->nc+bv->m)*bv->n,(PetscScalar**)a));
    410:   for (j=0;j<bv->nc+bv->m;j++) {
    411:     PetscCall(VecGetArrayRead(ctx->V[j],&p));
    412:     PetscCall(PetscArraycpy((PetscScalar*)*a+j*bv->n,p,bv->n));
    413:     PetscCall(VecRestoreArrayRead(ctx->V[j],&p));
    414:   }
    415:   PetscFunctionReturn(PETSC_SUCCESS);
    416: }

    418: static PetscErrorCode BVRestoreArrayRead_Vecs(BV bv,const PetscScalar **a)
    419: {
    420:   PetscFunctionBegin;
    421:   PetscCall(PetscFree(*a));
    422:   PetscFunctionReturn(PETSC_SUCCESS);
    423: }

    425: /*
    426:    Sets the value of vmip flag and resets ops->multinplace accordingly
    427:  */
    428: static inline PetscErrorCode BVVecsSetVmip(BV bv,PetscInt vmip)
    429: {
    430:   typedef PetscErrorCode (*fmultinplace)(BV,Mat,PetscInt,PetscInt);
    431:   fmultinplace multinplace[2] = {BVMultInPlace_Vecs_ME, BVMultInPlace_Vecs_Alloc};
    432:   BV_VECS      *ctx = (BV_VECS*)bv->data;

    434:   PetscFunctionBegin;
    435:   ctx->vmip            = vmip;
    436:   bv->ops->multinplace = multinplace[vmip];
    437:   PetscFunctionReturn(PETSC_SUCCESS);
    438: }

    440: static PetscErrorCode BVSetFromOptions_Vecs(BV bv,PetscOptionItems PetscOptionsObject)
    441: {
    442:   BV_VECS        *ctx = (BV_VECS*)bv->data;

    444:   PetscFunctionBegin;
    445:   PetscOptionsHeadBegin(PetscOptionsObject,"BV Vecs Options");

    447:     PetscCall(PetscOptionsRangeInt("-bv_vecs_vmip","Version of BVMultInPlace operation","",ctx->vmip,&ctx->vmip,NULL,0,1));
    448:     PetscCall(BVVecsSetVmip(bv,ctx->vmip));

    450:   PetscOptionsHeadEnd();
    451:   PetscFunctionReturn(PETSC_SUCCESS);
    452: }

    454: PetscErrorCode BVView_Vecs(BV bv,PetscViewer viewer)
    455: {
    456:   BV_VECS           *ctx = (BV_VECS*)bv->data;
    457:   PetscInt          j;
    458:   PetscViewerFormat format;
    459:   PetscBool         isascii,ismatlab=PETSC_FALSE;
    460:   const char        *bvname,*name;

    462:   PetscFunctionBegin;
    463:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    464:   if (isascii) {
    465:     PetscCall(PetscViewerGetFormat(viewer,&format));
    466:     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(PETSC_SUCCESS);
    467:     if (format == PETSC_VIEWER_ASCII_MATLAB) ismatlab = PETSC_TRUE;
    468:   }
    469:   if (ismatlab) {
    470:     PetscCall(PetscObjectGetName((PetscObject)bv,&bvname));
    471:     PetscCall(PetscViewerASCIIPrintf(viewer,"%s=[];\n",bvname));
    472:   }
    473:   for (j=bv->nc;j<bv->nc+bv->m;j++) {
    474:     PetscCall(VecView(ctx->V[j],viewer));
    475:     if (ismatlab) {
    476:       PetscCall(PetscObjectGetName((PetscObject)ctx->V[j],&name));
    477:       PetscCall(PetscViewerASCIIPrintf(viewer,"%s=[%s,%s];clear %s\n",bvname,bvname,name,name));
    478:     }
    479:   }
    480:   PetscFunctionReturn(PETSC_SUCCESS);
    481: }

    483: static PetscErrorCode BVDestroy_Vecs(BV bv)
    484: {
    485:   BV_VECS        *ctx = (BV_VECS*)bv->data;

    487:   PetscFunctionBegin;
    488:   if (!bv->issplit) PetscCall(VecDestroyVecs(bv->nc+bv->m,&ctx->V));
    489:   PetscCall(PetscFree(bv->data));
    490:   PetscFunctionReturn(PETSC_SUCCESS);
    491: }

    493: static PetscErrorCode BVDuplicate_Vecs(BV V,BV W)
    494: {
    495:   BV_VECS        *ctx = (BV_VECS*)V->data;

    497:   PetscFunctionBegin;
    498:   PetscCall(BVVecsSetVmip(W,ctx->vmip));
    499:   PetscFunctionReturn(PETSC_SUCCESS);
    500: }

    502: /*MC
    503:    BVVECS - BVVECS = "vecs" - A basis vectors object represented by an array of
    504:    independent `Vec`s.

    506:    Level: beginner

    508: .seealso: [](sec:bv), `BV`, `BVType`, `BVSetType()`
    509: M*/

    511: SLEPC_EXTERN PetscErrorCode BVCreate_Vecs(BV bv)
    512: {
    513:   BV_VECS        *ctx;
    514:   PetscInt       j,lsplit;
    515:   PetscBool      isgpu;
    516:   char           str[50];
    517:   BV             parent;
    518:   Vec            *Vpar,z;

    520:   PetscFunctionBegin;
    521:   PetscCall(PetscNew(&ctx));
    522:   bv->data = (void*)ctx;

    524:   if (PetscUnlikely(bv->issplit)) {
    525:     PetscCheck(bv->issplit>0,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"BVVECS does not support BVGetSplitRows()");
    526:     /* split BV: share the Vecs of the parent BV */
    527:     parent = bv->splitparent;
    528:     lsplit = parent->lsplit;
    529:     Vpar   = ((BV_VECS*)parent->data)->V;
    530:     ctx->V = (bv->issplit==1)? Vpar: Vpar+lsplit;
    531:   } else {
    532:     /* regular BV: create array of Vecs to store the BV columns */
    533:     PetscCall(BVCreateVec(bv,&z));
    534:     PetscCall(VecDuplicateVecs(z,bv->m,&ctx->V));
    535:     PetscCall(VecDestroy(&z));
    536:     if (((PetscObject)bv)->name) {
    537:       for (j=0;j<bv->m;j++) {
    538:         PetscCall(PetscSNPrintf(str,sizeof(str),"%s_%" PetscInt_FMT,((PetscObject)bv)->name,j));
    539:         PetscCall(PetscObjectSetName((PetscObject)ctx->V[j],str));
    540:       }
    541:     }
    542:   }
    543:   if (!bv->ld) bv->ld = bv->n;
    544:   PetscCheck(bv->ld==bv->n,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"BVVECS does not support a user-defined leading dimension");

    546:   if (PetscUnlikely(bv->Acreate)) {
    547:     for (j=0;j<bv->m;j++) PetscCall(MatGetColumnVector(bv->Acreate,ctx->V[j],j));
    548:     PetscCall(MatDestroy(&bv->Acreate));
    549:   }

    551:   /* Default version of BVMultInPlace */
    552:   PetscCall(PetscStrcmpAny(bv->vtype,&isgpu,VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,""));
    553:   ctx->vmip = isgpu? 1: 0;

    555:   /* Default BVMatMult method */
    556:   bv->vmm = BV_MATMULT_VECS;

    558:   /* Deferred call to setfromoptions */
    559:   if (bv->defersfo) {
    560:     PetscObjectOptionsBegin((PetscObject)bv);
    561:     PetscCall(BVSetFromOptions_Vecs(bv,PetscOptionsObject));
    562:     PetscOptionsEnd();
    563:   }
    564:   PetscCall(BVVecsSetVmip(bv,ctx->vmip));

    566:   bv->ops->mult             = BVMult_Vecs;
    567:   bv->ops->multvec          = BVMultVec_Vecs;
    568:   bv->ops->multinplacetrans = BVMultInPlaceHermitianTranspose_Vecs;
    569:   bv->ops->dot              = BVDot_Vecs;
    570:   bv->ops->dotvec           = BVDotVec_Vecs;
    571:   bv->ops->dotvec_begin     = BVDotVec_Begin_Vecs;
    572:   bv->ops->dotvec_end       = BVDotVec_End_Vecs;
    573:   bv->ops->scale            = BVScale_Vecs;
    574:   bv->ops->norm             = BVNorm_Vecs;
    575:   bv->ops->norm_begin       = BVNorm_Begin_Vecs;
    576:   bv->ops->norm_end         = BVNorm_End_Vecs;
    577:   bv->ops->normalize        = BVNormalize_Vecs;
    578:   bv->ops->matmult          = BVMatMult_Vecs;
    579:   bv->ops->copy             = BVCopy_Vecs;
    580:   bv->ops->copycolumn       = BVCopyColumn_Vecs;
    581:   bv->ops->resize           = BVResize_Vecs;
    582:   bv->ops->getcolumn        = BVGetColumn_Vecs;
    583:   bv->ops->restorecolumn    = BVRestoreColumn_Vecs;
    584:   bv->ops->getarray         = BVGetArray_Vecs;
    585:   bv->ops->restorearray     = BVRestoreArray_Vecs;
    586:   bv->ops->getarrayread     = BVGetArrayRead_Vecs;
    587:   bv->ops->restorearrayread = BVRestoreArrayRead_Vecs;
    588:   bv->ops->getmat           = BVGetMat_Default;
    589:   bv->ops->restoremat       = BVRestoreMat_Default;
    590:   bv->ops->destroy          = BVDestroy_Vecs;
    591:   bv->ops->duplicate        = BVDuplicate_Vecs;
    592:   bv->ops->setfromoptions   = BVSetFromOptions_Vecs;
    593:   bv->ops->view             = BVView_Vecs;
    594:   PetscFunctionReturn(PETSC_SUCCESS);
    595: }