Date: 2022-03-31T15:29:09+00:00

Actual source code: lobpcg.c
slepc-3.17.0 2022-03-31
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:    SLEPc eigensolver: "lobpcg"

     13:    Method: Locally Optimal Block Preconditioned Conjugate Gradient

     15:    Algorithm:

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

     20:    References:

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

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

     31: #include <slepc/private/epsimpl.h>

     33: typedef struct {
     34:   PetscInt  bs;        /* block size */
     35:   PetscBool lock;      /* soft locking active/inactive */
     36:   PetscReal restart;   /* restart parameter */
     37:   PetscInt  guard;     /* number of guard vectors */
     38: } EPS_LOBPCG;

     40: PetscErrorCode EPSSetDimensions_LOBPCG(EPS eps,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
     41: {
     42:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
     43:   PetscInt   k;

     45:   k = PetscMax(3*ctx->bs,((eps->nev-1)/ctx->bs+3)*ctx->bs);
     46:   if (*ncv!=PETSC_DEFAULT) { /* ncv set */
     48:   } else *ncv = k;
     49:   if (*mpd==PETSC_DEFAULT) *mpd = 3*ctx->bs;
     51:   PetscFunctionReturn(0);
     52: }

     54: PetscErrorCode EPSSetUp_LOBPCG(EPS eps)
     55: {
     56:   EPS_LOBPCG     *ctx = (EPS_LOBPCG*)eps->data;

     58:   EPSCheckHermitianDefinite(eps);
     59:   if (!ctx->bs) ctx->bs = PetscMin(16,eps->nev);
     61:   EPSSetDimensions_LOBPCG(eps,eps->nev,&eps->ncv,&eps->mpd);
     62:   if (eps->max_it==PETSC_DEFAULT) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
     63:   if (!eps->which) eps->which = EPS_SMALLEST_REAL;
     65:   EPSCheckUnsupported(eps,EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_EXTRACTION);
     66:   EPSCheckIgnored(eps,EPS_FEATURE_BALANCE);

     68:   if (!ctx->restart) ctx->restart = 0.9;

     70:   /* number of guard vectors */
     71:   if (ctx->bs==1) ctx->guard = 0;
     72:   else ctx->guard = PetscMin((PetscInt)((1.0-ctx->restart)*ctx->bs+0.45),ctx->bs-1);

     74:   EPSAllocateSolution(eps,0);
     75:   EPS_SetInnerProduct(eps);
     76:   DSSetType(eps->ds,DSGHEP);
     77:   DSAllocate(eps->ds,eps->mpd);
     78:   EPSSetWorkVecs(eps,1);
     79:   PetscFunctionReturn(0);
     80: }

     82: PetscErrorCode EPSSolve_LOBPCG(EPS eps)
     83: {
     84:   EPS_LOBPCG     *ctx = (EPS_LOBPCG*)eps->data;
     85:   PetscInt       i,j,k,ld,nv,ini,nmat,nc,nconv,locked,its,prev=0;
     86:   PetscReal      norm;
     87:   PetscScalar    *eigr,dot;
     88:   PetscBool      breakdown,countc,flip=PETSC_FALSE,checkprecond=PETSC_FALSE;
     89:   Mat            A,B,M,V=NULL,W=NULL;
     90:   Vec            v,z,w=eps->work[0];
     91:   BV             X,Y=NULL,Z,R,P,AX,BX;
     92:   SlepcSC        sc;

     94:   DSGetLeadingDimension(eps->ds,&ld);
     95:   STGetNumMatrices(eps->st,&nmat);
     96:   STGetMatrix(eps->st,0,&A);
     97:   if (nmat>1) STGetMatrix(eps->st,1,&B);
     98:   else B = NULL;

    100:   if (eps->which==EPS_LARGEST_REAL) {  /* flip spectrum */
    101:     flip = PETSC_TRUE;
    102:     DSGetSlepcSC(eps->ds,&sc);
    103:     sc->comparison = SlepcCompareSmallestReal;
    104:   }

    106:   /* undocumented option to check for a positive-definite preconditioner (turn-off by default) */
    107:   PetscOptionsGetBool(NULL,NULL,"-eps_lobpcg_checkprecond",&checkprecond,NULL);

    109:   /* 1. Allocate memory */
    110:   PetscCalloc1(3*ctx->bs,&eigr);
    111:   BVDuplicateResize(eps->V,3*ctx->bs,&Z);
    112:   BVDuplicateResize(eps->V,ctx->bs,&X);
    113:   BVDuplicateResize(eps->V,ctx->bs,&R);
    114:   BVDuplicateResize(eps->V,ctx->bs,&P);
    115:   BVDuplicateResize(eps->V,ctx->bs,&AX);
    116:   if (B) BVDuplicateResize(eps->V,ctx->bs,&BX);
    117:   nc = eps->nds;
    118:   if (nc>0 || eps->nev>ctx->bs-ctx->guard) BVDuplicateResize(eps->V,nc+eps->nev,&Y);
    119:   if (nc>0) {
    120:     for (j=0;j<nc;j++) {
    121:       BVGetColumn(eps->V,-nc+j,&v);
    122:       BVInsertVec(Y,j,v);
    123:       BVRestoreColumn(eps->V,-nc+j,&v);
    124:     }
    125:     BVSetActiveColumns(Y,0,nc);
    126:   }

    128:   /* 2. Apply the constraints to the initial vectors */
    129:   /* 3. B-orthogonalize initial vectors */
    130:   for (k=eps->nini;k<eps->ncv-ctx->bs;k++) { /* Generate more initial vectors if necessary */
    131:     BVSetRandomColumn(eps->V,k);
    132:     BVOrthonormalizeColumn(eps->V,k,PETSC_TRUE,NULL,NULL);
    133:   }
    134:   nv = ctx->bs;
    135:   BVSetActiveColumns(eps->V,0,nv);
    136:   BVSetActiveColumns(Z,0,nv);
    137:   BVCopy(eps->V,Z);
    138:   BVCopy(Z,X);

    140:   /* 4. Compute initial Ritz vectors */
    141:   BVMatMult(X,A,AX);
    142:   DSSetDimensions(eps->ds,nv,0,0);
    143:   DSGetMat(eps->ds,DS_MAT_A,&M);
    144:   BVMatProject(AX,NULL,X,M);
    145:   if (flip) MatScale(M,-1.0);
    146:   DSRestoreMat(eps->ds,DS_MAT_A,&M);
    147:   DSSetIdentity(eps->ds,DS_MAT_B);
    148:   DSSetState(eps->ds,DS_STATE_RAW);
    149:   DSSolve(eps->ds,eigr,NULL);
    150:   DSSort(eps->ds,eigr,NULL,NULL,NULL,NULL);
    151:   DSSynchronize(eps->ds,eigr,NULL);
    152:   for (j=0;j<nv;j++) eps->eigr[j] = flip? -eigr[j]: eigr[j];
    153:   DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
    154:   DSGetMat(eps->ds,DS_MAT_X,&M);
    155:   BVMultInPlace(X,M,0,nv);
    156:   BVMultInPlace(AX,M,0,nv);
    157:   MatDestroy(&M);

    159:   /* 5. Initialize range of active iterates */
    160:   locked = 0;  /* hard-locked vectors, the leading locked columns of V are eigenvectors */
    161:   nconv  = 0;  /* number of converged eigenvalues in the current block */
    162:   its    = 0;  /* iterations for the current block */

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

    167:     if (ctx->lock) {
    168:       BVSetActiveColumns(R,nconv,ctx->bs);
    169:       BVSetActiveColumns(AX,nconv,ctx->bs);
    170:       if (B) BVSetActiveColumns(BX,nconv,ctx->bs);
    171:     }

    173:     /* 7. Compute residuals */
    174:     ini = (ctx->lock)? nconv: 0;
    175:     BVCopy(AX,R);
    176:     if (B) BVMatMult(X,B,BX);
    177:     for (j=ini;j<ctx->bs;j++) {
    178:       BVGetColumn(R,j,&v);
    179:       BVGetColumn(B?BX:X,j,&z);
    180:       VecAXPY(v,-eps->eigr[locked+j],z);
    181:       BVRestoreColumn(R,j,&v);
    182:       BVRestoreColumn(B?BX:X,j,&z);
    183:     }

    185:     /* 8. Compute residual norms and update index set of active iterates */
    186:     k = ini;
    187:     countc = PETSC_TRUE;
    188:     for (j=ini;j<ctx->bs;j++) {
    189:       i = locked+j;
    190:       BVGetColumn(R,j,&v);
    191:       VecNorm(v,NORM_2,&norm);
    192:       BVRestoreColumn(R,j,&v);
    193:       (*eps->converged)(eps,eps->eigr[i],eps->eigi[i],norm,&eps->errest[i],eps->convergedctx);
    194:       if (countc) {
    195:         if (eps->errest[i] < eps->tol) k++;
    196:         else countc = PETSC_FALSE;
    197:       }
    198:       if (!countc && !eps->trackall) break;
    199:     }
    200:     nconv = k;
    201:     eps->nconv = locked + nconv;
    202:     if (its) EPSMonitor(eps,eps->its+its,eps->nconv,eps->eigr,eps->eigi,eps->errest,locked+ctx->bs);
    203:     (*eps->stopping)(eps,eps->its+its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx);
    204:     if (eps->reason != EPS_CONVERGED_ITERATING || nconv >= ctx->bs-ctx->guard) {
    205:       BVSetActiveColumns(eps->V,locked,eps->nconv);
    206:       BVSetActiveColumns(X,0,nconv);
    207:       BVCopy(X,eps->V);
    208:     }
    209:     if (eps->reason != EPS_CONVERGED_ITERATING) {
    210:       break;
    211:     } else if (nconv >= ctx->bs-ctx->guard) {
    212:       eps->its += its-1;
    213:       its = 0;
    214:     } else its++;

    216:     if (nconv >= ctx->bs-ctx->guard) {  /* force hard locking of vectors and compute new R */

    218:       /* extend constraints */
    219:       BVSetActiveColumns(Y,nc+locked,nc+locked+nconv);
    220:       BVCopy(X,Y);
    221:       BVSetActiveColumns(Y,0,nc+locked+nconv);

    223:       /* shift work BV's */
    224:       for (j=nconv;j<ctx->bs;j++) {
    225:         BVCopyColumn(X,j,j-nconv);
    226:         BVCopyColumn(R,j,j-nconv);
    227:         BVCopyColumn(P,j,j-nconv);
    228:         BVCopyColumn(AX,j,j-nconv);
    229:         if (B) BVCopyColumn(BX,j,j-nconv);
    230:       }

    232:       /* set new initial vectors */
    233:       BVSetActiveColumns(eps->V,locked+ctx->bs,locked+ctx->bs+nconv);
    234:       BVSetActiveColumns(X,ctx->bs-nconv,ctx->bs);
    235:       BVCopy(eps->V,X);
    236:       for (j=ctx->bs-nconv;j<ctx->bs;j++) {
    237:         BVGetColumn(X,j,&v);
    238:         BVOrthogonalizeVec(Y,v,NULL,&norm,&breakdown);
    239:         if (norm>0.0 && !breakdown) VecScale(v,1.0/norm);
    240:         else {
    241:           PetscInfo(eps,"Orthogonalization of initial vector failed\n");
    242:           eps->reason = EPS_DIVERGED_BREAKDOWN;
    243:           goto diverged;
    244:         }
    245:         BVRestoreColumn(X,j,&v);
    246:       }
    247:       locked += nconv;
    248:       nconv = 0;
    249:       BVSetActiveColumns(X,nconv,ctx->bs);

    251:       /* B-orthogonalize initial vectors */
    252:       BVOrthogonalize(X,NULL);
    253:       BVSetActiveColumns(Z,nconv,ctx->bs);
    254:       BVSetActiveColumns(AX,nconv,ctx->bs);
    255:       BVCopy(X,Z);

    257:       /* compute initial Ritz vectors */
    258:       nv = ctx->bs;
    259:       BVMatMult(X,A,AX);
    260:       DSSetDimensions(eps->ds,nv,0,0);
    261:       DSGetMat(eps->ds,DS_MAT_A,&M);
    262:       BVMatProject(AX,NULL,X,M);
    263:       if (flip) MatScale(M,-1.0);
    264:       DSRestoreMat(eps->ds,DS_MAT_A,&M);
    265:       DSSetIdentity(eps->ds,DS_MAT_B);
    266:       DSSetState(eps->ds,DS_STATE_RAW);
    267:       DSSolve(eps->ds,eigr,NULL);
    268:       DSSort(eps->ds,eigr,NULL,NULL,NULL,NULL);
    269:       DSSynchronize(eps->ds,eigr,NULL);
    270:       for (j=0;j<nv;j++) if (locked+j<eps->ncv) eps->eigr[locked+j] = flip? -eigr[j]: eigr[j];
    271:       DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
    272:       DSGetMat(eps->ds,DS_MAT_X,&M);
    273:       BVMultInPlace(X,M,0,nv);
    274:       BVMultInPlace(AX,M,0,nv);
    275:       MatDestroy(&M);

    277:       continue;   /* skip the rest of the iteration */
    278:     }

    280:     ini = (ctx->lock)? nconv: 0;
    281:     if (ctx->lock) {
    282:       BVSetActiveColumns(R,nconv,ctx->bs);
    283:       BVSetActiveColumns(P,nconv,ctx->bs);
    284:       BVSetActiveColumns(AX,nconv,ctx->bs);
    285:       if (B) BVSetActiveColumns(BX,nconv,ctx->bs);
    286:     }

    288:     /* 9. Apply preconditioner to the residuals */
    289:     BVGetMat(R,&V);
    290:     if (prev != ctx->bs-ini) {
    291:       prev = ctx->bs-ini;
    292:       MatDestroy(&W);
    293:       MatDuplicate(V,MAT_SHARE_NONZERO_PATTERN,&W);
    294:     }
    295:     STApplyMat(eps->st,V,W);
    296:     if (checkprecond) {
    297:       for (j=ini;j<ctx->bs;j++) {
    298:         MatDenseGetColumnVecRead(V,j-ini,&v);
    299:         MatDenseGetColumnVecRead(W,j-ini,&w);
    300:         VecDot(v,w,&dot);
    301:         MatDenseRestoreColumnVecRead(W,j-ini,&w);
    302:         MatDenseRestoreColumnVecRead(V,j-ini,&v);
    303:         if (PetscRealPart(dot)<0.0) {
    304:           PetscInfo(eps,"The preconditioner is not positive-definite\n");
    305:           eps->reason = EPS_DIVERGED_BREAKDOWN;
    306:           goto diverged;
    307:         }
    308:       }
    309:     }
    310:     if (nc+locked>0) {
    311:       for (j=ini;j<ctx->bs;j++) {
    312:         MatDenseGetColumnVecWrite(W,j-ini,&w);
    313:         BVOrthogonalizeVec(Y,w,NULL,&norm,&breakdown);
    314:         if (norm>0.0 && !breakdown) VecScale(w,1.0/norm);
    315:         MatDenseRestoreColumnVecWrite(W,j-ini,&w);
    316:         if (norm<=0.0 || breakdown) {
    317:           PetscInfo(eps,"Orthogonalization of preconditioned residual failed\n");
    318:           eps->reason = EPS_DIVERGED_BREAKDOWN;
    319:           goto diverged;
    320:         }
    321:       }
    322:     }
    323:     MatCopy(W,V,SAME_NONZERO_PATTERN);
    324:     BVRestoreMat(R,&V);

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

    329:     /* 13-16. B-orthonormalize conjugate directions */
    330:     if (its>1) BVOrthogonalize(P,NULL);

    332:     /* 17-23. Compute symmetric Gram matrices */
    333:     BVSetActiveColumns(Z,0,ctx->bs);
    334:     BVSetActiveColumns(X,0,ctx->bs);
    335:     BVCopy(X,Z);
    336:     BVSetActiveColumns(Z,ctx->bs,2*ctx->bs-ini);
    337:     BVCopy(R,Z);
    338:     if (its>1) {
    339:       BVSetActiveColumns(Z,2*ctx->bs-ini,3*ctx->bs-2*ini);
    340:       BVCopy(P,Z);
    341:     }

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

    346:     BVSetActiveColumns(Z,0,nv);
    347:     DSSetDimensions(eps->ds,nv,0,0);
    348:     DSGetMat(eps->ds,DS_MAT_A,&M);
    349:     BVMatProject(Z,A,Z,M);
    350:     if (flip) MatScale(M,-1.0);
    351:     DSRestoreMat(eps->ds,DS_MAT_A,&M);
    352:     DSGetMat(eps->ds,DS_MAT_B,&M);
    353:     BVMatProject(Z,B,Z,M); /* covers also the case B=NULL */
    354:     DSRestoreMat(eps->ds,DS_MAT_B,&M);

    356:     /* 24. Solve the generalized eigenvalue problem */
    357:     DSSetState(eps->ds,DS_STATE_RAW);
    358:     DSSolve(eps->ds,eigr,NULL);
    359:     DSSort(eps->ds,eigr,NULL,NULL,NULL,NULL);
    360:     DSSynchronize(eps->ds,eigr,NULL);
    361:     for (j=0;j<nv;j++) if (locked+j<eps->ncv) eps->eigr[locked+j] = flip? -eigr[j]: eigr[j];
    362:     DSVectors(eps->ds,DS_MAT_X,NULL,NULL);

    364:     /* 25-33. Compute Ritz vectors */
    365:     DSGetMat(eps->ds,DS_MAT_X,&M);
    366:     BVSetActiveColumns(Z,ctx->bs,nv);
    367:     if (ctx->lock) BVSetActiveColumns(P,0,ctx->bs);
    368:     BVMult(P,1.0,0.0,Z,M);
    369:     BVCopy(P,X);
    370:     if (ctx->lock) BVSetActiveColumns(P,nconv,ctx->bs);
    371:     BVSetActiveColumns(Z,0,ctx->bs);
    372:     BVMult(X,1.0,1.0,Z,M);
    373:     if (ctx->lock) BVSetActiveColumns(X,nconv,ctx->bs);
    374:     BVMatMult(X,A,AX);
    375:     MatDestroy(&M);
    376:   }

    378: diverged:
    379:   eps->its += its;

    381:   if (flip) sc->comparison = SlepcCompareLargestReal;
    382:   PetscFree(eigr);
    383:   MatDestroy(&W);
    384:   if (V) BVRestoreMat(R,&V); /* only needed when goto diverged is reached */
    385:   BVDestroy(&Z);
    386:   BVDestroy(&X);
    387:   BVDestroy(&R);
    388:   BVDestroy(&P);
    389:   BVDestroy(&AX);
    390:   if (B) BVDestroy(&BX);
    391:   if (nc>0 || eps->nev>ctx->bs-ctx->guard) BVDestroy(&Y);
    392:   PetscFunctionReturn(0);
    393: }

    395: static PetscErrorCode EPSLOBPCGSetBlockSize_LOBPCG(EPS eps,PetscInt bs)
    396: {
    397:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    399:   if (bs == PETSC_DEFAULT || bs == PETSC_DECIDE) bs = 1;
    401:   if (ctx->bs != bs) {
    402:     ctx->bs = bs;
    403:     eps->state = EPS_STATE_INITIAL;
    404:   }
    405:   PetscFunctionReturn(0);
    406: }

    408: /*@
    409:    EPSLOBPCGSetBlockSize - Sets the block size of the LOBPCG method.

    411:    Logically Collective on eps

    413:    Input Parameters:
    414: +  eps - the eigenproblem solver context
    415: -  bs  - the block size

    417:    Options Database Key:
    418: .  -eps_lobpcg_blocksize - Sets the block size

    420:    Level: advanced

    422: .seealso: EPSLOBPCGGetBlockSize()
    423: @*/
    424: PetscErrorCode EPSLOBPCGSetBlockSize(EPS eps,PetscInt bs)
    425: {
    428:   PetscTryMethod(eps,"EPSLOBPCGSetBlockSize_C",(EPS,PetscInt),(eps,bs));
    429:   PetscFunctionReturn(0);
    430: }

    432: static PetscErrorCode EPSLOBPCGGetBlockSize_LOBPCG(EPS eps,PetscInt *bs)
    433: {
    434:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    436:   *bs = ctx->bs;
    437:   PetscFunctionReturn(0);
    438: }

    440: /*@
    441:    EPSLOBPCGGetBlockSize - Gets the block size used in the LOBPCG method.

    443:    Not Collective

    445:    Input Parameter:
    446: .  eps - the eigenproblem solver context

    448:    Output Parameter:
    449: .  bs - the block size

    451:    Level: advanced

    453: .seealso: EPSLOBPCGSetBlockSize()
    454: @*/
    455: PetscErrorCode EPSLOBPCGGetBlockSize(EPS eps,PetscInt *bs)
    456: {
    459:   PetscUseMethod(eps,"EPSLOBPCGGetBlockSize_C",(EPS,PetscInt*),(eps,bs));
    460:   PetscFunctionReturn(0);
    461: }

    463: static PetscErrorCode EPSLOBPCGSetRestart_LOBPCG(EPS eps,PetscReal restart)
    464: {
    465:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    467:   if (restart==PETSC_DEFAULT) restart = 0.9;
    469:   if (restart != ctx->restart) {
    470:     ctx->restart = restart;
    471:     eps->state = EPS_STATE_INITIAL;
    472:   }
    473:   PetscFunctionReturn(0);
    474: }

    476: /*@
    477:    EPSLOBPCGSetRestart - Sets the restart parameter for the LOBPCG method.

    479:    Logically Collective on eps

    481:    Input Parameters:
    482: +  eps - the eigenproblem solver context
    483: -  restart - the percentage of the block of vectors to force a restart

    485:    Options Database Key:
    486: .  -eps_lobpcg_restart - Sets the restart parameter

    488:    Notes:
    489:    The meaning of this parameter is the proportion of vectors within the
    490:    current block iterate that must have converged in order to force a
    491:    restart with hard locking.
    492:    Allowed values are in the range [0.1,1.0]. The default is 0.9.

    494:    Level: advanced

    496: .seealso: EPSLOBPCGGetRestart()
    497: @*/
    498: PetscErrorCode EPSLOBPCGSetRestart(EPS eps,PetscReal restart)
    499: {
    502:   PetscTryMethod(eps,"EPSLOBPCGSetRestart_C",(EPS,PetscReal),(eps,restart));
    503:   PetscFunctionReturn(0);
    504: }

    506: static PetscErrorCode EPSLOBPCGGetRestart_LOBPCG(EPS eps,PetscReal *restart)
    507: {
    508:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    510:   *restart = ctx->restart;
    511:   PetscFunctionReturn(0);
    512: }

    514: /*@
    515:    EPSLOBPCGGetRestart - Gets the restart parameter used in the LOBPCG method.

    517:    Not Collective

    519:    Input Parameter:
    520: .  eps - the eigenproblem solver context

    522:    Output Parameter:
    523: .  restart - the restart parameter

    525:    Level: advanced

    527: .seealso: EPSLOBPCGSetRestart()
    528: @*/
    529: PetscErrorCode EPSLOBPCGGetRestart(EPS eps,PetscReal *restart)
    530: {
    533:   PetscUseMethod(eps,"EPSLOBPCGGetRestart_C",(EPS,PetscReal*),(eps,restart));
    534:   PetscFunctionReturn(0);
    535: }

    537: static PetscErrorCode EPSLOBPCGSetLocking_LOBPCG(EPS eps,PetscBool lock)
    538: {
    539:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    541:   ctx->lock = lock;
    542:   PetscFunctionReturn(0);
    543: }

    545: /*@
    546:    EPSLOBPCGSetLocking - Choose between locking and non-locking variants of
    547:    the LOBPCG method.

    549:    Logically Collective on eps

    551:    Input Parameters:
    552: +  eps  - the eigenproblem solver context
    553: -  lock - true if the locking variant must be selected

    555:    Options Database Key:
    556: .  -eps_lobpcg_locking - Sets the locking flag

    558:    Notes:
    559:    This flag refers to soft locking (converged vectors within the current
    560:    block iterate), since hard locking is always used (when nev is larger
    561:    than the block size).

    563:    Level: advanced

    565: .seealso: EPSLOBPCGGetLocking()
    566: @*/
    567: PetscErrorCode EPSLOBPCGSetLocking(EPS eps,PetscBool lock)
    568: {
    571:   PetscTryMethod(eps,"EPSLOBPCGSetLocking_C",(EPS,PetscBool),(eps,lock));
    572:   PetscFunctionReturn(0);
    573: }

    575: static PetscErrorCode EPSLOBPCGGetLocking_LOBPCG(EPS eps,PetscBool *lock)
    576: {
    577:   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;

    579:   *lock = ctx->lock;
    580:   PetscFunctionReturn(0);
    581: }

    583: /*@
    584:    EPSLOBPCGGetLocking - Gets the locking flag used in the LOBPCG method.

    586:    Not Collective

    588:    Input Parameter:
    589: .  eps - the eigenproblem solver context

    591:    Output Parameter:
    592: .  lock - the locking flag

    594:    Level: advanced

    596: .seealso: EPSLOBPCGSetLocking()
    597: @*/
    598: PetscErrorCode EPSLOBPCGGetLocking(EPS eps,PetscBool *lock)
    599: {
    602:   PetscUseMethod(eps,"EPSLOBPCGGetLocking_C",(EPS,PetscBool*),(eps,lock));
    603:   PetscFunctionReturn(0);
    604: }

    606: PetscErrorCode EPSView_LOBPCG(EPS eps,PetscViewer viewer)
    607: {
    608:   EPS_LOBPCG     *ctx = (EPS_LOBPCG*)eps->data;
    609:   PetscBool      isascii;

    611:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
    612:   if (isascii) {
    613:     PetscViewerASCIIPrintf(viewer,"  block size %" PetscInt_FMT "\n",ctx->bs);
    614:     PetscViewerASCIIPrintf(viewer,"  restart parameter=%g (using %" PetscInt_FMT " guard vectors)\n",(double)ctx->restart,ctx->guard);
    615:     PetscViewerASCIIPrintf(viewer,"  soft locking %sactivated\n",ctx->lock?"":"de");
    616:   }
    617:   PetscFunctionReturn(0);
    618: }

    620: PetscErrorCode EPSSetFromOptions_LOBPCG(PetscOptionItems *PetscOptionsObject,EPS eps)
    621: {
    622:   PetscBool      lock,flg;
    623:   PetscInt       bs;
    624:   PetscReal      restart;

    626:   PetscOptionsHead(PetscOptionsObject,"EPS LOBPCG Options");

    628:     PetscOptionsInt("-eps_lobpcg_blocksize","Block size","EPSLOBPCGSetBlockSize",20,&bs,&flg);
    629:     if (flg) EPSLOBPCGSetBlockSize(eps,bs);

    631:     PetscOptionsReal("-eps_lobpcg_restart","Percentage of the block of vectors to force a restart","EPSLOBPCGSetRestart",0.5,&restart,&flg);
    632:     if (flg) EPSLOBPCGSetRestart(eps,restart);

    634:     PetscOptionsBool("-eps_lobpcg_locking","Choose between locking and non-locking variants","EPSLOBPCGSetLocking",PETSC_TRUE,&lock,&flg);
    635:     if (flg) EPSLOBPCGSetLocking(eps,lock);

    637:   PetscOptionsTail();
    638:   PetscFunctionReturn(0);
    639: }

    641: PetscErrorCode EPSDestroy_LOBPCG(EPS eps)
    642: {
    643:   PetscFree(eps->data);
    644:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetBlockSize_C",NULL);
    645:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetBlockSize_C",NULL);
    646:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetRestart_C",NULL);
    647:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetRestart_C",NULL);
    648:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetLocking_C",NULL);
    649:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetLocking_C",NULL);
    650:   PetscFunctionReturn(0);
    651: }

    653: SLEPC_EXTERN PetscErrorCode EPSCreate_LOBPCG(EPS eps)
    654: {
    655:   EPS_LOBPCG     *lobpcg;

    657:   PetscNewLog(eps,&lobpcg);
    658:   eps->data = (void*)lobpcg;
    659:   lobpcg->lock = PETSC_TRUE;

    661:   eps->useds = PETSC_TRUE;
    662:   eps->categ = EPS_CATEGORY_PRECOND;

    664:   eps->ops->solve          = EPSSolve_LOBPCG;
    665:   eps->ops->setup          = EPSSetUp_LOBPCG;
    666:   eps->ops->setupsort      = EPSSetUpSort_Default;
    667:   eps->ops->setfromoptions = EPSSetFromOptions_LOBPCG;
    668:   eps->ops->destroy        = EPSDestroy_LOBPCG;
    669:   eps->ops->view           = EPSView_LOBPCG;
    670:   eps->ops->backtransform  = EPSBackTransform_Default;
    671:   eps->ops->setdefaultst   = EPSSetDefaultST_GMRES;

    673:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetBlockSize_C",EPSLOBPCGSetBlockSize_LOBPCG);
    674:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetBlockSize_C",EPSLOBPCGGetBlockSize_LOBPCG);
    675:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetRestart_C",EPSLOBPCGSetRestart_LOBPCG);
    676:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetRestart_C",EPSLOBPCGGetRestart_LOBPCG);
    677:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetLocking_C",EPSLOBPCGSetLocking_LOBPCG);
    678:   PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetLocking_C",EPSLOBPCGGetLocking_LOBPCG);
    679:   PetscFunctionReturn(0);
    680: }