LCOV - code coverage report
Current view: top level - pep/impls/krylov/toar - ptoar.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 466 486 95.9 %
Date: 2024-11-23 00:39:48 Functions: 19 19 100.0 %
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 polynomial eigensolver: "toar"
      12             : 
      13             :    Method: TOAR
      14             : 
      15             :    Algorithm:
      16             : 
      17             :        Two-Level Orthogonal Arnoldi.
      18             : 
      19             :    References:
      20             : 
      21             :        [1] Y. Su, J. Zhang and Z. Bai, "A compact Arnoldi algorithm for
      22             :            polynomial eigenvalue problems", talk presented at RANMEP 2008.
      23             : 
      24             :        [2] C. Campos and J.E. Roman, "Parallel Krylov solvers for the
      25             :            polynomial eigenvalue problem in SLEPc", SIAM J. Sci. Comput.
      26             :            38(5):S385-S411, 2016.
      27             : 
      28             :        [3] D. Lu, Y. Su and Z. Bai, "Stability analysis of the two-level
      29             :            orthogonal Arnoldi procedure", SIAM J. Matrix Anal. App.
      30             :            37(1):195-214, 2016.
      31             : */
      32             : 
      33             : #include <slepc/private/pepimpl.h>    /*I "slepcpep.h" I*/
      34             : #include "../src/pep/impls/krylov/pepkrylov.h"
      35             : #include <slepcblaslapack.h>
      36             : 
      37             : static PetscBool  cited = PETSC_FALSE;
      38             : static const char citation[] =
      39             :   "@Article{slepc-pep,\n"
      40             :   "   author = \"C. Campos and J. E. Roman\",\n"
      41             :   "   title = \"Parallel {Krylov} solvers for the polynomial eigenvalue problem in {SLEPc}\",\n"
      42             :   "   journal = \"{SIAM} J. Sci. Comput.\",\n"
      43             :   "   volume = \"38\",\n"
      44             :   "   number = \"5\",\n"
      45             :   "   pages = \"S385--S411\",\n"
      46             :   "   year = \"2016,\"\n"
      47             :   "   doi = \"https://doi.org/10.1137/15M1022458\"\n"
      48             :   "}\n";
      49             : 
      50          91 : static PetscErrorCode PEPSetUp_TOAR(PEP pep)
      51             : {
      52          91 :   PEP_TOAR       *ctx = (PEP_TOAR*)pep->data;
      53          91 :   PetscBool      sinv,flg;
      54          91 :   PetscInt       i;
      55             : 
      56          91 :   PetscFunctionBegin;
      57          91 :   PEPCheckShiftSinvert(pep);
      58          91 :   PetscCall(PEPSetDimensions_Default(pep,pep->nev,&pep->ncv,&pep->mpd));
      59          91 :   PetscCheck(ctx->lock || pep->mpd>=pep->ncv,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Should not use mpd parameter in non-locking variant");
      60          91 :   if (pep->max_it==PETSC_DETERMINE) pep->max_it = PetscMax(100,2*(pep->nmat-1)*pep->n/pep->ncv);
      61          91 :   if (!pep->which) PetscCall(PEPSetWhichEigenpairs_Default(pep));
      62          91 :   PetscCheck(pep->which!=PEP_ALL,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"This solver does not support computing all eigenvalues");
      63          91 :   if (pep->problem_type!=PEP_GENERAL) PetscCall(PetscInfo(pep,"Problem type ignored, performing a non-symmetric linearization\n"));
      64             : 
      65          91 :   if (!ctx->keep) ctx->keep = 0.5;
      66             : 
      67          91 :   PetscCall(PEPAllocateSolution(pep,pep->nmat-1));
      68          91 :   PetscCall(PEPSetWorkVecs(pep,3));
      69          91 :   PetscCall(DSSetType(pep->ds,DSNHEP));
      70          91 :   PetscCall(DSSetExtraRow(pep->ds,PETSC_TRUE));
      71          91 :   PetscCall(DSAllocate(pep->ds,pep->ncv+1));
      72             : 
      73          91 :   PetscCall(PEPBasisCoefficients(pep,pep->pbc));
      74          91 :   PetscCall(STGetTransform(pep->st,&flg));
      75          91 :   if (!flg) {
      76          80 :     PetscCall(PetscFree(pep->solvematcoeffs));
      77          80 :     PetscCall(PetscMalloc1(pep->nmat,&pep->solvematcoeffs));
      78          80 :     PetscCall(PetscObjectTypeCompare((PetscObject)pep->st,STSINVERT,&sinv));
      79          80 :     if (sinv) PetscCall(PEPEvaluateBasis(pep,pep->target,0,pep->solvematcoeffs,NULL));
      80             :     else {
      81          82 :       for (i=0;i<pep->nmat-1;i++) pep->solvematcoeffs[i] = 0.0;
      82          26 :       pep->solvematcoeffs[pep->nmat-1] = 1.0;
      83             :     }
      84             :   }
      85          91 :   PetscCall(BVDestroy(&ctx->V));
      86          91 :   PetscCall(BVCreateTensor(pep->V,pep->nmat-1,&ctx->V));
      87          91 :   PetscFunctionReturn(PETSC_SUCCESS);
      88             : }
      89             : 
      90             : /*
      91             :   Extend the TOAR basis by applying the matrix operator
      92             :   over a vector which is decomposed in the TOAR way
      93             :   Input:
      94             :     - pbc: array containing the polynomial basis coefficients
      95             :     - S,V: define the latest Arnoldi vector (nv vectors in V)
      96             :   Output:
      97             :     - t: new vector extending the TOAR basis
      98             :     - r: temporary coefficients to compute the TOAR coefficients
      99             :          for the new Arnoldi vector
     100             :   Workspace: t_ (two vectors)
     101             : */
     102        9531 : static PetscErrorCode PEPTOARExtendBasis(PEP pep,PetscBool sinvert,PetscScalar sigma,PetscScalar *S,PetscInt ls,PetscInt nv,BV V,Vec t,PetscScalar *r,PetscInt lr,Vec *t_)
     103             : {
     104        9531 :   PetscInt       nmat=pep->nmat,deg=nmat-1,k,j,off=0,lss;
     105        9531 :   Vec            v=t_[0],ve=t_[1],q=t_[2];
     106        9531 :   PetscScalar    alpha=1.0,*ss,a;
     107        9531 :   PetscReal      *ca=pep->pbc,*cb=pep->pbc+nmat,*cg=pep->pbc+2*nmat;
     108        9531 :   PetscBool      flg;
     109             : 
     110        9531 :   PetscFunctionBegin;
     111        9531 :   PetscCall(BVSetActiveColumns(pep->V,0,nv));
     112        9531 :   PetscCall(STGetTransform(pep->st,&flg));
     113        9531 :   if (sinvert) {
     114      145085 :     for (j=0;j<nv;j++) {
     115      138274 :       if (deg>1) r[lr+j] = S[j]/ca[0];
     116      138274 :       if (deg>2) r[2*lr+j] = (S[ls+j]+(sigma-cb[1])*r[lr+j])/ca[1];
     117             :     }
     118       37387 :     for (k=2;k<deg-1;k++) {
     119      778940 :       for (j=0;j<nv;j++) r[(k+1)*lr+j] = (S[k*ls+j]+(sigma-cb[k])*r[k*lr+j]-cg[k]*r[(k-1)*lr+j])/ca[k];
     120             :     }
     121      145085 :     k = deg-1;
     122      145085 :     for (j=0;j<nv;j++) r[j] = (S[k*ls+j]+(sigma-cb[k])*r[k*lr+j]-cg[k]*r[(k-1)*lr+j])/ca[k];
     123        6811 :     ss = r; lss = lr; off = 1; alpha = -1.0; a = pep->sfactor;
     124             :   } else {
     125        2720 :     ss = S; lss = ls; off = 0; alpha = -ca[deg-1]; a = 1.0;
     126             :   }
     127        9531 :   PetscCall(BVMultVec(V,1.0,0.0,v,ss+off*lss));
     128        9531 :   if (PetscUnlikely(pep->Dr)) { /* balancing */
     129        1476 :     PetscCall(VecPointwiseMult(v,v,pep->Dr));
     130             :   }
     131        9531 :   PetscCall(STMatMult(pep->st,off,v,q));
     132        9531 :   PetscCall(VecScale(q,a));
     133       43741 :   for (j=1+off;j<deg+off-1;j++) {
     134       34210 :     PetscCall(BVMultVec(V,1.0,0.0,v,ss+j*lss));
     135       34210 :     if (PetscUnlikely(pep->Dr)) PetscCall(VecPointwiseMult(v,v,pep->Dr));
     136       34210 :     PetscCall(STMatMult(pep->st,j,v,t));
     137       34210 :     a *= pep->sfactor;
     138       34210 :     PetscCall(VecAXPY(q,a,t));
     139             :   }
     140        9531 :   if (sinvert) {
     141        6811 :     PetscCall(BVMultVec(V,1.0,0.0,v,ss));
     142        6811 :     if (PetscUnlikely(pep->Dr)) PetscCall(VecPointwiseMult(v,v,pep->Dr));
     143        6811 :     PetscCall(STMatMult(pep->st,deg,v,t));
     144        6811 :     a *= pep->sfactor;
     145        6811 :     PetscCall(VecAXPY(q,a,t));
     146             :   } else {
     147        2720 :     PetscCall(BVMultVec(V,1.0,0.0,ve,ss+(deg-1)*lss));
     148        2720 :     if (PetscUnlikely(pep->Dr)) PetscCall(VecPointwiseMult(ve,ve,pep->Dr));
     149        2720 :     a *= pep->sfactor;
     150        2720 :     PetscCall(STMatMult(pep->st,deg-1,ve,t));
     151        2720 :     PetscCall(VecAXPY(q,a,t));
     152        2720 :     a *= pep->sfactor;
     153             :   }
     154        9531 :   if (flg || !sinvert) alpha /= a;
     155        9531 :   PetscCall(STMatSolve(pep->st,q,t));
     156        9531 :   PetscCall(VecScale(t,alpha));
     157        9531 :   if (!sinvert) {
     158        2720 :     PetscCall(VecAXPY(t,cg[deg-1],v));
     159        2720 :     PetscCall(VecAXPY(t,cb[deg-1],ve));
     160             :   }
     161        9531 :   if (PetscUnlikely(pep->Dr)) PetscCall(VecPointwiseDivide(t,t,pep->Dr));
     162        9531 :   PetscFunctionReturn(PETSC_SUCCESS);
     163             : }
     164             : 
     165             : /*
     166             :   Compute TOAR coefficients of the blocks of the new Arnoldi vector computed
     167             : */
     168        9531 : static PetscErrorCode PEPTOARCoefficients(PEP pep,PetscBool sinvert,PetscScalar sigma,PetscInt nv,PetscScalar *S,PetscInt ls,PetscScalar *r,PetscInt lr,PetscScalar *x)
     169             : {
     170        9531 :   PetscInt    k,j,nmat=pep->nmat,d=nmat-1;
     171        9531 :   PetscReal   *ca=pep->pbc,*cb=pep->pbc+nmat,*cg=pep->pbc+2*nmat;
     172        9531 :   PetscScalar t=1.0,tp=0.0,tt;
     173             : 
     174        9531 :   PetscFunctionBegin;
     175        9531 :   if (sinvert) {
     176       47564 :     for (k=1;k<d;k++) {
     177       40753 :       tt = t;
     178       40753 :       t = ((sigma-cb[k-1])*t-cg[k-1]*tp)/ca[k-1]; /* k-th basis polynomial */
     179       40753 :       tp = tt;
     180     1035222 :       for (j=0;j<=nv;j++) r[k*lr+j] += t*x[j];
     181             :     }
     182             :   } else {
     183       48036 :     for (j=0;j<=nv;j++) r[j] = (cb[0]-sigma)*S[j]+ca[0]*S[ls+j];
     184        2988 :     for (k=1;k<d-1;k++) {
     185        4920 :       for (j=0;j<=nv;j++) r[k*lr+j] = (cb[k]-sigma)*S[k*ls+j]+ca[k]*S[(k+1)*ls+j]+cg[k]*S[(k-1)*ls+j];
     186             :     }
     187        2720 :     if (sigma!=0.0) for (j=0;j<=nv;j++) r[(d-1)*lr+j] -= sigma*S[(d-1)*ls+j];
     188             :   }
     189        9531 :   PetscFunctionReturn(PETSC_SUCCESS);
     190             : }
     191             : 
     192             : /*
     193             :   Compute a run of Arnoldi iterations dim(work)=ld
     194             : */
     195         886 : static PetscErrorCode PEPTOARrun(PEP pep,PetscScalar sigma,Mat A,PetscInt k,PetscInt *M,PetscReal *beta,PetscBool *breakdown,Vec *t_)
     196             : {
     197         886 :   PEP_TOAR       *ctx = (PEP_TOAR*)pep->data;
     198         886 :   PetscInt       j,m=*M,deg=pep->nmat-1,ld;
     199         886 :   PetscInt       ldh,lds,nqt,l;
     200         886 :   Vec            t;
     201         886 :   PetscReal      norm=0.0;
     202         886 :   PetscBool      flg,sinvert=PETSC_FALSE,lindep;
     203         886 :   PetscScalar    *H,*x,*S;
     204         886 :   Mat            MS;
     205             : 
     206         886 :   PetscFunctionBegin;
     207         886 :   *beta = 0.0;
     208         886 :   PetscCall(MatDenseGetArray(A,&H));
     209         886 :   PetscCall(MatDenseGetLDA(A,&ldh));
     210         886 :   PetscCall(BVTensorGetFactors(ctx->V,NULL,&MS));
     211         886 :   PetscCall(MatDenseGetArray(MS,&S));
     212         886 :   PetscCall(BVGetSizes(pep->V,NULL,NULL,&ld));
     213         886 :   lds = ld*deg;
     214         886 :   PetscCall(BVGetActiveColumns(pep->V,&l,&nqt));
     215         886 :   PetscCall(STGetTransform(pep->st,&flg));
     216         886 :   if (!flg) {
     217             :     /* spectral transformation handled by the solver */
     218         792 :     PetscCall(PetscObjectTypeCompareAny((PetscObject)pep->st,&flg,STSINVERT,STSHIFT,""));
     219         792 :     PetscCheck(flg,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"ST type not supported for TOAR without transforming matrices");
     220         792 :     PetscCall(PetscObjectTypeCompare((PetscObject)pep->st,STSINVERT,&sinvert));
     221             :   }
     222         886 :   PetscCall(BVSetActiveColumns(ctx->V,0,m));
     223       10415 :   for (j=k;j<m;j++) {
     224             :     /* apply operator */
     225        9531 :     PetscCall(BVGetColumn(pep->V,nqt,&t));
     226        9531 :     PetscCall(PEPTOARExtendBasis(pep,sinvert,sigma,S+j*lds,ld,nqt,pep->V,t,S+(j+1)*lds,ld,t_));
     227        9531 :     PetscCall(BVRestoreColumn(pep->V,nqt,&t));
     228             : 
     229             :     /* orthogonalize */
     230        9531 :     if (sinvert) x = S+(j+1)*lds;
     231        2720 :     else x = S+(deg-1)*ld+(j+1)*lds;
     232        9531 :     PetscCall(BVOrthogonalizeColumn(pep->V,nqt,x,&norm,&lindep));
     233        9531 :     if (!lindep) {
     234        8475 :       x[nqt] = norm;
     235        8475 :       PetscCall(BVScaleColumn(pep->V,nqt,1.0/norm));
     236        8475 :       nqt++;
     237             :     }
     238             : 
     239        9531 :     PetscCall(PEPTOARCoefficients(pep,sinvert,sigma,nqt-1,S+j*lds,ld,S+(j+1)*lds,ld,x));
     240             : 
     241             :     /* level-2 orthogonalization */
     242        9531 :     PetscCall(BVOrthogonalizeColumn(ctx->V,j+1,H+j*ldh,&norm,breakdown));
     243        9531 :     H[j+1+ldh*j] = norm;
     244        9531 :     if (PetscUnlikely(*breakdown)) {
     245           2 :       *M = j+1;
     246           2 :       break;
     247             :     }
     248        9529 :     PetscCall(BVScaleColumn(ctx->V,j+1,1.0/norm));
     249        9529 :     PetscCall(BVSetActiveColumns(pep->V,l,nqt));
     250             :   }
     251         886 :   *beta = norm;
     252         886 :   PetscCall(BVSetActiveColumns(ctx->V,0,*M));
     253         886 :   PetscCall(MatDenseRestoreArray(MS,&S));
     254         886 :   PetscCall(BVTensorRestoreFactors(ctx->V,NULL,&MS));
     255         886 :   PetscCall(MatDenseRestoreArray(A,&H));
     256         886 :   PetscFunctionReturn(PETSC_SUCCESS);
     257             : }
     258             : 
     259             : /*
     260             :   Computes T_j = phi_idx(T). In T_j and T_p are phi_{idx-1}(T)
     261             :    and phi_{idx-2}(T) respectively or null if idx=0,1.
     262             :    Tp and Tj are input/output arguments
     263             : */
     264           5 : static PetscErrorCode PEPEvaluateBasisM(PEP pep,PetscInt k,PetscScalar *T,PetscInt ldt,PetscInt idx,PetscScalar **Tp,PetscScalar **Tj)
     265             : {
     266           5 :   PetscInt       i;
     267           5 :   PetscReal      *ca,*cb,*cg;
     268           5 :   PetscScalar    *pt,g,a;
     269           5 :   PetscBLASInt   k_,ldt_;
     270             : 
     271           5 :   PetscFunctionBegin;
     272           5 :   if (idx==0) {
     273           1 :     PetscCall(PetscArrayzero(*Tj,k*k));
     274           1 :     PetscCall(PetscArrayzero(*Tp,k*k));
     275          14 :     for (i=0;i<k;i++) (*Tj)[i+i*k] = 1.0;
     276             :   } else {
     277           4 :     PetscCall(PetscBLASIntCast(ldt,&ldt_));
     278           4 :     PetscCall(PetscBLASIntCast(k,&k_));
     279           4 :     ca = pep->pbc; cb = pep->pbc+pep->nmat; cg = pep->pbc+2*pep->nmat;
     280          56 :     for (i=0;i<k;i++) T[i*ldt+i] -= cb[idx-1];
     281           4 :     a = 1/ca[idx-1];
     282           4 :     g = (idx==1)?0.0:-cg[idx-1]/ca[idx-1];
     283           4 :     PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&k_,&k_,&k_,&a,T,&ldt_,*Tj,&k_,&g,*Tp,&k_));
     284           4 :     pt = *Tj; *Tj = *Tp; *Tp = pt;
     285          56 :     for (i=0;i<k;i++) T[i*ldt+i] += cb[idx-1];
     286             :   }
     287           5 :   PetscFunctionReturn(PETSC_SUCCESS);
     288             : }
     289             : 
     290          14 : static PetscErrorCode PEPExtractInvariantPair(PEP pep,PetscScalar sigma,PetscInt sr,PetscInt k,PetscScalar *S,PetscInt ld,PetscInt deg,Mat HH)
     291             : {
     292          14 :   PetscInt       i,j,jj,ldh,lds,ldt,d=pep->nmat-1,idxcpy=0;
     293          14 :   PetscScalar    *H,*At,*Bt,*Hj,*Hp,*T,sone=1.0,g,a,*pM,*work;
     294          14 :   PetscBLASInt   k_,sr_,lds_,ldh_,info,*p,lwork,ldt_;
     295          14 :   PetscBool      transf=PETSC_FALSE,flg;
     296          14 :   PetscReal      norm,maxnrm,*rwork;
     297          14 :   BV             *R,Y;
     298          14 :   Mat            M,*A;
     299             : 
     300          14 :   PetscFunctionBegin;
     301          14 :   if (k==0) PetscFunctionReturn(PETSC_SUCCESS);
     302          14 :   PetscCall(MatDenseGetArray(HH,&H));
     303          14 :   PetscCall(MatDenseGetLDA(HH,&ldh));
     304          14 :   lds = deg*ld;
     305          14 :   PetscCall(PetscCalloc6(k,&p,sr*k,&At,k*k,&Bt,k*k,&Hj,k*k,&Hp,sr*k,&work));
     306          14 :   PetscCall(PetscBLASIntCast(sr,&sr_));
     307          14 :   PetscCall(PetscBLASIntCast(k,&k_));
     308          14 :   PetscCall(PetscBLASIntCast(lds,&lds_));
     309          14 :   PetscCall(PetscBLASIntCast(ldh,&ldh_));
     310          14 :   PetscCall(STGetTransform(pep->st,&flg));
     311          14 :   if (!flg) {
     312          11 :     PetscCall(PetscObjectTypeCompare((PetscObject)pep->st,STSINVERT,&flg));
     313          11 :     if (flg || sigma!=0.0) transf=PETSC_TRUE;
     314             :   }
     315           7 :   if (transf) {
     316           7 :     PetscCall(PetscMalloc1(k*k,&T));
     317          41 :     ldt = k;
     318          41 :     for (i=0;i<k;i++) PetscCall(PetscArraycpy(T+k*i,H+i*ldh,k));
     319           7 :     if (flg) {
     320           7 :       PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     321           7 :       PetscCallBLAS("LAPACKgetrf",LAPACKgetrf_(&k_,&k_,T,&k_,p,&info));
     322           7 :       SlepcCheckLapackInfo("getrf",info);
     323           7 :       PetscCall(PetscBLASIntCast(sr*k,&lwork));
     324           7 :       PetscCallBLAS("LAPACKgetri",LAPACKgetri_(&k_,T,&k_,p,work,&lwork,&info));
     325           7 :       SlepcCheckLapackInfo("getri",info);
     326           7 :       PetscCall(PetscFPTrapPop());
     327             :     }
     328          41 :     if (sigma!=0.0) for (i=0;i<k;i++) T[i+k*i] += sigma;
     329             :   } else {
     330           7 :     T = H; ldt = ldh;
     331             :   }
     332          14 :   PetscCall(PetscBLASIntCast(ldt,&ldt_));
     333          14 :   switch (pep->extract) {
     334             :   case PEP_EXTRACT_NONE:
     335             :     break;
     336          11 :   case PEP_EXTRACT_NORM:
     337          11 :     if (pep->basis == PEP_BASIS_MONOMIAL) {
     338          11 :       PetscCall(PetscBLASIntCast(ldt,&ldt_));
     339          11 :       PetscCall(PetscMalloc1(k,&rwork));
     340          11 :       norm = LAPACKlange_("F",&k_,&k_,T,&ldt_,rwork);
     341          11 :       PetscCall(PetscFree(rwork));
     342          11 :       if (norm>1.0) idxcpy = d-1;
     343             :     } else {
     344           0 :       PetscCall(PetscBLASIntCast(ldt,&ldt_));
     345           0 :       PetscCall(PetscMalloc1(k,&rwork));
     346             :       maxnrm = 0.0;
     347           0 :       for (i=0;i<pep->nmat-1;i++) {
     348           0 :         PetscCall(PEPEvaluateBasisM(pep,k,T,ldt,i,&Hp,&Hj));
     349           0 :         norm = LAPACKlange_("F",&k_,&k_,Hj,&k_,rwork);
     350           0 :         if (norm > maxnrm) {
     351           0 :           idxcpy = i;
     352           0 :           maxnrm = norm;
     353             :         }
     354             :       }
     355           0 :       PetscCall(PetscFree(rwork));
     356             :     }
     357          11 :     if (idxcpy>0) {
     358             :       /* copy block idxcpy of S to the first one */
     359          76 :       for (j=0;j<k;j++) PetscCall(PetscArraycpy(S+j*lds,S+idxcpy*ld+j*lds,sr));
     360             :     }
     361             :     break;
     362           1 :   case PEP_EXTRACT_RESIDUAL:
     363           1 :     PetscCall(STGetTransform(pep->st,&flg));
     364           1 :     if (flg) {
     365           0 :       PetscCall(PetscMalloc1(pep->nmat,&A));
     366           0 :       for (i=0;i<pep->nmat;i++) PetscCall(STGetMatrixTransformed(pep->st,i,A+i));
     367           1 :     } else A = pep->A;
     368           1 :     PetscCall(PetscMalloc1(pep->nmat-1,&R));
     369           3 :     for (i=0;i<pep->nmat-1;i++) PetscCall(BVDuplicateResize(pep->V,k,R+i));
     370           1 :     PetscCall(BVDuplicateResize(pep->V,sr,&Y));
     371           1 :     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,sr,k,NULL,&M));
     372           1 :     g = 0.0; a = 1.0;
     373           1 :     PetscCall(BVSetActiveColumns(pep->V,0,sr));
     374           4 :     for (j=0;j<pep->nmat;j++) {
     375           3 :       PetscCall(BVMatMult(pep->V,A[j],Y));
     376           3 :       PetscCall(PEPEvaluateBasisM(pep,k,T,ldt,i,&Hp,&Hj));
     377           9 :       for (i=0;i<pep->nmat-1;i++) {
     378           6 :         PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&sr_,&k_,&k_,&a,S+i*ld,&lds_,Hj,&k_,&g,At,&sr_));
     379           6 :         PetscCall(MatDenseGetArray(M,&pM));
     380          84 :         for (jj=0;jj<k;jj++) PetscCall(PetscArraycpy(pM+jj*sr,At+jj*sr,sr));
     381           6 :         PetscCall(MatDenseRestoreArray(M,&pM));
     382           9 :         PetscCall(BVMult(R[i],1.0,(i==0)?0.0:1.0,Y,M));
     383             :       }
     384             :     }
     385             : 
     386             :     /* frobenius norm */
     387             :     maxnrm = 0.0;
     388           3 :     for (i=0;i<pep->nmat-1;i++) {
     389           2 :       PetscCall(BVNorm(R[i],NORM_FROBENIUS,&norm));
     390           2 :       if (maxnrm > norm) {
     391           0 :         maxnrm = norm;
     392           0 :         idxcpy = i;
     393             :       }
     394             :     }
     395           1 :     if (idxcpy>0) {
     396             :       /* copy block idxcpy of S to the first one */
     397           0 :       for (j=0;j<k;j++) PetscCall(PetscArraycpy(S+j*lds,S+idxcpy*ld+j*lds,sr));
     398             :     }
     399           1 :     if (flg) PetscCall(PetscFree(A));
     400           3 :     for (i=0;i<pep->nmat-1;i++) PetscCall(BVDestroy(&R[i]));
     401           1 :     PetscCall(PetscFree(R));
     402           1 :     PetscCall(BVDestroy(&Y));
     403           1 :     PetscCall(MatDestroy(&M));
     404             :     break;
     405             :   case PEP_EXTRACT_STRUCTURED:
     406          14 :     for (j=0;j<k;j++) Bt[j+j*k] = 1.0;
     407          14 :     for (j=0;j<sr;j++) {
     408         182 :       for (i=0;i<k;i++) At[j*k+i] = PetscConj(S[i*lds+j]);
     409             :     }
     410           1 :     PetscCall(PEPEvaluateBasisM(pep,k,T,ldt,0,&Hp,&Hj));
     411           2 :     for (i=1;i<deg;i++) {
     412           1 :       PetscCall(PEPEvaluateBasisM(pep,k,T,ldt,i,&Hp,&Hj));
     413           1 :       PetscCallBLAS("BLASgemm",BLASgemm_("N","C",&k_,&sr_,&k_,&sone,Hj,&k_,S+i*ld,&lds_,&sone,At,&k_));
     414           1 :       PetscCallBLAS("BLASgemm",BLASgemm_("N","C",&k_,&k_,&k_,&sone,Hj,&k_,Hj,&k_,&sone,Bt,&k_));
     415             :     }
     416           1 :     PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     417           1 :     PetscCallBLAS("LAPACKgesv",LAPACKgesv_(&k_,&sr_,Bt,&k_,p,At,&k_,&info));
     418           1 :     PetscCall(PetscFPTrapPop());
     419           1 :     SlepcCheckLapackInfo("gesv",info);
     420          14 :     for (j=0;j<sr;j++) {
     421         182 :       for (i=0;i<k;i++) S[i*lds+j] = PetscConj(At[j*k+i]);
     422             :     }
     423             :     break;
     424             :   }
     425          14 :   if (transf) PetscCall(PetscFree(T));
     426          14 :   PetscCall(PetscFree6(p,At,Bt,Hj,Hp,work));
     427          14 :   PetscCall(MatDenseRestoreArray(HH,&H));
     428          14 :   PetscFunctionReturn(PETSC_SUCCESS);
     429             : }
     430             : 
     431          91 : static PetscErrorCode PEPSolve_TOAR(PEP pep)
     432             : {
     433          91 :   PEP_TOAR       *ctx = (PEP_TOAR*)pep->data;
     434          91 :   PetscInt       i,j,k,l,nv=0,ld,lds,nq=0,nconv=0;
     435          91 :   PetscInt       nmat=pep->nmat,deg=nmat-1;
     436          91 :   PetscScalar    *S,sigma;
     437          91 :   PetscReal      beta;
     438          91 :   PetscBool      breakdown=PETSC_FALSE,flg,falselock=PETSC_FALSE,sinv=PETSC_FALSE;
     439          91 :   Mat            H,MS,MQ;
     440             : 
     441          91 :   PetscFunctionBegin;
     442          91 :   PetscCall(PetscCitationsRegister(citation,&cited));
     443          91 :   if (ctx->lock) {
     444             :     /* undocumented option to use a cheaper locking instead of the true locking */
     445          90 :     PetscCall(PetscOptionsGetBool(NULL,NULL,"-pep_toar_falselocking",&falselock,NULL));
     446             :   }
     447          91 :   PetscCall(STGetShift(pep->st,&sigma));
     448             : 
     449             :   /* update polynomial basis coefficients */
     450          91 :   PetscCall(STGetTransform(pep->st,&flg));
     451          91 :   if (pep->sfactor!=1.0) {
     452           8 :     for (i=0;i<nmat;i++) {
     453           6 :       pep->pbc[nmat+i] /= pep->sfactor;
     454           6 :       pep->pbc[2*nmat+i] /= pep->sfactor*pep->sfactor;
     455             :     }
     456           2 :     if (!flg) {
     457           2 :       pep->target /= pep->sfactor;
     458           2 :       PetscCall(RGPushScale(pep->rg,1.0/pep->sfactor));
     459           2 :       PetscCall(STScaleShift(pep->st,1.0/pep->sfactor));
     460           2 :       sigma /= pep->sfactor;
     461             :     } else {
     462           0 :       PetscCall(PetscObjectTypeCompare((PetscObject)pep->st,STSINVERT,&sinv));
     463           0 :       pep->target = sinv?pep->target*pep->sfactor:pep->target/pep->sfactor;
     464           0 :       PetscCall(RGPushScale(pep->rg,sinv?pep->sfactor:1.0/pep->sfactor));
     465           0 :       PetscCall(STScaleShift(pep->st,sinv?pep->sfactor:1.0/pep->sfactor));
     466             :     }
     467             :   }
     468             : 
     469          91 :   if (flg) sigma = 0.0;
     470             : 
     471             :   /* clean projected matrix (including the extra-arrow) */
     472          91 :   PetscCall(DSSetDimensions(pep->ds,PETSC_DETERMINE,PETSC_DETERMINE,PETSC_DETERMINE));
     473          91 :   PetscCall(DSGetMat(pep->ds,DS_MAT_A,&H));
     474          91 :   PetscCall(MatZeroEntries(H));
     475          91 :   PetscCall(DSRestoreMat(pep->ds,DS_MAT_A,&H));
     476             : 
     477             :   /* Get the starting Arnoldi vector */
     478          91 :   PetscCall(BVTensorBuildFirstColumn(ctx->V,pep->nini));
     479             : 
     480             :   /* restart loop */
     481          91 :   l = 0;
     482          91 :   while (pep->reason == PEP_CONVERGED_ITERATING) {
     483         886 :     pep->its++;
     484             : 
     485             :     /* compute an nv-step Lanczos factorization */
     486         886 :     nv = PetscMax(PetscMin(nconv+pep->mpd,pep->ncv),nv);
     487         886 :     PetscCall(DSGetMat(pep->ds,DS_MAT_A,&H));
     488         886 :     PetscCall(PEPTOARrun(pep,sigma,H,pep->nconv+l,&nv,&beta,&breakdown,pep->work));
     489         886 :     PetscCall(DSRestoreMat(pep->ds,DS_MAT_A,&H));
     490         886 :     PetscCall(DSSetDimensions(pep->ds,nv,pep->nconv,pep->nconv+l));
     491         886 :     PetscCall(DSSetState(pep->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
     492         886 :     PetscCall(BVSetActiveColumns(ctx->V,pep->nconv,nv));
     493             : 
     494             :     /* solve projected problem */
     495         886 :     PetscCall(DSSolve(pep->ds,pep->eigr,pep->eigi));
     496         886 :     PetscCall(DSSort(pep->ds,pep->eigr,pep->eigi,NULL,NULL,NULL));
     497         886 :     PetscCall(DSUpdateExtraRow(pep->ds));
     498         886 :     PetscCall(DSSynchronize(pep->ds,pep->eigr,pep->eigi));
     499             : 
     500             :     /* check convergence */
     501         886 :     PetscCall(PEPKrylovConvergence(pep,PETSC_FALSE,pep->nconv,nv-pep->nconv,beta,&k));
     502         886 :     PetscCall((*pep->stopping)(pep,pep->its,pep->max_it,k,pep->nev,&pep->reason,pep->stoppingctx));
     503             : 
     504             :     /* update l */
     505         886 :     if (pep->reason != PEP_CONVERGED_ITERATING || breakdown) l = 0;
     506             :     else {
     507         795 :       l = (nv==k)?0:PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
     508         795 :       PetscCall(DSGetTruncateSize(pep->ds,k,nv,&l));
     509         795 :       if (!breakdown) {
     510             :         /* prepare the Rayleigh quotient for restart */
     511         795 :         PetscCall(DSTruncate(pep->ds,k+l,PETSC_FALSE));
     512             :       }
     513             :     }
     514         886 :     nconv = k;
     515         886 :     if (!ctx->lock && pep->reason == PEP_CONVERGED_ITERATING && !breakdown) { l += k; k = 0; } /* non-locking variant: reset no. of converged pairs */
     516         886 :     if (l) PetscCall(PetscInfo(pep,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
     517             : 
     518             :     /* update S */
     519         886 :     PetscCall(DSGetMat(pep->ds,DS_MAT_Q,&MQ));
     520         886 :     PetscCall(BVMultInPlace(ctx->V,MQ,pep->nconv,k+l));
     521         886 :     PetscCall(DSRestoreMat(pep->ds,DS_MAT_Q,&MQ));
     522             : 
     523             :     /* copy last column of S */
     524         886 :     PetscCall(BVCopyColumn(ctx->V,nv,k+l));
     525             : 
     526         886 :     if (PetscUnlikely(breakdown && pep->reason == PEP_CONVERGED_ITERATING)) {
     527             :       /* stop if breakdown */
     528           0 :       PetscCall(PetscInfo(pep,"Breakdown TOAR method (it=%" PetscInt_FMT " norm=%g)\n",pep->its,(double)beta));
     529           0 :       pep->reason = PEP_DIVERGED_BREAKDOWN;
     530             :     }
     531         886 :     if (pep->reason != PEP_CONVERGED_ITERATING) l--;
     532             :     /* truncate S */
     533         886 :     PetscCall(BVGetActiveColumns(pep->V,NULL,&nq));
     534         886 :     if (k+l+deg<=nq) {
     535         792 :       PetscCall(BVSetActiveColumns(ctx->V,pep->nconv,k+l+1));
     536         792 :       if (!falselock && ctx->lock) PetscCall(BVTensorCompress(ctx->V,k-pep->nconv));
     537           7 :       else PetscCall(BVTensorCompress(ctx->V,0));
     538             :     }
     539         886 :     pep->nconv = k;
     540         977 :     PetscCall(PEPMonitor(pep,pep->its,nconv,pep->eigr,pep->eigi,pep->errest,nv));
     541             :   }
     542          91 :   if (pep->nconv>0) {
     543             :     /* {V*S_nconv^i}_{i=0}^{d-1} has rank nconv instead of nconv+d-1. Force zeros in each S_nconv^i block */
     544          91 :     PetscCall(BVSetActiveColumns(ctx->V,0,pep->nconv));
     545          91 :     PetscCall(BVGetActiveColumns(pep->V,NULL,&nq));
     546          91 :     PetscCall(BVSetActiveColumns(pep->V,0,nq));
     547          91 :     if (nq>pep->nconv) {
     548           2 :       PetscCall(BVTensorCompress(ctx->V,pep->nconv));
     549           2 :       PetscCall(BVSetActiveColumns(pep->V,0,pep->nconv));
     550           2 :       nq = pep->nconv;
     551             :     }
     552             : 
     553             :     /* perform Newton refinement if required */
     554          91 :     if (pep->refine==PEP_REFINE_MULTIPLE && pep->rits>0) {
     555             :       /* extract invariant pair */
     556          14 :       PetscCall(BVTensorGetFactors(ctx->V,NULL,&MS));
     557          14 :       PetscCall(MatDenseGetArray(MS,&S));
     558          14 :       PetscCall(DSGetMat(pep->ds,DS_MAT_A,&H));
     559          14 :       PetscCall(BVGetSizes(pep->V,NULL,NULL,&ld));
     560          14 :       lds = deg*ld;
     561          14 :       PetscCall(PEPExtractInvariantPair(pep,sigma,nq,pep->nconv,S,ld,deg,H));
     562          14 :       PetscCall(DSRestoreMat(pep->ds,DS_MAT_A,&H));
     563          14 :       PetscCall(DSSetDimensions(pep->ds,pep->nconv,0,0));
     564          14 :       PetscCall(DSSetState(pep->ds,DS_STATE_RAW));
     565          14 :       PetscCall(PEPNewtonRefinement_TOAR(pep,sigma,&pep->rits,NULL,pep->nconv,S,lds));
     566          14 :       PetscCall(DSSolve(pep->ds,pep->eigr,pep->eigi));
     567          14 :       PetscCall(DSSort(pep->ds,pep->eigr,pep->eigi,NULL,NULL,NULL));
     568          14 :       PetscCall(DSSynchronize(pep->ds,pep->eigr,pep->eigi));
     569          14 :       PetscCall(DSGetMat(pep->ds,DS_MAT_Q,&MQ));
     570          14 :       PetscCall(BVMultInPlace(ctx->V,MQ,0,pep->nconv));
     571          14 :       PetscCall(DSRestoreMat(pep->ds,DS_MAT_Q,&MQ));
     572          14 :       PetscCall(MatDenseRestoreArray(MS,&S));
     573          14 :       PetscCall(BVTensorRestoreFactors(ctx->V,NULL,&MS));
     574             :     }
     575             :   }
     576          91 :   PetscCall(STGetTransform(pep->st,&flg));
     577          91 :   if (pep->refine!=PEP_REFINE_MULTIPLE || pep->rits==0) {
     578          77 :     if (!flg) PetscTryTypeMethod(pep,backtransform);
     579          77 :     if (pep->sfactor!=1.0) {
     580          13 :       for (j=0;j<pep->nconv;j++) {
     581          11 :         pep->eigr[j] *= pep->sfactor;
     582          11 :         pep->eigi[j] *= pep->sfactor;
     583             :       }
     584             :       /* restore original values */
     585           8 :       for (i=0;i<pep->nmat;i++) {
     586           6 :         pep->pbc[pep->nmat+i] *= pep->sfactor;
     587           6 :         pep->pbc[2*pep->nmat+i] *= pep->sfactor*pep->sfactor;
     588             :       }
     589             :     }
     590             :   }
     591             :   /* restore original values */
     592          91 :   if (!flg) {
     593          80 :     pep->target *= pep->sfactor;
     594          80 :     PetscCall(STScaleShift(pep->st,pep->sfactor));
     595             :   } else {
     596          11 :     PetscCall(STScaleShift(pep->st,sinv?1.0/pep->sfactor:pep->sfactor));
     597          11 :     pep->target = (sinv)?pep->target/pep->sfactor:pep->target*pep->sfactor;
     598             :   }
     599          91 :   if (pep->sfactor!=1.0) PetscCall(RGPopScale(pep->rg));
     600             : 
     601             :   /* change the state to raw so that DSVectors() computes eigenvectors from scratch */
     602          91 :   PetscCall(DSSetDimensions(pep->ds,pep->nconv,0,0));
     603          91 :   PetscCall(DSSetState(pep->ds,DS_STATE_RAW));
     604          91 :   PetscFunctionReturn(PETSC_SUCCESS);
     605             : }
     606             : 
     607           2 : static PetscErrorCode PEPTOARSetRestart_TOAR(PEP pep,PetscReal keep)
     608             : {
     609           2 :   PEP_TOAR *ctx = (PEP_TOAR*)pep->data;
     610             : 
     611           2 :   PetscFunctionBegin;
     612           2 :   if (keep==(PetscReal)PETSC_DEFAULT || keep==(PetscReal)PETSC_DECIDE) ctx->keep = 0.5;
     613             :   else {
     614           2 :     PetscCheck(keep>=0.1 && keep<=0.9,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"The keep argument must be in the range [0.1,0.9]");
     615           2 :     ctx->keep = keep;
     616             :   }
     617           2 :   PetscFunctionReturn(PETSC_SUCCESS);
     618             : }
     619             : 
     620             : /*@
     621             :    PEPTOARSetRestart - Sets the restart parameter for the TOAR
     622             :    method, in particular the proportion of basis vectors that must be kept
     623             :    after restart.
     624             : 
     625             :    Logically Collective
     626             : 
     627             :    Input Parameters:
     628             : +  pep  - the eigenproblem solver context
     629             : -  keep - the number of vectors to be kept at restart
     630             : 
     631             :    Options Database Key:
     632             : .  -pep_toar_restart - Sets the restart parameter
     633             : 
     634             :    Notes:
     635             :    Allowed values are in the range [0.1,0.9]. The default is 0.5.
     636             : 
     637             :    Level: advanced
     638             : 
     639             : .seealso: PEPTOARGetRestart()
     640             : @*/
     641           2 : PetscErrorCode PEPTOARSetRestart(PEP pep,PetscReal keep)
     642             : {
     643           2 :   PetscFunctionBegin;
     644           2 :   PetscValidHeaderSpecific(pep,PEP_CLASSID,1);
     645           6 :   PetscValidLogicalCollectiveReal(pep,keep,2);
     646           2 :   PetscTryMethod(pep,"PEPTOARSetRestart_C",(PEP,PetscReal),(pep,keep));
     647           2 :   PetscFunctionReturn(PETSC_SUCCESS);
     648             : }
     649             : 
     650           1 : static PetscErrorCode PEPTOARGetRestart_TOAR(PEP pep,PetscReal *keep)
     651             : {
     652           1 :   PEP_TOAR *ctx = (PEP_TOAR*)pep->data;
     653             : 
     654           1 :   PetscFunctionBegin;
     655           1 :   *keep = ctx->keep;
     656           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     657             : }
     658             : 
     659             : /*@
     660             :    PEPTOARGetRestart - Gets the restart parameter used in the TOAR method.
     661             : 
     662             :    Not Collective
     663             : 
     664             :    Input Parameter:
     665             : .  pep - the eigenproblem solver context
     666             : 
     667             :    Output Parameter:
     668             : .  keep - the restart parameter
     669             : 
     670             :    Level: advanced
     671             : 
     672             : .seealso: PEPTOARSetRestart()
     673             : @*/
     674           1 : PetscErrorCode PEPTOARGetRestart(PEP pep,PetscReal *keep)
     675             : {
     676           1 :   PetscFunctionBegin;
     677           1 :   PetscValidHeaderSpecific(pep,PEP_CLASSID,1);
     678           1 :   PetscAssertPointer(keep,2);
     679           1 :   PetscUseMethod(pep,"PEPTOARGetRestart_C",(PEP,PetscReal*),(pep,keep));
     680           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     681             : }
     682             : 
     683           1 : static PetscErrorCode PEPTOARSetLocking_TOAR(PEP pep,PetscBool lock)
     684             : {
     685           1 :   PEP_TOAR *ctx = (PEP_TOAR*)pep->data;
     686             : 
     687           1 :   PetscFunctionBegin;
     688           1 :   ctx->lock = lock;
     689           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     690             : }
     691             : 
     692             : /*@
     693             :    PEPTOARSetLocking - Choose between locking and non-locking variants of
     694             :    the TOAR method.
     695             : 
     696             :    Logically Collective
     697             : 
     698             :    Input Parameters:
     699             : +  pep  - the eigenproblem solver context
     700             : -  lock - true if the locking variant must be selected
     701             : 
     702             :    Options Database Key:
     703             : .  -pep_toar_locking - Sets the locking flag
     704             : 
     705             :    Notes:
     706             :    The default is to lock converged eigenpairs when the method restarts.
     707             :    This behaviour can be changed so that all directions are kept in the
     708             :    working subspace even if already converged to working accuracy (the
     709             :    non-locking variant).
     710             : 
     711             :    Level: advanced
     712             : 
     713             : .seealso: PEPTOARGetLocking()
     714             : @*/
     715           1 : PetscErrorCode PEPTOARSetLocking(PEP pep,PetscBool lock)
     716             : {
     717           1 :   PetscFunctionBegin;
     718           1 :   PetscValidHeaderSpecific(pep,PEP_CLASSID,1);
     719           3 :   PetscValidLogicalCollectiveBool(pep,lock,2);
     720           1 :   PetscTryMethod(pep,"PEPTOARSetLocking_C",(PEP,PetscBool),(pep,lock));
     721           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     722             : }
     723             : 
     724           1 : static PetscErrorCode PEPTOARGetLocking_TOAR(PEP pep,PetscBool *lock)
     725             : {
     726           1 :   PEP_TOAR *ctx = (PEP_TOAR*)pep->data;
     727             : 
     728           1 :   PetscFunctionBegin;
     729           1 :   *lock = ctx->lock;
     730           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     731             : }
     732             : 
     733             : /*@
     734             :    PEPTOARGetLocking - Gets the locking flag used in the TOAR method.
     735             : 
     736             :    Not Collective
     737             : 
     738             :    Input Parameter:
     739             : .  pep - the eigenproblem solver context
     740             : 
     741             :    Output Parameter:
     742             : .  lock - the locking flag
     743             : 
     744             :    Level: advanced
     745             : 
     746             : .seealso: PEPTOARSetLocking()
     747             : @*/
     748           1 : PetscErrorCode PEPTOARGetLocking(PEP pep,PetscBool *lock)
     749             : {
     750           1 :   PetscFunctionBegin;
     751           1 :   PetscValidHeaderSpecific(pep,PEP_CLASSID,1);
     752           1 :   PetscAssertPointer(lock,2);
     753           1 :   PetscUseMethod(pep,"PEPTOARGetLocking_C",(PEP,PetscBool*),(pep,lock));
     754           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     755             : }
     756             : 
     757          84 : static PetscErrorCode PEPSetFromOptions_TOAR(PEP pep,PetscOptionItems *PetscOptionsObject)
     758             : {
     759          84 :   PetscBool      flg,lock;
     760          84 :   PetscReal      keep;
     761             : 
     762          84 :   PetscFunctionBegin;
     763          84 :   PetscOptionsHeadBegin(PetscOptionsObject,"PEP TOAR Options");
     764             : 
     765          84 :     PetscCall(PetscOptionsReal("-pep_toar_restart","Proportion of vectors kept after restart","PEPTOARSetRestart",0.5,&keep,&flg));
     766          84 :     if (flg) PetscCall(PEPTOARSetRestart(pep,keep));
     767             : 
     768          84 :     PetscCall(PetscOptionsBool("-pep_toar_locking","Choose between locking and non-locking variants","PEPTOARSetLocking",PETSC_FALSE,&lock,&flg));
     769          84 :     if (flg) PetscCall(PEPTOARSetLocking(pep,lock));
     770             : 
     771          84 :   PetscOptionsHeadEnd();
     772          84 :   PetscFunctionReturn(PETSC_SUCCESS);
     773             : }
     774             : 
     775           1 : static PetscErrorCode PEPView_TOAR(PEP pep,PetscViewer viewer)
     776             : {
     777           1 :   PEP_TOAR       *ctx = (PEP_TOAR*)pep->data;
     778           1 :   PetscBool      isascii;
     779             : 
     780           1 :   PetscFunctionBegin;
     781           1 :   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
     782           1 :   if (isascii) {
     783           1 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  %d%% of basis vectors kept after restart\n",(int)(100*ctx->keep)));
     784           1 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  using the %slocking variant\n",ctx->lock?"":"non-"));
     785             :   }
     786           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     787             : }
     788             : 
     789          88 : static PetscErrorCode PEPDestroy_TOAR(PEP pep)
     790             : {
     791          88 :   PEP_TOAR       *ctx = (PEP_TOAR*)pep->data;
     792             : 
     793          88 :   PetscFunctionBegin;
     794          88 :   PetscCall(BVDestroy(&ctx->V));
     795          88 :   PetscCall(PetscFree(pep->data));
     796          88 :   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPTOARSetRestart_C",NULL));
     797          88 :   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPTOARGetRestart_C",NULL));
     798          88 :   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPTOARSetLocking_C",NULL));
     799          88 :   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPTOARGetLocking_C",NULL));
     800          88 :   PetscFunctionReturn(PETSC_SUCCESS);
     801             : }
     802             : 
     803          88 : SLEPC_EXTERN PetscErrorCode PEPCreate_TOAR(PEP pep)
     804             : {
     805          88 :   PEP_TOAR       *ctx;
     806             : 
     807          88 :   PetscFunctionBegin;
     808          88 :   PetscCall(PetscNew(&ctx));
     809          88 :   pep->data = (void*)ctx;
     810             : 
     811          88 :   pep->lineariz = PETSC_TRUE;
     812          88 :   ctx->lock     = PETSC_TRUE;
     813             : 
     814          88 :   pep->ops->solve          = PEPSolve_TOAR;
     815          88 :   pep->ops->setup          = PEPSetUp_TOAR;
     816          88 :   pep->ops->setfromoptions = PEPSetFromOptions_TOAR;
     817          88 :   pep->ops->destroy        = PEPDestroy_TOAR;
     818          88 :   pep->ops->view           = PEPView_TOAR;
     819          88 :   pep->ops->backtransform  = PEPBackTransform_Default;
     820          88 :   pep->ops->computevectors = PEPComputeVectors_Default;
     821          88 :   pep->ops->extractvectors = PEPExtractVectors_TOAR;
     822             : 
     823          88 :   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPTOARSetRestart_C",PEPTOARSetRestart_TOAR));
     824          88 :   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPTOARGetRestart_C",PEPTOARGetRestart_TOAR));
     825          88 :   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPTOARSetLocking_C",PEPTOARSetLocking_TOAR));
     826          88 :   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPTOARGetLocking_C",PEPTOARGetLocking_TOAR));
     827          88 :   PetscFunctionReturn(PETSC_SUCCESS);
     828             : }

Generated by: LCOV version 1.14