LCOV - code coverage report
Current view: top level - eps/impls/cg/lobpcg - lobpcg.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 369 395 93.4 %
Date: 2024-12-18 00:42:09 Functions: 18 19 94.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3             :    SLEPc - Scalable Library for Eigenvalue Problem Computations
       4             :    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
       5             : 
       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"
      12             : 
      13             :    Method: Locally Optimal Block Preconditioned Conjugate Gradient
      14             : 
      15             :    Algorithm:
      16             : 
      17             :        LOBPCG with soft and hard locking. Follows the implementation
      18             :        in BLOPEX [2].
      19             : 
      20             :    References:
      21             : 
      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.
      25             : 
      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             : */
      30             : 
      31             : #include <slepc/private/epsimpl.h>                /*I "slepceps.h" I*/
      32             : 
      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;
      39             : 
      40          29 : static PetscErrorCode EPSSetDimensions_LOBPCG(EPS eps,PetscInt *nev,PetscInt *ncv,PetscInt *mpd)
      41             : {
      42          29 :   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
      43          29 :   PetscInt   k;
      44             : 
      45          29 :   PetscFunctionBegin;
      46          29 :   if (*nev==0) *nev = 1;
      47          29 :   k = PetscMax(3*ctx->bs,((*nev-1)/ctx->bs+3)*ctx->bs);
      48          29 :   if (*ncv!=PETSC_DETERMINE) { /* ncv set */
      49          10 :     PetscCheck(*ncv>=k,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"The value of ncv is not sufficiently large");
      50          19 :   } else *ncv = k;
      51          29 :   if (*mpd==PETSC_DETERMINE) *mpd = 3*ctx->bs;
      52           6 :   else PetscCheck(*mpd==3*ctx->bs,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"This solver does not allow a value of mpd different from 3*blocksize");
      53          29 :   PetscFunctionReturn(PETSC_SUCCESS);
      54             : }
      55             : 
      56          29 : static PetscErrorCode EPSSetUp_LOBPCG(EPS eps)
      57             : {
      58          29 :   EPS_LOBPCG     *ctx = (EPS_LOBPCG*)eps->data;
      59             : 
      60          29 :   PetscFunctionBegin;
      61          29 :   EPSCheckHermitianDefinite(eps);
      62          29 :   EPSCheckNotStructured(eps);
      63          42 :   if (!ctx->bs) ctx->bs = PetscMin(16,eps->nev?eps->nev:1);
      64          29 :   PetscCheck(eps->n-eps->nds>=5*ctx->bs,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"The problem size is too small relative to the block size");
      65          29 :   PetscCall(EPSSetDimensions_LOBPCG(eps,&eps->nev,&eps->ncv,&eps->mpd));
      66          29 :   if (eps->max_it==PETSC_DETERMINE) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
      67          29 :   if (!eps->which) eps->which = EPS_SMALLEST_REAL;
      68          29 :   PetscCheck(eps->which==EPS_SMALLEST_REAL || eps->which==EPS_LARGEST_REAL,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver supports only smallest real or largest real eigenvalues");
      69          29 :   EPSCheckUnsupported(eps,EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_EXTRACTION | EPS_FEATURE_THRESHOLD);
      70          29 :   EPSCheckIgnored(eps,EPS_FEATURE_BALANCE);
      71             : 
      72          29 :   if (!ctx->restart) ctx->restart = 0.9;
      73             : 
      74             :   /* number of guard vectors */
      75          29 :   if (ctx->bs==1) ctx->guard = 0;
      76          25 :   else ctx->guard = PetscMin((PetscInt)((1.0-ctx->restart)*ctx->bs+0.45),ctx->bs-1);
      77             : 
      78          29 :   PetscCall(EPSAllocateSolution(eps,0));
      79          29 :   PetscCall(EPS_SetInnerProduct(eps));
      80          29 :   PetscCall(DSSetType(eps->ds,DSGHEP));
      81          29 :   PetscCall(DSAllocate(eps->ds,eps->mpd));
      82          29 :   PetscCall(EPSSetWorkVecs(eps,1));
      83          29 :   PetscFunctionReturn(PETSC_SUCCESS);
      84             : }
      85             : 
      86          29 : static PetscErrorCode EPSSolve_LOBPCG(EPS eps)
      87             : {
      88          29 :   EPS_LOBPCG     *ctx = (EPS_LOBPCG*)eps->data;
      89          29 :   PetscInt       i,j,k,nv,ini,nmat,nc,nconv,locked,its,prev=0;
      90          29 :   PetscReal      norm;
      91          29 :   PetscScalar    *eigr,dot;
      92          29 :   PetscBool      breakdown,countc,flip=PETSC_FALSE,checkprecond=PETSC_FALSE;
      93          29 :   Mat            A,B,M,V=NULL,W=NULL;
      94          29 :   Vec            v,z,w=eps->work[0];
      95          29 :   BV             X,Y=NULL,Z,R,P,AX,BX;
      96          29 :   SlepcSC        sc;
      97             : 
      98          29 :   PetscFunctionBegin;
      99          29 :   PetscCall(STGetNumMatrices(eps->st,&nmat));
     100          29 :   PetscCall(STGetMatrix(eps->st,0,&A));
     101          29 :   if (nmat>1) PetscCall(STGetMatrix(eps->st,1,&B));
     102          20 :   else B = NULL;
     103             : 
     104          29 :   if (eps->which==EPS_LARGEST_REAL) {  /* flip spectrum */
     105           2 :     flip = PETSC_TRUE;
     106           2 :     PetscCall(DSGetSlepcSC(eps->ds,&sc));
     107           2 :     sc->comparison = SlepcCompareSmallestReal;
     108             :   }
     109             : 
     110             :   /* undocumented option to check for a positive-definite preconditioner (turn-off by default) */
     111          29 :   PetscCall(PetscOptionsGetBool(NULL,NULL,"-eps_lobpcg_checkprecond",&checkprecond,NULL));
     112             : 
     113             :   /* 1. Allocate memory */
     114          29 :   PetscCall(PetscCalloc1(3*ctx->bs,&eigr));
     115          29 :   PetscCall(BVDuplicateResize(eps->V,3*ctx->bs,&Z));
     116          29 :   PetscCall(BVDuplicateResize(eps->V,ctx->bs,&X));
     117          29 :   PetscCall(BVDuplicateResize(eps->V,ctx->bs,&R));
     118          29 :   PetscCall(BVDuplicateResize(eps->V,ctx->bs,&P));
     119          29 :   PetscCall(BVDuplicateResize(eps->V,ctx->bs,&AX));
     120          29 :   if (B) PetscCall(BVDuplicateResize(eps->V,ctx->bs,&BX));
     121          29 :   nc = eps->nds;
     122          29 :   if (nc>0 || eps->nev>ctx->bs-ctx->guard) PetscCall(BVDuplicateResize(eps->V,nc+eps->nev,&Y));
     123          29 :   if (nc>0) {
     124           5 :     for (j=0;j<nc;j++) {
     125           3 :       PetscCall(BVGetColumn(eps->V,-nc+j,&v));
     126           3 :       PetscCall(BVInsertVec(Y,j,v));
     127           3 :       PetscCall(BVRestoreColumn(eps->V,-nc+j,&v));
     128             :     }
     129           2 :     PetscCall(BVSetActiveColumns(Y,0,nc));
     130             :   }
     131             : 
     132             :   /* 2. Apply the constraints to the initial vectors */
     133             :   /* 3. B-orthogonalize initial vectors */
     134         302 :   for (k=eps->nini;k<eps->ncv-ctx->bs;k++) { /* Generate more initial vectors if necessary */
     135         273 :     PetscCall(BVSetRandomColumn(eps->V,k));
     136         273 :     PetscCall(BVOrthonormalizeColumn(eps->V,k,PETSC_TRUE,NULL,NULL));
     137             :   }
     138          29 :   nv = ctx->bs;
     139          29 :   PetscCall(BVSetActiveColumns(eps->V,0,nv));
     140          29 :   PetscCall(BVSetActiveColumns(Z,0,nv));
     141          29 :   PetscCall(BVCopy(eps->V,Z));
     142          29 :   PetscCall(BVCopy(Z,X));
     143             : 
     144             :   /* 4. Compute initial Ritz vectors */
     145          29 :   PetscCall(BVMatMult(X,A,AX));
     146          29 :   PetscCall(DSSetDimensions(eps->ds,nv,0,0));
     147          29 :   PetscCall(DSGetMat(eps->ds,DS_MAT_A,&M));
     148          29 :   PetscCall(BVMatProject(AX,NULL,X,M));
     149          29 :   if (flip) PetscCall(MatScale(M,-1.0));
     150          29 :   PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&M));
     151          29 :   PetscCall(DSSetIdentity(eps->ds,DS_MAT_B));
     152          29 :   PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
     153          29 :   PetscCall(DSSolve(eps->ds,eigr,NULL));
     154          29 :   PetscCall(DSSort(eps->ds,eigr,NULL,NULL,NULL,NULL));
     155          29 :   PetscCall(DSSynchronize(eps->ds,eigr,NULL));
     156         137 :   for (j=0;j<nv;j++) eps->eigr[j] = flip? -eigr[j]: eigr[j];
     157          29 :   PetscCall(DSVectors(eps->ds,DS_MAT_X,NULL,NULL));
     158          29 :   PetscCall(DSGetMat(eps->ds,DS_MAT_X,&M));
     159          29 :   PetscCall(BVMultInPlace(X,M,0,nv));
     160          29 :   PetscCall(BVMultInPlace(AX,M,0,nv));
     161          29 :   PetscCall(DSRestoreMat(eps->ds,DS_MAT_X,&M));
     162             : 
     163             :   /* 5. Initialize range of active iterates */
     164             :   locked = 0;  /* hard-locked vectors, the leading locked columns of V are eigenvectors */
     165             :   nconv  = 0;  /* number of converged eigenvalues in the current block */
     166             :   its    = 0;  /* iterations for the current block */
     167             : 
     168             :   /* 6. Main loop */
     169        1693 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     170             : 
     171        1693 :     if (ctx->lock) {
     172        1351 :       PetscCall(BVSetActiveColumns(R,nconv,ctx->bs));
     173        1351 :       PetscCall(BVSetActiveColumns(AX,nconv,ctx->bs));
     174        1351 :       if (B) PetscCall(BVSetActiveColumns(BX,nconv,ctx->bs));
     175             :     }
     176             : 
     177             :     /* 7. Compute residuals */
     178        1693 :     ini = (ctx->lock)? nconv: 0;
     179        1693 :     PetscCall(BVCopy(AX,R));
     180        1693 :     if (B) PetscCall(BVMatMult(X,B,BX));
     181        6561 :     for (j=ini;j<ctx->bs;j++) {
     182        4868 :       PetscCall(BVGetColumn(R,j,&v));
     183        4868 :       PetscCall(BVGetColumn(B?BX:X,j,&z));
     184        4868 :       PetscCall(VecAXPY(v,-eps->eigr[locked+j],z));
     185        4868 :       PetscCall(BVRestoreColumn(R,j,&v));
     186        4868 :       PetscCall(BVRestoreColumn(B?BX:X,j,&z));
     187             :     }
     188             : 
     189             :     /* 8. Compute residual norms and update index set of active iterates */
     190             :     k = ini;
     191             :     countc = PETSC_TRUE;
     192        1915 :     for (j=ini;j<ctx->bs;j++) {
     193        1889 :       i = locked+j;
     194        1889 :       PetscCall(BVGetColumn(R,j,&v));
     195        1889 :       PetscCall(VecNorm(v,NORM_2,&norm));
     196        1889 :       PetscCall(BVRestoreColumn(R,j,&v));
     197        1889 :       PetscCall((*eps->converged)(eps,eps->eigr[i],eps->eigi[i],norm,&eps->errest[i],eps->convergedctx));
     198        1889 :       if (countc) {
     199        1889 :         if (eps->errest[i] < eps->tol) k++;
     200             :         else countc = PETSC_FALSE;
     201             :       }
     202        1889 :       if (!countc && !eps->trackall) break;
     203             :     }
     204        1693 :     nconv = k;
     205        1693 :     eps->nconv = locked + nconv;
     206        1693 :     if (its) PetscCall(EPSMonitor(eps,eps->its+its,eps->nconv,eps->eigr,eps->eigi,eps->errest,locked+ctx->bs));
     207        1693 :     PetscCall((*eps->stopping)(eps,eps->its+its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx));
     208        1693 :     if (eps->reason != EPS_CONVERGED_ITERATING || nconv >= ctx->bs-ctx->guard) {
     209          35 :       PetscCall(BVSetActiveColumns(eps->V,locked,eps->nconv));
     210          35 :       PetscCall(BVSetActiveColumns(X,0,nconv));
     211          35 :       PetscCall(BVCopy(X,eps->V));
     212             :     }
     213        1693 :     if (eps->reason != EPS_CONVERGED_ITERATING) {
     214             :       break;
     215        1664 :     } else if (nconv >= ctx->bs-ctx->guard) {
     216           6 :       eps->its += its-1;
     217           6 :       its = 0;
     218        1658 :     } else its++;
     219             : 
     220        1664 :     if (nconv >= ctx->bs-ctx->guard) {  /* force hard locking of vectors and compute new R */
     221             : 
     222             :       /* extend constraints */
     223           6 :       PetscCall(BVSetActiveColumns(Y,nc+locked,nc+locked+nconv));
     224           6 :       PetscCall(BVCopy(X,Y));
     225           6 :       PetscCall(BVSetActiveColumns(Y,0,nc+locked+nconv));
     226             : 
     227             :       /* shift work BV's */
     228           9 :       for (j=nconv;j<ctx->bs;j++) {
     229           3 :         PetscCall(BVCopyColumn(X,j,j-nconv));
     230           3 :         PetscCall(BVCopyColumn(R,j,j-nconv));
     231           3 :         PetscCall(BVCopyColumn(P,j,j-nconv));
     232           3 :         PetscCall(BVCopyColumn(AX,j,j-nconv));
     233           3 :         if (B) PetscCall(BVCopyColumn(BX,j,j-nconv));
     234             :       }
     235             : 
     236             :       /* set new initial vectors */
     237           6 :       PetscCall(BVSetActiveColumns(eps->V,locked+ctx->bs,locked+ctx->bs+nconv));
     238           6 :       PetscCall(BVSetActiveColumns(X,ctx->bs-nconv,ctx->bs));
     239           6 :       PetscCall(BVCopy(eps->V,X));
     240          28 :       for (j=ctx->bs-nconv;j<ctx->bs;j++) {
     241          22 :         PetscCall(BVGetColumn(X,j,&v));
     242          22 :         PetscCall(BVOrthogonalizeVec(Y,v,NULL,&norm,&breakdown));
     243          22 :         if (norm>0.0 && !breakdown) PetscCall(VecScale(v,1.0/norm));
     244             :         else {
     245           0 :           PetscCall(PetscInfo(eps,"Orthogonalization of initial vector failed\n"));
     246           0 :           eps->reason = EPS_DIVERGED_BREAKDOWN;
     247           0 :           goto diverged;
     248             :         }
     249          22 :         PetscCall(BVRestoreColumn(X,j,&v));
     250             :       }
     251           6 :       locked += nconv;
     252           6 :       nconv = 0;
     253           6 :       PetscCall(BVSetActiveColumns(X,nconv,ctx->bs));
     254             : 
     255             :       /* B-orthogonalize initial vectors */
     256           6 :       PetscCall(BVOrthogonalize(X,NULL));
     257           6 :       PetscCall(BVSetActiveColumns(Z,nconv,ctx->bs));
     258           6 :       PetscCall(BVSetActiveColumns(AX,nconv,ctx->bs));
     259           6 :       PetscCall(BVCopy(X,Z));
     260             : 
     261             :       /* compute initial Ritz vectors */
     262           6 :       nv = ctx->bs;
     263           6 :       PetscCall(BVMatMult(X,A,AX));
     264           6 :       PetscCall(DSSetDimensions(eps->ds,nv,0,0));
     265           6 :       PetscCall(DSGetMat(eps->ds,DS_MAT_A,&M));
     266           6 :       PetscCall(BVMatProject(AX,NULL,X,M));
     267           6 :       if (flip) PetscCall(MatScale(M,-1.0));
     268           6 :       PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&M));
     269           6 :       PetscCall(DSSetIdentity(eps->ds,DS_MAT_B));
     270           6 :       PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
     271           6 :       PetscCall(DSSolve(eps->ds,eigr,NULL));
     272           6 :       PetscCall(DSSort(eps->ds,eigr,NULL,NULL,NULL,NULL));
     273           6 :       PetscCall(DSSynchronize(eps->ds,eigr,NULL));
     274          31 :       for (j=0;j<nv;j++) if (locked+j<eps->ncv) eps->eigr[locked+j] = flip? -eigr[j]: eigr[j];
     275           6 :       PetscCall(DSVectors(eps->ds,DS_MAT_X,NULL,NULL));
     276           6 :       PetscCall(DSGetMat(eps->ds,DS_MAT_X,&M));
     277           6 :       PetscCall(BVMultInPlace(X,M,0,nv));
     278           6 :       PetscCall(BVMultInPlace(AX,M,0,nv));
     279           6 :       PetscCall(DSRestoreMat(eps->ds,DS_MAT_X,&M));
     280             : 
     281           6 :       continue;   /* skip the rest of the iteration */
     282             :     }
     283             : 
     284        1658 :     ini = (ctx->lock)? nconv: 0;
     285        1658 :     if (ctx->lock) {
     286        1320 :       PetscCall(BVSetActiveColumns(R,nconv,ctx->bs));
     287        1320 :       PetscCall(BVSetActiveColumns(P,nconv,ctx->bs));
     288        1320 :       PetscCall(BVSetActiveColumns(AX,nconv,ctx->bs));
     289        1320 :       if (B) PetscCall(BVSetActiveColumns(BX,nconv,ctx->bs));
     290             :     }
     291             : 
     292             :     /* 9. Apply preconditioner to the residuals */
     293        1658 :     PetscCall(BVGetMat(R,&V));
     294        1658 :     if (prev != ctx->bs-ini) {
     295          89 :       prev = ctx->bs-ini;
     296          89 :       PetscCall(MatDestroy(&W));
     297          89 :       PetscCall(MatDuplicate(V,MAT_SHARE_NONZERO_PATTERN,&W));
     298             :     }
     299        1658 :     PetscCall(STApplyMat(eps->st,V,W));
     300        1658 :     if (checkprecond) {
     301           0 :       for (j=ini;j<ctx->bs;j++) {
     302           0 :         PetscCall(MatDenseGetColumnVecRead(V,j-ini,&v));
     303           0 :         PetscCall(MatDenseGetColumnVecRead(W,j-ini,&w));
     304           0 :         PetscCall(VecDot(v,w,&dot));
     305           0 :         PetscCall(MatDenseRestoreColumnVecRead(W,j-ini,&w));
     306           0 :         PetscCall(MatDenseRestoreColumnVecRead(V,j-ini,&v));
     307           0 :         if (PetscRealPart(dot)<0.0) {
     308           0 :           PetscCall(PetscInfo(eps,"The preconditioner is not positive-definite\n"));
     309           0 :           eps->reason = EPS_DIVERGED_BREAKDOWN;
     310           0 :           goto diverged;
     311             :         }
     312             :       }
     313             :     }
     314        1658 :     if (nc+locked>0) {
     315        1308 :       for (j=ini;j<ctx->bs;j++) {
     316        1005 :         PetscCall(MatDenseGetColumnVecWrite(W,j-ini,&w));
     317        1005 :         PetscCall(BVOrthogonalizeVec(Y,w,NULL,&norm,&breakdown));
     318        1005 :         if (norm>0.0 && !breakdown) PetscCall(VecScale(w,1.0/norm));
     319        1005 :         PetscCall(MatDenseRestoreColumnVecWrite(W,j-ini,&w));
     320        1005 :         if (norm<=0.0 || breakdown) {
     321           0 :           PetscCall(PetscInfo(eps,"Orthogonalization of preconditioned residual failed\n"));
     322           0 :           eps->reason = EPS_DIVERGED_BREAKDOWN;
     323           0 :           goto diverged;
     324             :         }
     325             :       }
     326             :     }
     327        1658 :     PetscCall(MatCopy(W,V,SAME_NONZERO_PATTERN));
     328        1658 :     PetscCall(BVRestoreMat(R,&V));
     329             : 
     330             :     /* 11. B-orthonormalize preconditioned residuals */
     331        1658 :     PetscCall(BVOrthogonalize(R,NULL));
     332             : 
     333             :     /* 13-16. B-orthonormalize conjugate directions */
     334        1658 :     if (its>1) PetscCall(BVOrthogonalize(P,NULL));
     335             : 
     336             :     /* 17-23. Compute symmetric Gram matrices */
     337        1658 :     PetscCall(BVSetActiveColumns(Z,0,ctx->bs));
     338        1658 :     PetscCall(BVSetActiveColumns(X,0,ctx->bs));
     339        1658 :     PetscCall(BVCopy(X,Z));
     340        1658 :     PetscCall(BVSetActiveColumns(Z,ctx->bs,2*ctx->bs-ini));
     341        1658 :     PetscCall(BVCopy(R,Z));
     342        1658 :     if (its>1) {
     343        1624 :       PetscCall(BVSetActiveColumns(Z,2*ctx->bs-ini,3*ctx->bs-2*ini));
     344        1624 :       PetscCall(BVCopy(P,Z));
     345             :     }
     346             : 
     347        1658 :     if (its>1) nv = 3*ctx->bs-2*ini;
     348          34 :     else nv = 2*ctx->bs-ini;
     349             : 
     350        1658 :     PetscCall(BVSetActiveColumns(Z,0,nv));
     351        1658 :     PetscCall(DSSetDimensions(eps->ds,nv,0,0));
     352        1658 :     PetscCall(DSGetMat(eps->ds,DS_MAT_A,&M));
     353        1658 :     PetscCall(BVMatProject(Z,A,Z,M));
     354        1658 :     if (flip) PetscCall(MatScale(M,-1.0));
     355        1658 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&M));
     356        1658 :     PetscCall(DSGetMat(eps->ds,DS_MAT_B,&M));
     357        1658 :     PetscCall(BVMatProject(Z,B,Z,M)); /* covers also the case B=NULL */
     358        1658 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_B,&M));
     359             : 
     360             :     /* 24. Solve the generalized eigenvalue problem */
     361        1658 :     PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
     362        1658 :     PetscCall(DSSolve(eps->ds,eigr,NULL));
     363        1658 :     PetscCall(DSSort(eps->ds,eigr,NULL,NULL,NULL,NULL));
     364        1658 :     PetscCall(DSSynchronize(eps->ds,eigr,NULL));
     365       16692 :     for (j=0;j<nv;j++) if (locked+j<eps->ncv) eps->eigr[locked+j] = flip? -eigr[j]: eigr[j];
     366        1658 :     PetscCall(DSVectors(eps->ds,DS_MAT_X,NULL,NULL));
     367             : 
     368             :     /* 25-33. Compute Ritz vectors */
     369        1658 :     PetscCall(DSGetMat(eps->ds,DS_MAT_X,&M));
     370        1658 :     PetscCall(BVSetActiveColumns(Z,ctx->bs,nv));
     371        1658 :     if (ctx->lock) PetscCall(BVSetActiveColumns(P,0,ctx->bs));
     372        1658 :     PetscCall(BVMult(P,1.0,0.0,Z,M));
     373        1658 :     PetscCall(BVCopy(P,X));
     374        1658 :     if (ctx->lock) PetscCall(BVSetActiveColumns(P,nconv,ctx->bs));
     375        1658 :     PetscCall(BVSetActiveColumns(Z,0,ctx->bs));
     376        1658 :     PetscCall(BVMult(X,1.0,1.0,Z,M));
     377        1658 :     if (ctx->lock) PetscCall(BVSetActiveColumns(X,nconv,ctx->bs));
     378        1658 :     PetscCall(BVMatMult(X,A,AX));
     379        3351 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_X,&M));
     380             :   }
     381             : 
     382          29 : diverged:
     383          29 :   eps->its += its;
     384             : 
     385          29 :   if (flip) sc->comparison = SlepcCompareLargestReal;
     386          29 :   PetscCall(PetscFree(eigr));
     387          29 :   PetscCall(MatDestroy(&W));
     388          29 :   if (V) PetscCall(BVRestoreMat(R,&V)); /* only needed when goto diverged is reached */
     389          29 :   PetscCall(BVDestroy(&Z));
     390          29 :   PetscCall(BVDestroy(&X));
     391          29 :   PetscCall(BVDestroy(&R));
     392          29 :   PetscCall(BVDestroy(&P));
     393          29 :   PetscCall(BVDestroy(&AX));
     394          29 :   if (B) PetscCall(BVDestroy(&BX));
     395          29 :   if (nc>0 || eps->nev>ctx->bs-ctx->guard) PetscCall(BVDestroy(&Y));
     396          29 :   PetscFunctionReturn(PETSC_SUCCESS);
     397             : }
     398             : 
     399           8 : static PetscErrorCode EPSLOBPCGSetBlockSize_LOBPCG(EPS eps,PetscInt bs)
     400             : {
     401           8 :   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
     402             : 
     403           8 :   PetscFunctionBegin;
     404           8 :   if (bs == PETSC_DEFAULT || bs == PETSC_DECIDE) bs = 0;
     405           8 :   else PetscCheck(bs>0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid block size %" PetscInt_FMT,bs);
     406           8 :   if (ctx->bs != bs) {
     407           8 :     ctx->bs = bs;
     408           8 :     eps->state = EPS_STATE_INITIAL;
     409             :   }
     410           8 :   PetscFunctionReturn(PETSC_SUCCESS);
     411             : }
     412             : 
     413             : /*@
     414             :    EPSLOBPCGSetBlockSize - Sets the block size of the LOBPCG method.
     415             : 
     416             :    Logically Collective
     417             : 
     418             :    Input Parameters:
     419             : +  eps - the eigenproblem solver context
     420             : -  bs  - the block size
     421             : 
     422             :    Options Database Key:
     423             : .  -eps_lobpcg_blocksize - Sets the block size
     424             : 
     425             :    Level: advanced
     426             : 
     427             : .seealso: EPSLOBPCGGetBlockSize()
     428             : @*/
     429           8 : PetscErrorCode EPSLOBPCGSetBlockSize(EPS eps,PetscInt bs)
     430             : {
     431           8 :   PetscFunctionBegin;
     432           8 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     433          24 :   PetscValidLogicalCollectiveInt(eps,bs,2);
     434           8 :   PetscTryMethod(eps,"EPSLOBPCGSetBlockSize_C",(EPS,PetscInt),(eps,bs));
     435           8 :   PetscFunctionReturn(PETSC_SUCCESS);
     436             : }
     437             : 
     438           1 : static PetscErrorCode EPSLOBPCGGetBlockSize_LOBPCG(EPS eps,PetscInt *bs)
     439             : {
     440           1 :   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
     441             : 
     442           1 :   PetscFunctionBegin;
     443           1 :   *bs = ctx->bs;
     444           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     445             : }
     446             : 
     447             : /*@
     448             :    EPSLOBPCGGetBlockSize - Gets the block size used in the LOBPCG method.
     449             : 
     450             :    Not Collective
     451             : 
     452             :    Input Parameter:
     453             : .  eps - the eigenproblem solver context
     454             : 
     455             :    Output Parameter:
     456             : .  bs - the block size
     457             : 
     458             :    Level: advanced
     459             : 
     460             : .seealso: EPSLOBPCGSetBlockSize()
     461             : @*/
     462           1 : PetscErrorCode EPSLOBPCGGetBlockSize(EPS eps,PetscInt *bs)
     463             : {
     464           1 :   PetscFunctionBegin;
     465           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     466           1 :   PetscAssertPointer(bs,2);
     467           1 :   PetscUseMethod(eps,"EPSLOBPCGGetBlockSize_C",(EPS,PetscInt*),(eps,bs));
     468           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     469             : }
     470             : 
     471           1 : static PetscErrorCode EPSLOBPCGSetRestart_LOBPCG(EPS eps,PetscReal restart)
     472             : {
     473           1 :   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
     474             : 
     475           1 :   PetscFunctionBegin;
     476           1 :   if (restart==(PetscReal)PETSC_DEFAULT || restart==(PetscReal)PETSC_DECIDE) restart = 0.9;
     477           1 :   PetscCheck(restart>=0.1 && restart<=1.0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The restart argument %g must be in the range [0.1,1.0]",(double)restart);
     478           1 :   if (restart != ctx->restart) {
     479           1 :     ctx->restart = restart;
     480           1 :     eps->state = EPS_STATE_INITIAL;
     481             :   }
     482           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     483             : }
     484             : 
     485             : /*@
     486             :    EPSLOBPCGSetRestart - Sets the restart parameter for the LOBPCG method.
     487             : 
     488             :    Logically Collective
     489             : 
     490             :    Input Parameters:
     491             : +  eps - the eigenproblem solver context
     492             : -  restart - the percentage of the block of vectors to force a restart
     493             : 
     494             :    Options Database Key:
     495             : .  -eps_lobpcg_restart - Sets the restart parameter
     496             : 
     497             :    Notes:
     498             :    The meaning of this parameter is the proportion of vectors within the
     499             :    current block iterate that must have converged in order to force a
     500             :    restart with hard locking.
     501             :    Allowed values are in the range [0.1,1.0]. The default is 0.9.
     502             : 
     503             :    Level: advanced
     504             : 
     505             : .seealso: EPSLOBPCGGetRestart()
     506             : @*/
     507           1 : PetscErrorCode EPSLOBPCGSetRestart(EPS eps,PetscReal restart)
     508             : {
     509           1 :   PetscFunctionBegin;
     510           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     511           3 :   PetscValidLogicalCollectiveReal(eps,restart,2);
     512           1 :   PetscTryMethod(eps,"EPSLOBPCGSetRestart_C",(EPS,PetscReal),(eps,restart));
     513           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     514             : }
     515             : 
     516           1 : static PetscErrorCode EPSLOBPCGGetRestart_LOBPCG(EPS eps,PetscReal *restart)
     517             : {
     518           1 :   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
     519             : 
     520           1 :   PetscFunctionBegin;
     521           1 :   *restart = ctx->restart;
     522           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     523             : }
     524             : 
     525             : /*@
     526             :    EPSLOBPCGGetRestart - Gets the restart parameter used in the LOBPCG method.
     527             : 
     528             :    Not Collective
     529             : 
     530             :    Input Parameter:
     531             : .  eps - the eigenproblem solver context
     532             : 
     533             :    Output Parameter:
     534             : .  restart - the restart parameter
     535             : 
     536             :    Level: advanced
     537             : 
     538             : .seealso: EPSLOBPCGSetRestart()
     539             : @*/
     540           1 : PetscErrorCode EPSLOBPCGGetRestart(EPS eps,PetscReal *restart)
     541             : {
     542           1 :   PetscFunctionBegin;
     543           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     544           1 :   PetscAssertPointer(restart,2);
     545           1 :   PetscUseMethod(eps,"EPSLOBPCGGetRestart_C",(EPS,PetscReal*),(eps,restart));
     546           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     547             : }
     548             : 
     549           1 : static PetscErrorCode EPSLOBPCGSetLocking_LOBPCG(EPS eps,PetscBool lock)
     550             : {
     551           1 :   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
     552             : 
     553           1 :   PetscFunctionBegin;
     554           1 :   ctx->lock = lock;
     555           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     556             : }
     557             : 
     558             : /*@
     559             :    EPSLOBPCGSetLocking - Choose between locking and non-locking variants of
     560             :    the LOBPCG method.
     561             : 
     562             :    Logically Collective
     563             : 
     564             :    Input Parameters:
     565             : +  eps  - the eigenproblem solver context
     566             : -  lock - true if the locking variant must be selected
     567             : 
     568             :    Options Database Key:
     569             : .  -eps_lobpcg_locking - Sets the locking flag
     570             : 
     571             :    Notes:
     572             :    This flag refers to soft locking (converged vectors within the current
     573             :    block iterate), since hard locking is always used (when nev is larger
     574             :    than the block size).
     575             : 
     576             :    Level: advanced
     577             : 
     578             : .seealso: EPSLOBPCGGetLocking()
     579             : @*/
     580           1 : PetscErrorCode EPSLOBPCGSetLocking(EPS eps,PetscBool lock)
     581             : {
     582           1 :   PetscFunctionBegin;
     583           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     584           3 :   PetscValidLogicalCollectiveBool(eps,lock,2);
     585           1 :   PetscTryMethod(eps,"EPSLOBPCGSetLocking_C",(EPS,PetscBool),(eps,lock));
     586           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     587             : }
     588             : 
     589           1 : static PetscErrorCode EPSLOBPCGGetLocking_LOBPCG(EPS eps,PetscBool *lock)
     590             : {
     591           1 :   EPS_LOBPCG *ctx = (EPS_LOBPCG*)eps->data;
     592             : 
     593           1 :   PetscFunctionBegin;
     594           1 :   *lock = ctx->lock;
     595           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     596             : }
     597             : 
     598             : /*@
     599             :    EPSLOBPCGGetLocking - Gets the locking flag used in the LOBPCG method.
     600             : 
     601             :    Not Collective
     602             : 
     603             :    Input Parameter:
     604             : .  eps - the eigenproblem solver context
     605             : 
     606             :    Output Parameter:
     607             : .  lock - the locking flag
     608             : 
     609             :    Level: advanced
     610             : 
     611             : .seealso: EPSLOBPCGSetLocking()
     612             : @*/
     613           1 : PetscErrorCode EPSLOBPCGGetLocking(EPS eps,PetscBool *lock)
     614             : {
     615           1 :   PetscFunctionBegin;
     616           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     617           1 :   PetscAssertPointer(lock,2);
     618           1 :   PetscUseMethod(eps,"EPSLOBPCGGetLocking_C",(EPS,PetscBool*),(eps,lock));
     619           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     620             : }
     621             : 
     622           0 : static PetscErrorCode EPSView_LOBPCG(EPS eps,PetscViewer viewer)
     623             : {
     624           0 :   EPS_LOBPCG     *ctx = (EPS_LOBPCG*)eps->data;
     625           0 :   PetscBool      isascii;
     626             : 
     627           0 :   PetscFunctionBegin;
     628           0 :   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
     629           0 :   if (isascii) {
     630           0 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  block size %" PetscInt_FMT "\n",ctx->bs));
     631           0 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  restart parameter=%g (using %" PetscInt_FMT " guard vectors)\n",(double)ctx->restart,ctx->guard));
     632           0 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  soft locking %sactivated\n",ctx->lock?"":"de"));
     633             :   }
     634           0 :   PetscFunctionReturn(PETSC_SUCCESS);
     635             : }
     636             : 
     637          23 : static PetscErrorCode EPSSetFromOptions_LOBPCG(EPS eps,PetscOptionItems *PetscOptionsObject)
     638             : {
     639          23 :   PetscBool      lock,flg;
     640          23 :   PetscInt       bs;
     641          23 :   PetscReal      restart;
     642             : 
     643          23 :   PetscFunctionBegin;
     644          23 :   PetscOptionsHeadBegin(PetscOptionsObject,"EPS LOBPCG Options");
     645             : 
     646          23 :     PetscCall(PetscOptionsInt("-eps_lobpcg_blocksize","Block size","EPSLOBPCGSetBlockSize",20,&bs,&flg));
     647          23 :     if (flg) PetscCall(EPSLOBPCGSetBlockSize(eps,bs));
     648             : 
     649          23 :     PetscCall(PetscOptionsReal("-eps_lobpcg_restart","Percentage of the block of vectors to force a restart","EPSLOBPCGSetRestart",0.5,&restart,&flg));
     650          23 :     if (flg) PetscCall(EPSLOBPCGSetRestart(eps,restart));
     651             : 
     652          23 :     PetscCall(PetscOptionsBool("-eps_lobpcg_locking","Choose between locking and non-locking variants","EPSLOBPCGSetLocking",PETSC_TRUE,&lock,&flg));
     653          23 :     if (flg) PetscCall(EPSLOBPCGSetLocking(eps,lock));
     654             : 
     655          23 :   PetscOptionsHeadEnd();
     656          23 :   PetscFunctionReturn(PETSC_SUCCESS);
     657             : }
     658             : 
     659          23 : static PetscErrorCode EPSDestroy_LOBPCG(EPS eps)
     660             : {
     661          23 :   PetscFunctionBegin;
     662          23 :   PetscCall(PetscFree(eps->data));
     663          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetBlockSize_C",NULL));
     664          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetBlockSize_C",NULL));
     665          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetRestart_C",NULL));
     666          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetRestart_C",NULL));
     667          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetLocking_C",NULL));
     668          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetLocking_C",NULL));
     669          23 :   PetscFunctionReturn(PETSC_SUCCESS);
     670             : }
     671             : 
     672          23 : SLEPC_EXTERN PetscErrorCode EPSCreate_LOBPCG(EPS eps)
     673             : {
     674          23 :   EPS_LOBPCG     *lobpcg;
     675             : 
     676          23 :   PetscFunctionBegin;
     677          23 :   PetscCall(PetscNew(&lobpcg));
     678          23 :   eps->data = (void*)lobpcg;
     679          23 :   lobpcg->lock = PETSC_TRUE;
     680             : 
     681          23 :   eps->useds = PETSC_TRUE;
     682          23 :   eps->categ = EPS_CATEGORY_PRECOND;
     683             : 
     684          23 :   eps->ops->solve          = EPSSolve_LOBPCG;
     685          23 :   eps->ops->setup          = EPSSetUp_LOBPCG;
     686          23 :   eps->ops->setupsort      = EPSSetUpSort_Default;
     687          23 :   eps->ops->setfromoptions = EPSSetFromOptions_LOBPCG;
     688          23 :   eps->ops->destroy        = EPSDestroy_LOBPCG;
     689          23 :   eps->ops->view           = EPSView_LOBPCG;
     690          23 :   eps->ops->backtransform  = EPSBackTransform_Default;
     691          23 :   eps->ops->setdefaultst   = EPSSetDefaultST_GMRES;
     692             : 
     693          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetBlockSize_C",EPSLOBPCGSetBlockSize_LOBPCG));
     694          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetBlockSize_C",EPSLOBPCGGetBlockSize_LOBPCG));
     695          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetRestart_C",EPSLOBPCGSetRestart_LOBPCG));
     696          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetRestart_C",EPSLOBPCGGetRestart_LOBPCG));
     697          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGSetLocking_C",EPSLOBPCGSetLocking_LOBPCG));
     698          23 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLOBPCGGetLocking_C",EPSLOBPCGGetLocking_LOBPCG));
     699          23 :   PetscFunctionReturn(PETSC_SUCCESS);
     700             : }

Generated by: LCOV version 1.14