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

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

      1: /*

      3:    SLEPc eigensolver: "lobpcg"

      5:    Method: Locally Optimal Block Preconditioned Conjugate Gradient

      7:    Algorithm:

      9:        LOBPCG with soft and hard locking. Follows the implementation
     10:        in BLOPEX [2].

     12:    References:

     14:        [1] A. V. Knyazev, "Toward the optimal preconditioned eigensolver:
     15:            locally optimal block preconditioned conjugate gradient method",
     16:            SIAM J. Sci. Comput. 23(2):517-541, 2001.

     18:        [2] A. V. Knyazev et al., "Block Locally Optimal Preconditioned
     19:            Eigenvalue Xolvers (BLOPEX) in Hypre and PETSc", SIAM J. Sci.
     20:            Comput. 29(5):2224-2239, 2007.

     22:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     23:    SLEPc - Scalable Library for Eigenvalue Problem Computations
     24:    Copyright (c) 2002-2015, Universitat Politecnica de Valencia, Spain

     26:    This file is part of SLEPc.

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

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

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

     42: #include <slepc/private/epsimpl.h>                /*I "slepceps.h" I*/
     43: #include <slepc/private/dsimpl.h>                 /*I "slepcds.h" I*/

     45: typedef struct {
     46:   PetscInt  bs;     /* block size */
     47:   PetscBool lock;   /* soft locking active/inactive */
     48: } EPS_LOBPCG;

     52: PetscErrorCode EPSSetDimensions_LOBPCG(EPS eps,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
     53: {
     54:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
     55:   PetscInt   k;

     58:   k = PetscMax(3*ctx->bs,((eps->nev-1)/ctx->bs+3)*ctx->bs);
     59:   if (*ncv) { /* ncv set */
     60:     if (*ncv<k) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv is not sufficiently large");
     61:   } else *ncv = k;
     62:   if (!*mpd) *mpd = 3*ctx->bs;
     63:   else if (*mpd!=3*ctx->bs) SETERRQ(PetscObjectComm((PetscObject)eps),1,"This solver does not allow a value of mpd different from 3*blocksize");
     64:   return(0);
     65: }

     69: PetscErrorCode EPSSetUp_LOBPCG(EPS eps)
     70: {
     72:   EPS_LOBPCG     *ctx = (EPS_LOBPCG*)eps->data;
     73:   PetscBool      precond,istrivial;

     76:   if (!eps->ishermitian || (eps->isgeneralized && !eps->ispositive)) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"LOBPCG only works for Hermitian problems");
     77:   if (!ctx->bs) ctx->bs = PetscMin(16,eps->nev);
     78:   if (eps->n-eps->nds<5*ctx->bs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"The problem size is too small relative to the block size");
     79:   EPSSetDimensions_LOBPCG(eps,eps->nev,&eps->ncv,&eps->mpd);
     80:   if (!eps->max_it) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
     81:   if (!eps->which) eps->which = EPS_SMALLEST_REAL;
     82:   if (eps->which!=EPS_SMALLEST_REAL) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Wrong value of eps->which");
     83:   if (eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs not supported in this solver");
     84:   if (eps->extraction) { PetscInfo(eps,"Warning: extraction type ignored\n"); }
     85:   RGIsTrivial(eps->rg,&istrivial);
     86:   if (!istrivial) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver does not support region filtering");

     88:   STSetUp(eps->st);
     89:   PetscObjectTypeCompare((PetscObject)eps->st,STPRECOND,&precond);
     90:   if (!precond) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"LOBPCG only works with precond ST");

     92:   EPSAllocateSolution(eps,0);
     93:   EPS_SetInnerProduct(eps);
     94:   DSSetType(eps->ds,DSGHEP);
     95:   DSAllocate(eps->ds,eps->mpd);
     96:   EPSSetWorkVecs(eps,1);
     97:   return(0);
     98: }

    102: PetscErrorCode EPSSolve_LOBPCG(EPS eps)
    103: {
    105:   EPS_LOBPCG     *ctx = (EPS_LOBPCG*)eps->data;
    106:   PetscInt       i,j,k,ld,nv,ini,kini,nmat,nc,nconv,bdone,its;
    107:   PetscReal      norm;
    108:   PetscBool      breakdown,countc;
    109:   Mat            A,B,M;
    110:   Vec            v,w=eps->work[0];
    111:   BV             X,Y,Z,R,P,AX,BX;

    114:   DSGetLeadingDimension(eps->ds,&ld);
    115:   STGetNumMatrices(eps->st,&nmat);
    116:   STGetOperators(eps->st,0,&A);
    117:   if (nmat>1) { STGetOperators(eps->st,1,&B); }
    118:   else B = NULL;

    120:   /* 1. Allocate memory */
    121:   BVDuplicateResize(eps->V,3*ctx->bs,&Z);
    122:   BVDuplicateResize(eps->V,ctx->bs,&X);
    123:   BVDuplicateResize(eps->V,ctx->bs,&R);
    124:   BVDuplicateResize(eps->V,ctx->bs,&P);
    125:   BVDuplicateResize(eps->V,ctx->bs,&AX);
    126:   if (B) {
    127:     BVDuplicateResize(eps->V,ctx->bs,&BX);
    128:   }
    129:   nc = eps->nds;
    130:   if (nc>0 || eps->nev>ctx->bs) {
    131:     BVDuplicateResize(eps->V,nc+eps->nev,&Y);
    132:   }
    133:   if (nc>0) {
    134:     for (j=0;j<nc;j++) {
    135:       BVGetColumn(eps->V,-nc+j,&v);
    136:       BVInsertVec(Y,j,v);
    137:       BVRestoreColumn(eps->V,-nc+j,&v);
    138:     }
    139:     BVSetActiveColumns(Y,0,nc);
    140:   }

    142:   /* 2. Apply the constraints to the initial vectors */
    143:   kini = eps->nini;
    144:   while (kini<eps->ncv-2*ctx->bs) { /* Generate more initial vectors if necessary */
    145:     BVSetRandomColumn(eps->V,kini,eps->rand);
    146:     BVOrthogonalizeColumn(eps->V,kini,NULL,&norm,&breakdown);
    147:     if (norm>0.0 && !breakdown) {
    148:       BVScaleColumn(eps->V,kini,1.0/norm);
    149:       kini++;
    150:     }
    151:   }
    152:   nv = ctx->bs;
    153:   BVSetActiveColumns(eps->V,0,nv);
    154:   BVSetActiveColumns(Z,0,nv);
    155:   BVCopy(eps->V,Z);
    156:   BVCopy(Z,X);

    158:   /* 3. B-orthogonalize initial vectors */
    159:   if (B) {
    160:     BVMatMult(X,B,BX);
    161:   }

    163:   /* 4. Compute initial Ritz vectors */
    164:   BVMatMult(X,A,AX);
    165:   DSSetDimensions(eps->ds,nv,0,0,0);
    166:   DSGetMat(eps->ds,DS_MAT_A,&M);
    167:   BVMatProject(AX,NULL,X,M);
    168:   DSRestoreMat(eps->ds,DS_MAT_A,&M);
    169:   DSSetIdentity(eps->ds,DS_MAT_B);
    170:   DSSetState(eps->ds,DS_STATE_RAW);
    171:   DSSolve(eps->ds,eps->eigr,eps->eigi);
    172:   DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL);
    173:   DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
    174:   DSGetMat(eps->ds,DS_MAT_X,&M);
    175:   BVMultInPlace(X,M,0,nv);
    176:   BVMultInPlace(AX,M,0,nv);
    177:   DSRestoreMat(eps->ds,DS_MAT_X,&M);

    179:   /* 5. Initialize range of active iterates */
    180:   bdone = 0;  /* finished blocks, the leading bdone*bs columns of V are eigenvectors */
    181:   nconv = 0;  /* number of converged eigenvalues in the current block */
    182:   its   = 0;  /* iterations for the current block */

    184:   /* 6. Main loop */
    185:   while (eps->reason == EPS_CONVERGED_ITERATING) {

    187:     if (ctx->lock) {
    188:       BVSetActiveColumns(R,nconv,ctx->bs);
    189:       BVSetActiveColumns(AX,nconv,ctx->bs);
    190:       if (B) {
    191:         BVSetActiveColumns(BX,nconv,ctx->bs);
    192:       }
    193:     }

    195:     /* 7. Compute residuals */
    196:     DSGetMat(eps->ds,DS_MAT_A,&M);
    197:     BVCopy(AX,R);
    198:     if (B) {
    199:       BVMult(R,-1.0,1.0,BX,M);
    200:     } else {
    201:       BVMult(R,-1.0,1.0,X,M);
    202:     }
    203:     DSRestoreMat(eps->ds,DS_MAT_A,&M);

    205:     /* 8. Compute residual norms and update index set of active iterates */
    206:     ini = (ctx->lock)? nconv: 0;
    207:     k = ini;
    208:     countc = PETSC_TRUE;
    209:     for (j=ini;j<ctx->bs;j++) {
    210:       i = bdone*ctx->bs+j;
    211:       BVGetColumn(R,j,&v);
    212:       VecNorm(v,NORM_2,&norm);
    213:       BVRestoreColumn(R,j,&v);
    214:       (*eps->converged)(eps,eps->eigr[i],eps->eigi[i],norm,&eps->errest[i],eps->convergedctx);
    215:       if (countc) {
    216:         if (eps->errest[i] < eps->tol) k++;
    217:         else countc = PETSC_FALSE;
    218:       }
    219:       if (!countc && !eps->trackall) break;
    220:     }
    221:     nconv = k;
    222:     eps->nconv = bdone*ctx->bs + nconv;
    223:     if (eps->its+its) {
    224:       EPSMonitor(eps,eps->its+its,eps->nconv,eps->eigr,eps->eigi,eps->errest,(bdone+1)*ctx->bs);
    225:     }
    226:     if (eps->nconv >= eps->nev || nconv == ctx->bs) {
    227:       BVSetActiveColumns(eps->V,bdone*ctx->bs,bdone*ctx->bs+nconv);
    228:       BVSetActiveColumns(Z,0,nconv);
    229:       BVSetActiveColumns(X,0,nconv);
    230:       BVCopy(X,eps->V);
    231:       BVCopy(X,Z);
    232:     }
    233:     if (eps->nconv >= eps->nev) eps->reason = EPS_CONVERGED_TOL;
    234:     else if (eps->its+its >= eps->max_it) eps->reason = EPS_DIVERGED_ITS;
    235:     if (eps->nconv >= eps->nev || nconv == ctx->bs) {
    236:       eps->its += its;
    237:       its = 0;
    238:     }
    239:     its++;
    240:     if (eps->reason != EPS_CONVERGED_ITERATING) break;

    242:     if (nconv == ctx->bs) {  /* block finished: lock eigenvectors and compute new R */

    244:       /* extend constraints */
    245:       BVSetActiveColumns(Y,nc+bdone*ctx->bs,nc+(bdone+1)*ctx->bs);
    246:       BVCopy(Z,Y);
    247:       for (j=0;j<ctx->bs;j++) {
    248:         BVSetActiveColumns(Y,0,nc+bdone*ctx->bs+j);
    249:         BVGetColumn(Y,nc+bdone*ctx->bs+j,&v);
    250:         BVOrthogonalizeVec(Y,v,NULL,NULL,NULL);
    251:         VecNormalize(v,NULL);
    252:         BVRestoreColumn(Y,nc+bdone*ctx->bs+j,&v);
    253:       }
    254:       BVSetActiveColumns(Y,0,nc+(bdone+1)*ctx->bs);

    256:       bdone++;
    257:       nconv = 0;

    259:       /* set new initial vectors */
    260:       BVSetActiveColumns(eps->V,bdone*ctx->bs,(bdone+1)*ctx->bs);
    261:       BVCopy(eps->V,Z);
    262:       for (j=0;j<ctx->bs;j++) {
    263:         BVGetColumn(Z,j,&v);
    264:         BVOrthogonalizeVec(Y,v,NULL,NULL,NULL);
    265:         VecNormalize(v,NULL);
    266:         BVRestoreColumn(Z,j,&v);
    267:       }
    268:       BVSetActiveColumns(X,nconv,ctx->bs);
    269:       BVSetActiveColumns(AX,nconv,ctx->bs);
    270:       BVCopy(Z,X);

    272:       /* B-orthogonalize initial vectors */
    273:       if (B) {
    274:         BVMatMult(X,B,BX);
    275:       }

    277:       /* Compute initial Ritz vectors */
    278:       nv = ctx->bs;
    279:       BVMatMult(X,A,AX);
    280:       DSSetDimensions(eps->ds,nv,0,0,0);
    281:       DSGetMat(eps->ds,DS_MAT_A,&M);
    282:       BVMatProject(AX,NULL,X,M);
    283:       DSRestoreMat(eps->ds,DS_MAT_A,&M);
    284:       DSGetMat(eps->ds,DS_MAT_B,&M);
    285:       if (B) {
    286:         BVMatProject(Z,B,Z,M);
    287:       } else {
    288:         BVDot(Z,Z,M);
    289:       }
    290:       DSRestoreMat(eps->ds,DS_MAT_B,&M);
    291:       DSSetState(eps->ds,DS_STATE_RAW);
    292:       DSSolve(eps->ds,eps->eigr+bdone*ctx->bs,eps->eigi);
    293:       DSSort(eps->ds,eps->eigr+bdone*ctx->bs,eps->eigi,NULL,NULL,NULL);
    294:       DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
    295:       DSGetMat(eps->ds,DS_MAT_X,&M);
    296:       BVMultInPlace(Z,M,0,nv);
    297:       BVMultInPlace(X,M,0,nv);
    298:       BVMultInPlace(AX,M,0,nv);
    299:       DSRestoreMat(eps->ds,DS_MAT_X,&M);

    301:       EPSMonitor(eps,eps->its+its-1,eps->nconv,eps->eigr,eps->eigi,eps->errest,(bdone+1)*ctx->bs);

    303:       if (ctx->lock) {
    304:         BVSetActiveColumns(R,nconv,ctx->bs);
    305:         BVSetActiveColumns(AX,nconv,ctx->bs);
    306:         if (B) {
    307:           BVSetActiveColumns(BX,nconv,ctx->bs);
    308:         }
    309:       }

    311:       /* compute residuals */
    312:       DSGetMat(eps->ds,DS_MAT_A,&M);
    313:       BVCopy(AX,R);
    314:       if (B) {
    315:         BVMult(R,-1.0,1.0,BX,M);
    316:       } else {
    317:         BVMult(R,-1.0,1.0,X,M);
    318:       }
    319:       DSRestoreMat(eps->ds,DS_MAT_A,&M);
    320:     }

    322:     ini = (ctx->lock)? nconv: 0;
    323:     if (ctx->lock) {
    324:       BVSetActiveColumns(R,nconv,ctx->bs);
    325:       BVSetActiveColumns(P,nconv,ctx->bs);
    326:       BVSetActiveColumns(AX,nconv,ctx->bs);
    327:       if (B) {
    328:         BVSetActiveColumns(BX,nconv,ctx->bs);
    329:       }
    330:     }

    332:     /* 9. Apply preconditioner to the residuals */
    333:     for (j=ini;j<ctx->bs;j++) {
    334:       BVGetColumn(R,j,&v);
    335:       STMatSolve(eps->st,v,w);
    336:       if (nc+bdone*ctx->bs>0) {
    337:         BVOrthogonalizeVec(Y,w,NULL,NULL,NULL);
    338:         VecNormalize(w,NULL);
    339:       }
    340:       VecCopy(w,v);
    341:       BVRestoreColumn(R,j,&v);
    342:     }

    344:     /* 11. B-orthonormalize preconditioned residuals */
    345:     BVOrthogonalize(R,NULL);

    347:     /* 13-16. B-orthonormalize conjugate directions */
    348:     if (its>1) {
    349:       BVOrthogonalize(P,NULL);
    350:     }

    352:     /* 17-23. Compute symmetric Gram matrices */
    353:     BVSetActiveColumns(Z,0,ctx->bs);
    354:     BVSetActiveColumns(X,0,ctx->bs);
    355:     BVCopy(X,Z);
    356:     BVSetActiveColumns(Z,ctx->bs,2*ctx->bs-ini);
    357:     BVCopy(R,Z);
    358:     if (its>1) {
    359:       BVSetActiveColumns(Z,2*ctx->bs-ini,3*ctx->bs-2*ini);
    360:       BVCopy(P,Z);
    361:     }

    363:     if (its>1) nv = 3*ctx->bs-2*ini;
    364:     else nv = 2*ctx->bs-ini;

    366:     BVSetActiveColumns(Z,0,nv);
    367:     DSSetDimensions(eps->ds,nv,0,0,0);
    368:     DSGetMat(eps->ds,DS_MAT_A,&M);
    369:     BVMatProject(Z,A,Z,M);
    370:     DSRestoreMat(eps->ds,DS_MAT_A,&M);
    371:     DSGetMat(eps->ds,DS_MAT_B,&M);
    372:     if (B) {
    373:       BVMatProject(Z,B,Z,M);
    374:     } else {
    375:       BVDot(Z,Z,M);
    376:     }
    377:     DSRestoreMat(eps->ds,DS_MAT_B,&M);
    378:
    379:     /* 24. Solve the generalized eigenvalue problem */
    380:     DSSetState(eps->ds,DS_STATE_RAW);
    381:     DSSolve(eps->ds,eps->eigr+bdone*ctx->bs,eps->eigi);
    382:     DSSort(eps->ds,eps->eigr+bdone*ctx->bs,eps->eigi,NULL,NULL,NULL);
    383:     DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
    384:
    385:     /* 25-33. Compute Ritz vectors */
    386:     DSGetMat(eps->ds,DS_MAT_X,&M);
    387:     BVSetActiveColumns(Z,ctx->bs,nv);
    388:     if (ctx->lock) {
    389:       BVSetActiveColumns(P,0,ctx->bs);
    390:     }
    391:     BVMult(P,1.0,0.0,Z,M);
    392:     BVCopy(P,X);
    393:     if (ctx->lock) {
    394:       BVSetActiveColumns(P,nconv,ctx->bs);
    395:     }
    396:     BVSetActiveColumns(Z,0,ctx->bs);
    397:     BVMult(X,1.0,1.0,Z,M);
    398:     if (ctx->lock) {
    399:       BVSetActiveColumns(X,nconv,ctx->bs);
    400:     }
    401:     BVMatMult(X,A,AX);
    402:     if (B) {
    403:       BVMatMult(X,B,BX);
    404:     }
    405:     DSRestoreMat(eps->ds,DS_MAT_X,&M);
    406:   }

    408:   BVDestroy(&Z);
    409:   BVDestroy(&X);
    410:   BVDestroy(&R);
    411:   BVDestroy(&P);
    412:   BVDestroy(&AX);
    413:   if (B) {
    414:     BVDestroy(&BX);
    415:   }
    416:   if (nc>0 || eps->nev>ctx->bs) {
    417:     BVDestroy(&Y);
    418:   }
    419:   return(0);
    420: }

    424: static PetscErrorCode EPSLOBPCGSetBlockSize_LOBPCG(EPS eps,PetscInt bs)
    425: {
    426:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    429:   ctx->bs = bs;
    430:   return(0);
    431: }

    435: /*@
    436:    EPSLOBPCGSetBlockSize - Sets the block size of the LOBPCG method.

    438:    Logically Collective on EPS

    440:    Input Parameters:
    441: +  eps - the eigenproblem solver context
    442: -  bs  - the block size

    444:    Options Database Key:
    445: .  -eps_lobpcg_blocksize - Sets the block size

    447:    Level: advanced

    449: .seealso: EPSLOBPCGGetBlockSize()
    450: @*/
    451: PetscErrorCode EPSLOBPCGSetBlockSize(EPS eps,PetscInt bs)
    452: {

    458:   PetscTryMethod(eps,"EPSLOBPCGSetBlockSize_C",(EPS,PetscInt),(eps,bs));
    459:   return(0);
    460: }

    464: static PetscErrorCode EPSLOBPCGGetBlockSize_LOBPCG(EPS eps,PetscInt *bs)
    465: {
    466:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    469:   *bs = ctx->bs;
    470:   return(0);
    471: }

    475: /*@
    476:    EPSLOBPCGGetBlockSize - Gets the block size used in the LOBPCG method.

    478:    Not Collective

    480:    Input Parameter:
    481: .  eps - the eigenproblem solver context

    483:    Output Parameter:
    484: .  bs - the block size

    486:    Level: advanced

    488: .seealso: EPSLOBPCGSetBlockSize()
    489: @*/
    490: PetscErrorCode EPSLOBPCGGetBlockSize(EPS eps,PetscInt *bs)
    491: {

    497:   PetscTryMethod(eps,"EPSLOBPCGGetBlockSize_C",(EPS,PetscInt*),(eps,bs));
    498:   return(0);
    499: }

    503: static PetscErrorCode EPSLOBPCGSetLocking_LOBPCG(EPS eps,PetscBool lock)
    504: {
    505:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    508:   ctx->lock = lock;
    509:   return(0);
    510: }

    514: /*@
    515:    EPSLOBPCGSetLocking - Choose between locking and non-locking variants of
    516:    the LOBPCG method.

    518:    Logically Collective on EPS

    520:    Input Parameters:
    521: +  eps  - the eigenproblem solver context
    522: -  lock - true if the locking variant must be selected

    524:    Options Database Key:
    525: .  -eps_lobpcg_locking - Sets the locking flag

    527:    Notes:
    528:    This flag refers to soft locking (converged vectors within the current
    529:    block iterate), since hard locking is always used (when nev is larger
    530:    than the block size).

    532:    Level: advanced

    534: .seealso: EPSLOBPCGGetLocking()
    535: @*/
    536: PetscErrorCode EPSLOBPCGSetLocking(EPS eps,PetscBool lock)
    537: {

    543:   PetscTryMethod(eps,"EPSLOBPCGSetLocking_C",(EPS,PetscBool),(eps,lock));
    544:   return(0);
    545: }

    549: static PetscErrorCode EPSLOBPCGGetLocking_LOBPCG(EPS eps,PetscBool *lock)
    550: {
    551:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    554:   *lock = ctx->lock;
    555:   return(0);
    556: }

    560: /*@
    561:    EPSLOBPCGGetLocking - Gets the locking flag used in the LOBPCG method.

    563:    Not Collective

    565:    Input Parameter:
    566: .  eps - the eigenproblem solver context

    568:    Output Parameter:
    569: .  lock - the locking flag

    571:    Level: advanced

    573: .seealso: EPSLOBPCGSetLocking()
    574: @*/
    575: PetscErrorCode EPSLOBPCGGetLocking(EPS eps,PetscBool *lock)
    576: {

    582:   PetscTryMethod(eps,"EPSLOBPCGGetLocking_C",(EPS,PetscBool*),(eps,lock));
    583:   return(0);
    584: }

    588: PetscErrorCode EPSView_LOBPCG(EPS eps,PetscViewer viewer)
    589: {
    591:   EPS_LOBPCG     *ctx = (EPS_LOBPCG*)eps->data;
    592:   PetscBool      isascii;

    595:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
    596:   if (isascii) {
    597:     PetscViewerASCIIPrintf(viewer,"  LOBPCG: block size %D\n",ctx->bs);
    598:     PetscViewerASCIIPrintf(viewer,"  LOBPCG: soft locking %sactivated\n",ctx->lock?"":"de");
    599:   }
    600:   return(0);
    601: }

    605: PetscErrorCode EPSSetFromOptions_LOBPCG(PetscOptions *PetscOptionsObject,EPS eps)
    606: {
    608:   PetscBool      lock,flg;
    609:   PetscInt       bs;
    610:   KSP            ksp;

    613:   PetscOptionsHead(PetscOptionsObject,"EPS LOBPCG Options");
    614:   PetscOptionsInt("-eps_lobpcg_blocksize","LOBPCG block size","EPSLOBPCGSetBlockSize",20,&bs,&flg);
    615:   if (flg) {
    616:     EPSLOBPCGSetBlockSize(eps,bs);
    617:   }
    618:   PetscOptionsBool("-eps_lobpcg_locking","Choose between locking and non-locking variants","EPSLOBPCGSetLocking",PETSC_TRUE,&lock,&flg);
    619:   if (flg) {
    620:     EPSLOBPCGSetLocking(eps,lock);
    621:   }

    623:   /* Set STPrecond as the default ST */
    624:   if (!((PetscObject)eps->st)->type_name) {
    625:     STSetType(eps->st,STPRECOND);
    626:   }

    628:   /* Set the default options of the KSP */
    629:   STGetKSP(eps->st,&ksp);
    630:   if (!((PetscObject)ksp)->type_name) {
    631:     KSPSetType(ksp,KSPPREONLY);
    632:   }
    633:   PetscOptionsTail();
    634:   return(0);
    635: }

    639: PetscErrorCode EPSDestroy_LOBPCG(EPS eps)
    640: {

    644:   PetscFree(eps->data);
    645:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetBlockSize_C",NULL);
    646:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetBlockSize_C",NULL);
    647:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetLocking_C",NULL);
    648:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetLocking_C",NULL);
    649:   return(0);
    650: }

    654: PETSC_EXTERN PetscErrorCode EPSCreate_LOBPCG(EPS eps)
    655: {
    656:   EPS_LOBPCG     *lobpcg;

    660:   PetscNewLog(eps,&lobpcg);
    661:   eps->data = (void*)lobpcg;
    662:   lobpcg->lock = PETSC_TRUE;

    664:   eps->ops->setup          = EPSSetUp_LOBPCG;
    665:   eps->ops->solve          = EPSSolve_LOBPCG;
    666:   eps->ops->setfromoptions = EPSSetFromOptions_LOBPCG;
    667:   eps->ops->destroy        = EPSDestroy_LOBPCG;
    668:   eps->ops->view           = EPSView_LOBPCG;
    669:   eps->ops->backtransform  = EPSBackTransform_Default;
    670:   STSetType(eps->st,STPRECOND);
    671:   STPrecondSetKSPHasMat(eps->st,PETSC_TRUE);
    672:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetBlockSize_C",EPSLOBPCGSetBlockSize_LOBPCG);
    673:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetBlockSize_C",EPSLOBPCGGetBlockSize_LOBPCG);
    674:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetLocking_C",EPSLOBPCGSetLocking_LOBPCG);
    675:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetLocking_C",EPSLOBPCGGetLocking_LOBPCG);
    676:   return(0);
    677: }