Date: 2015-09-03T15:04:06+00:00

Actual source code: bvglobal.c
slepc-3.6.1 2015-09-03
Report Typos and Errors

      1: /*
      2:    BV operations involving global communication.

      4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      6:    Copyright (c) 2002-2015, Universitat Politecnica de Valencia, Spain

      8:    This file is part of SLEPc.

     10:    SLEPc is free software: you can redistribute it and/or modify it under  the
     11:    terms of version 3 of the GNU Lesser General Public License as published by
     12:    the Free Software Foundation.

     14:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
     15:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
     16:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
     17:    more details.

     19:    You  should have received a copy of the GNU Lesser General  Public  License
     20:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
     21:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     22: */

     24: #include <slepc/private/bvimpl.h>      /*I "slepcbv.h" I*/

     28: /*
     29:   BVDot for the particular case of non-standard inner product with
     30:   matrix B, which is assumed to be symmetric (or complex Hermitian)
     31: */
     32: PETSC_STATIC_INLINE PetscErrorCode BVDot_Private(BV X,BV Y,Mat M)
     33: {
     35:   PetscObjectId  idx,idy;
     36:   PetscInt       i,j,jend,m;
     37:   PetscScalar    *marray;
     38:   PetscBool      symm=PETSC_FALSE;
     39:   Vec            z;

     42:   MatGetSize(M,&m,NULL);
     43:   MatDenseGetArray(M,&marray);
     44:   PetscObjectGetId((PetscObject)X,&idx);
     45:   PetscObjectGetId((PetscObject)Y,&idy);
     46:   if (idx==idy) symm=PETSC_TRUE;  /* M=X'BX is symmetric */
     47:   jend = X->k;
     48:   for (j=X->l;j<jend;j++) {
     49:     if (symm) Y->k = j+1;
     50:     BVGetColumn(X,j,&z);
     51:     (*Y->ops->dotvec)(Y,z,marray+j*m+Y->l);
     52:     BVRestoreColumn(X,j,&z);
     53:     if (symm) {
     54:       for (i=X->l;i<j;i++)
     55:         marray[j+i*m] = PetscConj(marray[i+j*m]);
     56:     }
     57:   }
     58:   MatDenseRestoreArray(M,&marray);
     59:   return(0);
     60: }

     64: /*@
     65:    BVDot - Computes the 'block-dot' product of two basis vectors objects.

     67:    Collective on BV

     69:    Input Parameters:
     70: +  X, Y - basis vectors
     71: -  M    - Mat object where the result must be placed

     73:    Output Parameter:
     74: .  M    - the resulting matrix

     76:    Notes:
     77:    This is the generalization of VecDot() for a collection of vectors, M = Y^H*X.
     78:    The result is a matrix M whose entry m_ij is equal to y_i^H x_j (where y_i^H
     79:    denotes the conjugate transpose of y_i).

     81:    If a non-standard inner product has been specified with BVSetMatrix(),
     82:    then the result is M = Y^H*B*X. In this case, both X and Y must have
     83:    the same associated matrix.

     85:    On entry, M must be a sequential dense Mat with dimensions m,n at least, where
     86:    m is the number of active columns of Y and n is the number of active columns of X.
     87:    Only rows (resp. columns) of M starting from ly (resp. lx) are computed,
     88:    where ly (resp. lx) is the number of leading columns of Y (resp. X).

     90:    X and Y need not be different objects.

     92:    Level: intermediate

     94: .seealso: BVDotVec(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
     95: @*/
     96: PetscErrorCode BVDot(BV X,BV Y,Mat M)
     97: {
     99:   PetscBool      match;
    100:   PetscInt       m,n;

    107:   BVCheckSizes(X,1);
    109:   BVCheckSizes(Y,2);
    112:   PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
    113:   if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Mat argument must be of type seqdense");

    115:   MatGetSize(M,&m,&n);
    116:   if (m<Y->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Mat argument has %D rows, should have at least %D",m,Y->k);
    117:   if (n<X->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Mat argument has %D columns, should have at least %D",n,X->k);
    118:   if (X->n!=Y->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
    119:   if (X->matrix!=Y->matrix) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"X and Y must have the same inner product matrix");
    120:   if (X->l==X->k || Y->l==Y->k) return(0);

    122:   PetscLogEventBegin(BV_Dot,X,Y,0,0);
    123:   if (X->matrix) { /* non-standard inner product: cast into dotvec ops */
    124:     BVDot_Private(X,Y,M);
    125:   } else {
    126:     (*X->ops->dot)(X,Y,M);
    127:   }
    128:   PetscLogEventEnd(BV_Dot,X,Y,0,0);
    129:   return(0);
    130: }

    134: /*@
    135:    BVDotVec - Computes multiple dot products of a vector against all the
    136:    column vectors of a BV.

    138:    Collective on BV and Vec

    140:    Input Parameters:
    141: +  X - basis vectors
    142: -  y - a vector

    144:    Output Parameter:
    145: .  m - an array where the result must be placed

    147:    Notes:
    148:    This is analogue to VecMDot(), but using BV to represent a collection
    149:    of vectors. The result is m = X^H*y, so m_i is equal to x_j^H y. Note
    150:    that here X is transposed as opposed to BVDot().

    152:    If a non-standard inner product has been specified with BVSetMatrix(),
    153:    then the result is m = X^H*B*y.

    155:    The length of array m must be equal to the number of active columns of X
    156:    minus the number of leading columns, i.e. the first entry of m is the
    157:    product of the first non-leading column with y.

    159:    Level: intermediate

    161: .seealso: BVDot(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
    162: @*/
    163: PetscErrorCode BVDotVec(BV X,Vec y,PetscScalar *m)
    164: {
    166:   PetscInt       n;

    172:   BVCheckSizes(X,1);

    176:   VecGetLocalSize(y,&n);
    177:   if (X->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);

    179:   PetscLogEventBegin(BV_Dot,X,y,0,0);
    180:   (*X->ops->dotvec)(X,y,m);
    181:   PetscLogEventEnd(BV_Dot,X,y,0,0);
    182:   return(0);
    183: }

    187: /*@
    188:    BVDotVecBegin - Starts a split phase dot product computation.

    190:    Input Parameters:
    191: +  X - basis vectors
    192: .  y - a vector
    193: -  m - an array where the result will go (can be NULL)

    195:    Note:
    196:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

    198:    Level: advanced

    200: .seealso: BVDotVecEnd(), BVDotVec()
    201: @*/
    202: PetscErrorCode BVDotVecBegin(BV X,Vec y,PetscScalar *m)
    203: {
    204:   PetscErrorCode      ierr;
    205:   PetscInt            i,n,nv;
    206:   PetscSplitReduction *sr;
    207:   MPI_Comm            comm;

    213:   BVCheckSizes(X,1);

    217:   VecGetLocalSize(y,&n);
    218:   if (X->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);

    220:   if (X->ops->dotvec_begin) {
    221:     (*X->ops->dotvec_begin)(X,y,m);
    222:   } else {
    223:     nv = X->k-X->l;
    224:     PetscObjectGetComm((PetscObject)X,&comm);
    225:     PetscSplitReductionGet(comm,&sr);
    226:     if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
    227:     for (i=0;i<nv;i++) {
    228:       if (sr->numopsbegin+i >= sr->maxops) {
    229:         PetscSplitReductionExtend(sr);
    230:       }
    231:       sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
    232:       sr->invecs[sr->numopsbegin+i]     = (void*)X;
    233:     }
    234:     PetscLogEventBegin(BV_Dot,X,y,0,0);
    235:     (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
    236:     sr->numopsbegin += nv;
    237:     PetscLogEventEnd(BV_Dot,X,y,0,0);
    238:   }
    239:   return(0);
    240: }

    244: /*@
    245:    BVDotVecEnd - Ends a split phase dot product computation.

    247:    Input Parameters:
    248: +  X - basis vectors
    249: .  y - a vector
    250: -  m - an array where the result will go

    252:    Note:
    253:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

    255:    Level: advanced

    257: .seealso: BVDotVecBegin(), BVDotVec()
    258: @*/
    259: PetscErrorCode BVDotVecEnd(BV X,Vec y,PetscScalar *m)
    260: {
    261:   PetscErrorCode      ierr;
    262:   PetscInt            i,nv;
    263:   PetscSplitReduction *sr;
    264:   MPI_Comm            comm;

    269:   BVCheckSizes(X,1);

    271:   if (X->ops->dotvec_end) {
    272:     (*X->ops->dotvec_end)(X,y,m);
    273:   } else {
    274:     nv = X->k-X->l;
    275:     PetscObjectGetComm((PetscObject)X,&comm);
    276:     PetscSplitReductionGet(comm,&sr);
    277:     PetscSplitReductionEnd(sr);

    279:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
    280:     if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
    281:     if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
    282:     for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];

    284:     /* Finished getting all the results so reset to no outstanding requests */
    285:     if (sr->numopsend == sr->numopsbegin) {
    286:       sr->state       = STATE_BEGIN;
    287:       sr->numopsend   = 0;
    288:       sr->numopsbegin = 0;
    289:     }
    290:   }
    291:   return(0);
    292: }

    296: /*@
    297:    BVDotColumn - Computes multiple dot products of a column against all the
    298:    previous columns of a BV.

    300:    Collective on BV

    302:    Input Parameters:
    303: +  X - basis vectors
    304: -  j - the column index

    306:    Output Parameter:
    307: .  m - an array where the result must be placed

    309:    Notes:
    310:    This operation is equivalent to BVDotVec() but it uses column j of X
    311:    rather than taking a Vec as an argument. The number of active columns of
    312:    X is set to j before the computation, and restored afterwards.
    313:    If X has leading columns specified, then these columns do not participate
    314:    in the computation. Therefore, the length of array m must be equal to j
    315:    minus the number of leading columns.

    317:    Level: advanced

    319: .seealso: BVDot(), BVDotVec(), BVSetActiveColumns(), BVSetMatrix()
    320: @*/
    321: PetscErrorCode BVDotColumn(BV X,PetscInt j,PetscScalar *m)
    322: {
    324:   PetscInt       ksave;
    325:   Vec            y;

    331:   BVCheckSizes(X,1);

    333:   if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
    334:   if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);

    336:   PetscLogEventBegin(BV_Dot,X,0,0,0);
    337:   ksave = X->k;
    338:   X->k = j;
    339:   BVGetColumn(X,j,&y);
    340:   (*X->ops->dotvec)(X,y,m);
    341:   BVRestoreColumn(X,j,&y);
    342:   X->k = ksave;
    343:   PetscLogEventEnd(BV_Dot,X,0,0,0);
    344:   return(0);
    345: }

    349: /*@
    350:    BVDotColumnBegin - Starts a split phase dot product computation.

    352:    Input Parameters:
    353: +  X - basis vectors
    354: -  j - the column index
    355: -  m - an array where the result will go (can be NULL)

    357:    Note:
    358:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

    360:    Level: advanced

    362: .seealso: BVDotColumnEnd(), BVDotColumn()
    363: @*/
    364: PetscErrorCode BVDotColumnBegin(BV X,PetscInt j,PetscScalar *m)
    365: {
    366:   PetscErrorCode      ierr;
    367:   PetscInt            i,nv,ksave;
    368:   PetscSplitReduction *sr;
    369:   MPI_Comm            comm;
    370:   Vec                 y;

    376:   BVCheckSizes(X,1);

    378:   if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
    379:   if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
    380:   ksave = X->k;
    381:   X->k = j;
    382:   BVGetColumn(X,j,&y);

    384:   if (X->ops->dotvec_begin) {
    385:     (*X->ops->dotvec_begin)(X,y,m);
    386:   } else {
    387:     nv = X->k-X->l;
    388:     PetscObjectGetComm((PetscObject)X,&comm);
    389:     PetscSplitReductionGet(comm,&sr);
    390:     if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
    391:     for (i=0;i<nv;i++) {
    392:       if (sr->numopsbegin+i >= sr->maxops) {
    393:         PetscSplitReductionExtend(sr);
    394:       }
    395:       sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
    396:       sr->invecs[sr->numopsbegin+i]     = (void*)X;
    397:     }
    398:     PetscLogEventBegin(BV_Dot,X,0,0,0);
    399:     (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
    400:     sr->numopsbegin += nv;
    401:     PetscLogEventEnd(BV_Dot,X,0,0,0);
    402:   }
    403:   BVRestoreColumn(X,j,&y);
    404:   X->k = ksave;
    405:   return(0);
    406: }

    410: /*@
    411:    BVDotColumnEnd - Ends a split phase dot product computation.

    413:    Input Parameters:
    414: +  X - basis vectors
    415: -  j - the column index
    416: -  m - an array where the result will go

    418:    Note:
    419:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

    421:    Level: advanced

    423: .seealso: BVDotColumnBegin(), BVDotColumn()
    424: @*/
    425: PetscErrorCode BVDotColumnEnd(BV X,PetscInt j,PetscScalar *m)
    426: {
    427:   PetscErrorCode      ierr;
    428:   PetscInt            i,nv,ksave;
    429:   PetscSplitReduction *sr;
    430:   MPI_Comm            comm;
    431:   Vec                 y;

    437:   BVCheckSizes(X,1);

    439:   if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
    440:   if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
    441:   ksave = X->k;
    442:   X->k = j;

    444:   if (X->ops->dotvec_end) {
    445:     BVGetColumn(X,j,&y);
    446:     (*X->ops->dotvec_end)(X,y,m);
    447:     BVRestoreColumn(X,j,&y);
    448:   } else {
    449:     nv = X->k-X->l;
    450:     PetscObjectGetComm((PetscObject)X,&comm);
    451:     PetscSplitReductionGet(comm,&sr);
    452:     PetscSplitReductionEnd(sr);

    454:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
    455:     if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
    456:     if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
    457:     for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];

    459:     /* Finished getting all the results so reset to no outstanding requests */
    460:     if (sr->numopsend == sr->numopsbegin) {
    461:       sr->state       = STATE_BEGIN;
    462:       sr->numopsend   = 0;
    463:       sr->numopsbegin = 0;
    464:     }
    465:   }
    466:   X->k = ksave;
    467:   return(0);
    468: }

    472: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Private(BV bv,Vec z,NormType type,PetscReal *val)
    473: {
    475:   PetscScalar    p;

    478:   BV_IPMatMult(bv,z);
    479:   VecDot(bv->Bx,z,&p);
    480:   if (PetscAbsScalar(p)<PETSC_MACHINE_EPSILON)
    481:     PetscInfo(bv,"Zero norm, either the vector is zero or a semi-inner product is being used\n");
    482:   if (bv->indef) {
    483:     if (PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
    484:     if (PetscRealPart(p)<0.0) *val = -PetscSqrtScalar(-PetscRealPart(p));
    485:     else *val = PetscSqrtScalar(PetscRealPart(p));
    486:   } else {
    487:     if (PetscRealPart(p)<0.0 || PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
    488:     *val = PetscSqrtScalar(PetscRealPart(p));
    489:   }
    490:   return(0);
    491: }

    495: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Begin_Private(BV bv,Vec z,NormType type,PetscReal *val)
    496: {
    498:   PetscScalar    p;

    501:   BV_IPMatMult(bv,z);
    502:   VecDotBegin(bv->Bx,z,&p);
    503:   return(0);
    504: }

    508: PETSC_STATIC_INLINE PetscErrorCode BVNorm_End_Private(BV bv,Vec z,NormType type,PetscReal *val)
    509: {
    511:   PetscScalar    p;

    514:   VecDotEnd(bv->Bx,z,&p);
    515:   if (PetscAbsScalar(p)<PETSC_MACHINE_EPSILON)
    516:     PetscInfo(bv,"Zero norm, either the vector is zero or a semi-inner product is being used\n");
    517:   if (bv->indef) {
    518:     if (PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
    519:     if (PetscRealPart(p)<0.0) *val = -PetscSqrtScalar(-PetscRealPart(p));
    520:     else *val = PetscSqrtScalar(PetscRealPart(p));
    521:   } else {
    522:     if (PetscRealPart(p)<0.0 || PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
    523:     *val = PetscSqrtScalar(PetscRealPart(p));
    524:   }
    525:   return(0);
    526: }

    530: /*@
    531:    BVNorm - Computes the matrix norm of the BV.

    533:    Collective on BV

    535:    Input Parameters:
    536: +  bv   - basis vectors
    537: -  type - the norm type

    539:    Output Parameter:
    540: .  val  - the norm

    542:    Notes:
    543:    All active columns (except the leading ones) are considered as a matrix.
    544:    The allowed norms are NORM_1, NORM_FROBENIUS, and NORM_INFINITY.

    546:    This operation fails if a non-standard inner product has been
    547:    specified with BVSetMatrix().

    549:    Level: intermediate

    551: .seealso: BVNormVec(), BVNormColumn(), BVSetActiveColumns(), BVSetMatrix()
    552: @*/
    553: PetscErrorCode BVNorm(BV bv,NormType type,PetscReal *val)
    554: {

    562:   BVCheckSizes(bv,1);

    564:   if (type==NORM_2 || type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
    565:   if (bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Matrix norm not available for non-standard inner product");

    567:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
    568:   (*bv->ops->norm)(bv,-1,type,val);
    569:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
    570:   return(0);
    571: }

    575: /*@
    576:    BVNormVec - Computes the norm of a given vector.

    578:    Collective on BV

    580:    Input Parameters:
    581: +  bv   - basis vectors
    582: .  v    - the vector
    583: -  type - the norm type

    585:    Output Parameter:
    586: .  val  - the norm

    588:    Notes:
    589:    This is the analogue of BVNormColumn() but for a vector that is not in the BV.
    590:    If a non-standard inner product has been specified with BVSetMatrix(),
    591:    then the returned value is sqrt(v'*B*v), where B is the inner product
    592:    matrix (argument 'type' is ignored). Otherwise, VecNorm() is called.

    594:    Level: developer

    596: .seealso: BVNorm(), BVNormColumn(), BVSetMatrix()
    597: @*/
    598: PetscErrorCode BVNormVec(BV bv,Vec v,NormType type,PetscReal *val)
    599: {
    601:   PetscInt       n;

    609:   BVCheckSizes(bv,1);

    613:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    615:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
    616:   if (bv->matrix) { /* non-standard inner product */
    617:     VecGetLocalSize(v,&n);
    618:     if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
    619:     BVNorm_Private(bv,v,type,val);
    620:   } else {
    621:     VecNorm(v,type,val);
    622:   }
    623:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
    624:   return(0);
    625: }

    629: /*@
    630:    BVNormVecBegin - Starts a split phase norm computation.

    632:    Input Parameters:
    633: +  bv   - basis vectors
    634: .  v    - the vector
    635: .  type - the norm type
    636: -  val  - the norm

    638:    Note:
    639:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

    641:    Level: advanced

    643: .seealso: BVNormVecEnd(), BVNormVec()
    644: @*/
    645: PetscErrorCode BVNormVecBegin(BV bv,Vec v,NormType type,PetscReal *val)
    646: {
    648:   PetscInt       n;

    656:   BVCheckSizes(bv,1);

    660:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    662:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
    663:   if (bv->matrix) { /* non-standard inner product */
    664:     VecGetLocalSize(v,&n);
    665:     if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
    666:     BVNorm_Begin_Private(bv,v,type,val);
    667:   } else {
    668:     VecNormBegin(v,type,val);
    669:   }
    670:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
    671:   return(0);
    672: }

    676: /*@
    677:    BVNormVecEnd - Ends a split phase norm computation.

    679:    Input Parameters:
    680: +  bv   - basis vectors
    681: .  v    - the vector
    682: .  type - the norm type
    683: -  val  - the norm

    685:    Note:
    686:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

    688:    Level: advanced

    690: .seealso: BVNormVecBegin(), BVNormVec()
    691: @*/
    692: PetscErrorCode BVNormVecEnd(BV bv,Vec v,NormType type,PetscReal *val)
    693: {

    701:   BVCheckSizes(bv,1);

    703:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    705:   if (bv->matrix) { /* non-standard inner product */
    706:     BVNorm_End_Private(bv,v,type,val);
    707:   } else {
    708:     VecNormEnd(v,type,val);
    709:   }
    710:   return(0);
    711: }

    715: /*@
    716:    BVNormColumn - Computes the vector norm of a selected column.

    718:    Collective on BV

    720:    Input Parameters:
    721: +  bv   - basis vectors
    722: .  j    - column number to be used
    723: -  type - the norm type

    725:    Output Parameter:
    726: .  val  - the norm

    728:    Notes:
    729:    The norm of V[j] is computed (NORM_1, NORM_2, or NORM_INFINITY).
    730:    If a non-standard inner product has been specified with BVSetMatrix(),
    731:    then the returned value is sqrt(V[j]'*B*V[j]),
    732:    where B is the inner product matrix (argument 'type' is ignored).

    734:    Level: intermediate

    736: .seealso: BVNorm(), BVNormVec(), BVSetActiveColumns(), BVSetMatrix()
    737: @*/
    738: PetscErrorCode BVNormColumn(BV bv,PetscInt j,NormType type,PetscReal *val)
    739: {
    741:   Vec            z;

    749:   BVCheckSizes(bv,1);

    751:   if (j<0 || j>=bv->m) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %D, the number of columns is %D",j,bv->m);
    752:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    754:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
    755:   if (bv->matrix) { /* non-standard inner product */
    756:     BVGetColumn(bv,j,&z);
    757:     BVNorm_Private(bv,z,type,val);
    758:     BVRestoreColumn(bv,j,&z);
    759:   } else {
    760:     (*bv->ops->norm)(bv,j,type,val);
    761:   }
    762:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
    763:   return(0);
    764: }

    768: /*@
    769:    BVNormColumnBegin - Starts a split phase norm computation.

    771:    Input Parameters:
    772: +  bv   - basis vectors
    773: .  j    - column number to be used
    774: .  type - the norm type
    775: -  val  - the norm

    777:    Note:
    778:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

    780:    Level: advanced

    782: .seealso: BVNormColumnEnd(), BVNormColumn()
    783: @*/
    784: PetscErrorCode BVNormColumnBegin(BV bv,PetscInt j,NormType type,PetscReal *val)
    785: {
    786:   PetscErrorCode      ierr;
    787:   PetscSplitReduction *sr;
    788:   PetscReal           lresult;
    789:   MPI_Comm            comm;
    790:   Vec                 z;

    798:   BVCheckSizes(bv,1);

    800:   if (j<0 || j>=bv->m) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %D, the number of columns is %D",j,bv->m);
    801:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    803:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
    804:   BVGetColumn(bv,j,&z);
    805:   if (bv->matrix) { /* non-standard inner product */
    806:     BVNorm_Begin_Private(bv,z,type,val);
    807:   } else if (bv->ops->norm_begin) {
    808:     (*bv->ops->norm_begin)(bv,j,type,val);
    809:   } else {
    810:     PetscObjectGetComm((PetscObject)z,&comm);
    811:     PetscSplitReductionGet(comm,&sr);
    812:     if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
    813:     if (sr->numopsbegin >= sr->maxops) {
    814:       PetscSplitReductionExtend(sr);
    815:     }
    816:     sr->invecs[sr->numopsbegin] = (void*)bv;
    817:     (*bv->ops->norm_local)(bv,j,type,&lresult);
    818:     if (type == NORM_2) lresult = lresult*lresult;
    819:     else if (type == NORM_MAX) sr->reducetype[sr->numopsbegin] = REDUCE_MAX;
    820:     else sr->reducetype[sr->numopsbegin] = REDUCE_SUM;
    821:     sr->lvalues[sr->numopsbegin++] = lresult;
    822:   }
    823:   BVRestoreColumn(bv,j,&z);
    824:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
    825:   return(0);
    826: }

    830: /*@
    831:    BVNormColumnEnd - Ends a split phase norm computation.

    833:    Input Parameters:
    834: +  bv   - basis vectors
    835: .  j    - column number to be used
    836: .  type - the norm type
    837: -  val  - the norm

    839:    Note:
    840:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

    842:    Level: advanced

    844: .seealso: BVNormColumnBegin(), BVNormColumn()
    845: @*/
    846: PetscErrorCode BVNormColumnEnd(BV bv,PetscInt j,NormType type,PetscReal *val)
    847: {
    848:   PetscErrorCode      ierr;
    849:   PetscSplitReduction *sr;
    850:   MPI_Comm            comm;
    851:   Vec                 z;

    859:   BVCheckSizes(bv,1);

    861:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    863:   BVGetColumn(bv,j,&z);
    864:   if (bv->matrix) { /* non-standard inner product */
    865:     BVNorm_End_Private(bv,z,type,val);
    866:   } else if (bv->ops->norm_end) {
    867:     (*bv->ops->norm_end)(bv,j,type,val);
    868:   } else {
    869:     PetscObjectGetComm((PetscObject)z,&comm);
    870:     PetscSplitReductionGet(comm,&sr);
    871:     PetscSplitReductionEnd(sr);

    873:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
    874:     if ((void*)bv != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() in a different order or with a different vector than VecxxxBegin()");
    875:     if (sr->reducetype[sr->numopsend] != REDUCE_MAX && type == NORM_MAX) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called BVNormEnd(,NORM_MAX,) on a reduction started with VecDotBegin() or NORM_1 or NORM_2");
    876:     *val = PetscRealPart(sr->gvalues[sr->numopsend++]);
    877:     if (type == NORM_2) *val = PetscSqrtReal(*val);
    878:     if (sr->numopsend == sr->numopsbegin) {
    879:       sr->state       = STATE_BEGIN;
    880:       sr->numopsend   = 0;
    881:       sr->numopsbegin = 0;
    882:     }
    883:   }
    884:   BVRestoreColumn(bv,j,&z);
    885:   return(0);
    886: }

    890: /*
    891:   Compute Y^H*A*X: right part column by column (with MatMult) and bottom
    892:   part row by row (with MatMultHermitianTranspose); result placed in marray[*,ldm]
    893: */
    894: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Vec(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)
    895: {
    897:   PetscInt       i,j,lx,ly,kx,ky,ulim;
    898:   Vec            z,f;

    901:   lx = X->l; kx = X->k;
    902:   ly = Y->l; ky = Y->k;
    903:   BVCreateVec(X,&f);
    904:   for (j=lx;j<kx;j++) {
    905:     BVGetColumn(X,j,&z);
    906:     MatMult(A,z,f);
    907:     BVRestoreColumn(X,j,&z);
    908:     ulim = PetscMin(ly+(j-lx)+1,ky);
    909:     Y->l = 0; Y->k = ulim;
    910:     (*Y->ops->dotvec)(Y,f,marray+j*ldm);
    911:     if (symm) {
    912:       for (i=0;i<j;i++) marray[j+i*ldm] = PetscConj(marray[i+j*ldm]);
    913:     }
    914:   }
    915:   if (!symm) {
    916:     BV_AllocateCoeffs(Y);
    917:     for (j=ly;j<ky;j++) {
    918:       BVGetColumn(Y,j,&z);
    919:       MatMultHermitianTranspose(A,z,f);
    920:       BVRestoreColumn(Y,j,&z);
    921:       ulim = PetscMin(lx+(j-ly),kx);
    922:       X->l = 0; X->k = ulim;
    923:       (*X->ops->dotvec)(X,f,Y->h);
    924:       for (i=0;i<ulim;i++) marray[j+i*ldm] = PetscConj(Y->h[i]);
    925:     }
    926:   }
    927:   VecDestroy(&f);
    928:   X->l = lx; X->k = kx;
    929:   Y->l = ly; Y->k = ky;
    930:   return(0);
    931: }

    935: /*
    936:   Compute Y^H*A*X= [   --   | Y0'*W1 ]
    937:                    [ Y1'*W0 | Y1'*W1 ]
    938:   Allocates auxiliary BV to store the result of A*X, then one BVDot
    939:   call for top-right part and another one for bottom part;
    940:   result placed in marray[*,ldm]
    941: */
    942: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm)
    943: {
    945:   PetscInt       j,lx,ly,kx,ky;
    946:   PetscScalar    *harray;
    947:   Mat            H;
    948:   BV             W;

    951:   lx = X->l; kx = X->k;
    952:   ly = Y->l; ky = Y->k;
    953:   BVDuplicate(X,&W);
    954:   X->l = 0; X->k = kx;
    955:   BVMatMult(X,A,W);

    957:   /* top-right part, Y0'*AX1 */
    958:   if (ly>0 && lx<kx) {
    959:     MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
    960:     W->l = lx; W->k = kx;
    961:     Y->l = 0;  Y->k = ly;
    962:     BVDot(W,Y,H);
    963:     MatDenseGetArray(H,&harray);
    964:     for (j=lx;j<kx;j++) {
    965:       PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
    966:     }
    967:     MatDenseRestoreArray(H,&harray);
    968:     MatDestroy(&H);
    969:   }

    971:   /* bottom part, Y1'*AX */
    972:   if (kx>0 && ly<ky) {
    973:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
    974:     W->l = 0;  W->k = kx;
    975:     Y->l = ly; Y->k = ky;
    976:     BVDot(W,Y,H);
    977:     MatDenseGetArray(H,&harray);
    978:     for (j=0;j<kx;j++) {
    979:       PetscMemcpy(marray+j*ldm+ly,harray+j*ky+ly,(ky-ly)*sizeof(PetscScalar));
    980:     }
    981:     MatDenseRestoreArray(H,&harray);
    982:     MatDestroy(&H);
    983:   }
    984:   BVDestroy(&W);
    985:   X->l = lx; X->k = kx;
    986:   Y->l = ly; Y->k = ky;
    987:   return(0);
    988: }

    992: /*
    993:   Compute Y^H*A*X= [   --   | Y0'*W1 ]
    994:                    [ Y1'*W0 | Y1'*W1 ]
    995:   First stage: allocate auxiliary BV to store A*X1, one BVDot for right part;
    996:   Second stage: resize BV to accomodate A'*Y1, then call BVDot for transpose of
    997:   bottom-left part; result placed in marray[*,ldm]
    998: */
    999: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult_2(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)
    1000: {
    1002:   PetscInt       i,j,lx,ly,kx,ky;
    1003:   PetscScalar    *harray;
    1004:   Mat            H;
    1005:   BV             W;

    1008:   lx = X->l; kx = X->k;
    1009:   ly = Y->l; ky = Y->k;

    1011:   /* right part, Y'*AX1 */
    1012:   BVDuplicateResize(X,kx-lx,&W);
    1013:   if (ky>0 && lx<kx) {
    1014:     BVMatMult(X,A,W);
    1015:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx-lx,NULL,&H);
    1016:     Y->l = 0; Y->k = ky;
    1017:     BVDot(W,Y,H);
    1018:     MatDenseGetArray(H,&harray);
    1019:     for (j=lx;j<kx;j++) {
    1020:       PetscMemcpy(marray+j*ldm,harray+(j-lx)*ky,ky*sizeof(PetscScalar));
    1021:     }
    1022:     MatDenseRestoreArray(H,&harray);
    1023:     MatDestroy(&H);
    1024:   }

    1026:   /* bottom-left part, Y1'*AX0 */
    1027:   if (lx>0 && ly<ky) {
    1028:     if (symm) {
    1029:       /* do not compute, just copy symmetric elements */
    1030:       for (i=ly;i<ky;i++) {
    1031:         for (j=0;j<lx;j++) marray[i+j*ldm] = PetscConj(marray[j+i*ldm]);
    1032:       }
    1033:     } else {
    1034:       BVResize(W,ky-ly,PETSC_FALSE);
    1035:       Y->l = ly; Y->k = ky;
    1036:       BVMatMultHermitianTranspose(Y,A,W);
    1037:       MatCreateSeqDense(PETSC_COMM_SELF,lx,ky-ly,NULL,&H);
    1038:       X->l = 0; X->k = lx;
    1039:       BVDot(W,X,H);
    1040:       MatDenseGetArray(H,&harray);
    1041:       for (i=0;i<ky-ly;i++) {
    1042:         for (j=0;j<lx;j++) {
    1043:           marray[i+j*ldm+ly] = PetscConj(harray[j+i*(ky-ly)]);
    1044:         }
    1045:       }
    1046:       MatDenseRestoreArray(H,&harray);
    1047:       MatDestroy(&H);
    1048:     }
    1049:   }
    1050:   BVDestroy(&W);
    1051:   X->l = lx; X->k = kx;
    1052:   Y->l = ly; Y->k = ky;
    1053:   return(0);
    1054: }

    1058: /*
    1059:   Compute Y^H*X = [   --   | Y0'*X1 ]     (X contains A*X):
    1060:                   [ Y1'*X0 | Y1'*X1 ]
    1061:   one BVDot call for top-right part and another one for bottom part;
    1062:   result placed in marray[*,ldm]
    1063: */
    1064: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Dot(BV X,BV Y,PetscScalar *marray,PetscInt ldm)
    1065: {
    1067:   PetscInt       j,lx,ly,kx,ky;
    1068:   PetscScalar    *harray;
    1069:   Mat            H;

    1072:   lx = X->l; kx = X->k;
    1073:   ly = Y->l; ky = Y->k;

    1075:   /* top-right part, Y0'*X1 */
    1076:   if (ly>0 && lx<kx) {
    1077:     MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
    1078:     X->l = lx; X->k = kx;
    1079:     Y->l = 0;  Y->k = ly;
    1080:     BVDot(X,Y,H);
    1081:     MatDenseGetArray(H,&harray);
    1082:     for (j=lx;j<kx;j++) {
    1083:       PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
    1084:     }
    1085:     MatDenseRestoreArray(H,&harray);
    1086:     MatDestroy(&H);
    1087:   }

    1089:   /* bottom part, Y1'*X */
    1090:   if (kx>0 && ly<ky) {
    1091:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
    1092:     X->l = 0;  X->k = kx;
    1093:     Y->l = ly; Y->k = ky;
    1094:     BVDot(X,Y,H);
    1095:     MatDenseGetArray(H,&harray);
    1096:     for (j=0;j<kx;j++) {
    1097:       PetscMemcpy(marray+j*ldm+ly,harray+j*ky+ly,(ky-ly)*sizeof(PetscScalar));
    1098:     }
    1099:     MatDenseRestoreArray(H,&harray);
    1100:     MatDestroy(&H);
    1101:   }
    1102:   X->l = lx; X->k = kx;
    1103:   Y->l = ly; Y->k = ky;
    1104:   return(0);
    1105: }

    1109: /*@
    1110:    BVMatProject - Computes the projection of a matrix onto a subspace.

    1112:    Collective on BV

    1114:    Input Parameters:
    1115: +  X - basis vectors
    1116: .  A - (optional) matrix to be projected
    1117: .  Y - left basis vectors, can be equal to X
    1118: -  M - Mat object where the result must be placed

    1120:    Output Parameter:
    1121: .  M - the resulting matrix

    1123:    Notes:
    1124:    If A=NULL, then it is assumed that X already contains A*X.

    1126:    This operation is similar to BVDot(), with important differences.
    1127:    The goal is to compute the matrix resulting from the orthogonal projection
    1128:    of A onto the subspace spanned by the columns of X, M = X^H*A*X, or the
    1129:    oblique projection onto X along Y, M = Y^H*A*X.

    1131:    A difference with respect to BVDot() is that the standard inner product
    1132:    is always used, regardless of a non-standard inner product being specified
    1133:    with BVSetMatrix().

    1135:    On entry, M must be a sequential dense Mat with dimensions ky,kx at least,
    1136:    where ky (resp. kx) is the number of active columns of Y (resp. X).
    1137:    Another difference with respect to BVDot() is that all entries of M are
    1138:    computed except the leading ly,lx part, where ly (resp. lx) is the
    1139:    number of leading columns of Y (resp. X). Hence, the leading columns of
    1140:    X and Y participate in the computation, as opposed to BVDot().
    1141:    The leading part of M is assumed to be already available from previous
    1142:    computations.

    1144:    In the orthogonal projection case, Y=X, some computation can be saved if
    1145:    A is real symmetric (or complex Hermitian). In order to exploit this
    1146:    property, the symmetry flag of A must be set with MatSetOption().

    1148:    Level: intermediate

    1150: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
    1151: @*/
    1152: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)
    1153: {
    1155:   PetscBool      match,set,flg,symm=PETSC_FALSE;
    1156:   PetscInt       m,n;
    1157:   PetscScalar    *marray;
    1158:   Mat            Xmatrix,Ymatrix;
    1159:   PetscObjectId  idx,idy;

    1167:   BVCheckSizes(X,1);
    1168:   if (A) {
    1171:   }
    1173:   BVCheckSizes(Y,3);
    1176:   PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
    1177:   if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Matrix M must be of type seqdense");

    1179:   MatGetSize(M,&m,&n);
    1180:   if (m<Y->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Matrix M has %D rows, should have at least %D",m,Y->k);
    1181:   if (n<X->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Matrix M has %D columns, should have at least %D",n,X->k);
    1182:   if (X->n!=Y->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);

    1184:   PetscLogEventBegin(BV_MatProject,X,A,Y,0);
    1185:   /* temporarily set standard inner product */
    1186:   Xmatrix = X->matrix;
    1187:   Ymatrix = Y->matrix;
    1188:   X->matrix = Y->matrix = NULL;

    1190:   PetscObjectGetId((PetscObject)X,&idx);
    1191:   PetscObjectGetId((PetscObject)Y,&idy);
    1192:   if (!A && idx==idy) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot set X=Y if A=NULL");

    1194:   MatDenseGetArray(M,&marray);

    1196:   if (A && idx==idy) { /* check symmetry of M=X'AX */
    1197:     MatIsHermitianKnown(A,&set,&flg);
    1198:     symm = set? flg: PETSC_FALSE;
    1199:   }

    1201:   if (A) {
    1202:     if (X->vmm==BV_MATMULT_VECS) {
    1203:       /* perform computation column by column */
    1204:       BVMatProject_Vec(X,A,Y,marray,m,symm);
    1205:     } else {
    1206:       /* use BVMatMult, then BVDot */
    1207:       MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg);
    1208:       if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) {
    1209:         BVMatProject_MatMult_2(X,A,Y,marray,m,symm);
    1210:       } else {
    1211:         BVMatProject_MatMult(X,A,Y,marray,m);
    1212:       }
    1213:     }
    1214:   } else {
    1215:     /* use BVDot on subblocks */
    1216:     BVMatProject_Dot(X,Y,marray,m);
    1217:   }

    1219:   MatDenseRestoreArray(M,&marray);
    1220:   PetscLogEventEnd(BV_MatProject,X,A,Y,0);
    1221:   /* restore non-standard inner product */
    1222:   X->matrix = Xmatrix;
    1223:   Y->matrix = Ymatrix;
    1224:   return(0);
    1225: }