Date: 2026-01-20T11:35:35+00:00

Actual source code: slp-twosided.c

      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:    Two-sided variant of the NEPSLP solver.
     12: */

     14: #include <slepc/private/nepimpl.h>
     15: #include "slp.h"

     17: typedef struct _n_nep_def_ctx *NEP_NEDEF_CTX;

     19: struct _n_nep_def_ctx {
     20:   PetscInt    n;
     21:   PetscBool   ref;
     22:   PetscScalar *eig;
     23:   BV          V,W;
     24: };

     26: typedef struct {   /* context for two-sided solver */
     27:   Mat         Ft;
     28:   Mat         Jt;
     29:   Vec         w;
     30: } NEP_SLPTS_MATSHELL;

     32: typedef struct {   /* context for non-equivalence deflation */
     33:   NEP_NEDEF_CTX defctx;
     34:   Mat           F;
     35:   Mat           P;
     36:   Mat           J;
     37:   KSP           ksp;
     38:   PetscBool     isJ;
     39:   PetscScalar   lambda;
     40:   Vec           w[2];
     41: } NEP_NEDEF_MATSHELL;

     43: static PetscErrorCode MatMult_SLPTS_Right(Mat M,Vec x,Vec y)
     44: {
     45:   NEP_SLPTS_MATSHELL *ctx;

     47:   PetscFunctionBegin;
     48:   PetscCall(MatShellGetContext(M,&ctx));
     49:   PetscCall(MatMult(ctx->Jt,x,ctx->w));
     50:   PetscCall(MatSolve(ctx->Ft,ctx->w,y));
     51:   PetscFunctionReturn(PETSC_SUCCESS);
     52: }

     54: static PetscErrorCode MatMult_SLPTS_Left(Mat M,Vec x,Vec y)
     55: {
     56:   NEP_SLPTS_MATSHELL *ctx;

     58:   PetscFunctionBegin;
     59:   PetscCall(MatShellGetContext(M,&ctx));
     60:   PetscCall(MatMultTranspose(ctx->Jt,x,ctx->w));
     61:   PetscCall(MatSolveTranspose(ctx->Ft,ctx->w,y));
     62:   PetscFunctionReturn(PETSC_SUCCESS);
     63: }

     65: static PetscErrorCode MatDestroy_SLPTS(Mat M)
     66: {
     67:   NEP_SLPTS_MATSHELL *ctx;

     69:   PetscFunctionBegin;
     70:   PetscCall(MatShellGetContext(M,&ctx));
     71:   PetscCall(VecDestroy(&ctx->w));
     72:   PetscCall(PetscFree(ctx));
     73:   PetscFunctionReturn(PETSC_SUCCESS);
     74: }

     76: #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
     77: static PetscErrorCode MatCreateVecs_SLPTS(Mat M,Vec *left,Vec *right)
     78: {
     79:   NEP_SLPTS_MATSHELL *ctx;

     81:   PetscFunctionBegin;
     82:   PetscCall(MatShellGetContext(M,&ctx));
     83:   if (right) PetscCall(VecDuplicate(ctx->w,right));
     84:   if (left) PetscCall(VecDuplicate(ctx->w,left));
     85:   PetscFunctionReturn(PETSC_SUCCESS);
     86: }
     87: #endif

     89: static PetscErrorCode NEPSLPSetUpEPSMat(NEP nep,Mat F,Mat J,PetscBool left,Mat *M)
     90: {
     91:   Mat                Mshell;
     92:   PetscInt           nloc,mloc;
     93:   NEP_SLPTS_MATSHELL *shellctx;

     95:   PetscFunctionBegin;
     96:   /* Create mat shell */
     97:   PetscCall(PetscNew(&shellctx));
     98:   shellctx->Ft = F;
     99:   shellctx->Jt = J;
    100:   PetscCall(MatGetLocalSize(nep->function,&mloc,&nloc));
    101:   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)nep),nloc,mloc,PETSC_DETERMINE,PETSC_DETERMINE,shellctx,&Mshell));
    102:   if (left) PetscCall(MatShellSetOperation(Mshell,MATOP_MULT,(PetscErrorCodeFn*)MatMult_SLPTS_Left));
    103:   else PetscCall(MatShellSetOperation(Mshell,MATOP_MULT,(PetscErrorCodeFn*)MatMult_SLPTS_Right));
    104:   PetscCall(MatShellSetOperation(Mshell,MATOP_DESTROY,(PetscErrorCodeFn*)MatDestroy_SLPTS));
    105: #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
    106:   PetscCall(MatShellSetOperation(Mshell,MATOP_CREATE_VECS,(PetscErrorCodeFn*)MatCreateVecs_SLPTS));
    107: #endif
    108:   *M = Mshell;
    109:   PetscCall(MatCreateVecs(nep->function,&shellctx->w,NULL));
    110:   PetscFunctionReturn(PETSC_SUCCESS);
    111: }

    113: /* Functions for deflation */
    114: static PetscErrorCode NEPDeflationNEDestroy(NEP_NEDEF_CTX defctx)
    115: {
    116:   PetscFunctionBegin;
    117:   if (!defctx) PetscFunctionReturn(PETSC_SUCCESS);
    118:   PetscCall(PetscFree(defctx->eig));
    119:   PetscCall(PetscFree(defctx));
    120:   PetscFunctionReturn(PETSC_SUCCESS);
    121: }

    123: static PetscErrorCode NEPDeflationNECreate(NEP nep,BV V,BV W,PetscInt sz,NEP_NEDEF_CTX *defctx)
    124: {
    125:   NEP_NEDEF_CTX  op;

    127:   PetscFunctionBegin;
    128:   PetscCall(PetscNew(&op));
    129:   *defctx = op;
    130:   op->n   = 0;
    131:   op->ref = PETSC_FALSE;
    132:   PetscCall(PetscCalloc1(sz,&op->eig));
    133:   PetscCall(PetscObjectStateIncrease((PetscObject)V));
    134:   PetscCall(PetscObjectStateIncrease((PetscObject)W));
    135:   op->V = V;
    136:   op->W = W;
    137:   PetscFunctionReturn(PETSC_SUCCESS);
    138: }

    140: static PetscErrorCode NEPDeflationNEComputeFunction(NEP nep,Mat M,PetscScalar lambda)
    141: {
    142:   NEP_NEDEF_MATSHELL *matctx;

    144:   PetscFunctionBegin;
    145:   PetscCall(MatShellGetContext(M,&matctx));
    146:   if (lambda==matctx->lambda) PetscFunctionReturn(PETSC_SUCCESS);
    147:   PetscCall(NEPComputeFunction(nep,lambda,matctx->F,matctx->P));
    148:   if (matctx->isJ) PetscCall(NEPComputeJacobian(nep,lambda,matctx->J));
    149:   if (matctx->ksp) PetscCall(NEP_KSPSetOperators(matctx->ksp,matctx->F,matctx->P));
    150:   matctx->lambda = lambda;
    151:   PetscFunctionReturn(PETSC_SUCCESS);
    152: }

    154: static PetscErrorCode MatMult_NEPDeflationNE(Mat M,Vec x,Vec r)
    155: {
    156:   Vec                t,tt;
    157:   PetscScalar        *h,*alpha,lambda,*eig;
    158:   PetscInt           i,k;
    159:   NEP_NEDEF_MATSHELL *matctx;

    161:   PetscFunctionBegin;
    162:   PetscCall(MatShellGetContext(M,&matctx));
    163:   if (matctx->defctx->n && !matctx->defctx->ref) {
    164:     k = matctx->defctx->n;
    165:     lambda = matctx->lambda;
    166:     eig = matctx->defctx->eig;
    167:     t = matctx->w[0];
    168:     PetscCall(VecCopy(x,t));
    169:     PetscCall(PetscMalloc2(k,&h,k,&alpha));
    170:     for (i=0;i<k;i++) alpha[i] = (lambda-eig[i]-1.0)/(lambda-eig[i]);
    171:     PetscCall(BVDotVec(matctx->defctx->V,t,h));
    172:     for (i=0;i<k;i++) h[i] *= alpha[i];
    173:     PetscCall(BVMultVec(matctx->defctx->W,-1.0,1.0,t,h));
    174:     PetscCall(MatMult(matctx->isJ?matctx->J:matctx->F,t,r));
    175:     if (matctx->isJ) {
    176:       for (i=0;i<k;i++) h[i] *= (1.0/((lambda-eig[i])*(lambda-eig[i])))/alpha[i];
    177:       tt = matctx->w[1];
    178:       PetscCall(BVMultVec(matctx->defctx->W,-1.0,0.0,tt,h));
    179:       PetscCall(MatMult(matctx->F,tt,t));
    180:       PetscCall(VecAXPY(r,1.0,t));
    181:     }
    182:     PetscCall(PetscFree2(h,alpha));
    183:   } else PetscCall(MatMult(matctx->isJ?matctx->J:matctx->F,x,r));
    184:   PetscFunctionReturn(PETSC_SUCCESS);
    185: }

    187: static PetscErrorCode MatMultTranspose_NEPDeflationNE(Mat M,Vec x,Vec r)
    188: {
    189:   Vec                t,tt;
    190:   PetscScalar        *h,*alphaC,lambda,*eig;
    191:   PetscInt           i,k;
    192:   NEP_NEDEF_MATSHELL *matctx;

    194:   PetscFunctionBegin;
    195:   PetscCall(MatShellGetContext(M,&matctx));
    196:   t    = matctx->w[0];
    197:   PetscCall(VecCopy(x,t));
    198:   if (matctx->defctx->n && !matctx->defctx->ref) {
    199:     PetscCall(VecConjugate(t));
    200:     k = matctx->defctx->n;
    201:     lambda = matctx->lambda;
    202:     eig = matctx->defctx->eig;
    203:     PetscCall(PetscMalloc2(k,&h,k,&alphaC));
    204:     for (i=0;i<k;i++) alphaC[i] = PetscConj((lambda-eig[i]-1.0)/(lambda-eig[i]));
    205:     PetscCall(BVDotVec(matctx->defctx->W,t,h));
    206:     for (i=0;i<k;i++) h[i] *= alphaC[i];
    207:     PetscCall(BVMultVec(matctx->defctx->V,-1.0,1.0,t,h));
    208:     PetscCall(VecConjugate(t));
    209:     PetscCall(MatMultTranspose(matctx->isJ?matctx->J:matctx->F,t,r));
    210:     if (matctx->isJ) {
    211:       for (i=0;i<k;i++) h[i] *= PetscConj(1.0/((lambda-eig[i])*(lambda-eig[i])))/alphaC[i];
    212:       tt = matctx->w[1];
    213:       PetscCall(BVMultVec(matctx->defctx->V,-1.0,0.0,tt,h));
    214:       PetscCall(VecConjugate(tt));
    215:       PetscCall(MatMultTranspose(matctx->F,tt,t));
    216:       PetscCall(VecAXPY(r,1.0,t));
    217:     }
    218:     PetscCall(PetscFree2(h,alphaC));
    219:   } else PetscCall(MatMultTranspose(matctx->isJ?matctx->J:matctx->F,t,r));
    220:   PetscFunctionReturn(PETSC_SUCCESS);
    221: }

    223: static PetscErrorCode MatSolve_NEPDeflationNE(Mat M,Vec b,Vec x)
    224: {
    225:   PetscScalar        *h,*alpha,lambda,*eig;
    226:   PetscInt           i,k;
    227:   NEP_NEDEF_MATSHELL *matctx;

    229:   PetscFunctionBegin;
    230:   PetscCall(MatShellGetContext(M,&matctx));
    231:   if (!matctx->ksp) {
    232:     PetscCall(VecCopy(b,x));
    233:     PetscFunctionReturn(PETSC_SUCCESS);
    234:   }
    235:   PetscCall(KSPSolve(matctx->ksp,b,x));
    236:   if (matctx->defctx->n && !matctx->defctx->ref) {
    237:     k = matctx->defctx->n;
    238:     lambda = matctx->lambda;
    239:     eig = matctx->defctx->eig;
    240:     PetscCall(PetscMalloc2(k,&h,k,&alpha));
    241:     PetscCall(BVDotVec(matctx->defctx->V,x,h));
    242:     for (i=0;i<k;i++) alpha[i] = (lambda-eig[i]-1.0)/(lambda-eig[i]);
    243:     for (i=0;i<k;i++) h[i] *= alpha[i]/(1.0-alpha[i]);
    244:     PetscCall(BVMultVec(matctx->defctx->W,1.0,1.0,x,h));
    245:     PetscCall(PetscFree2(h,alpha));
    246:   }
    247:   PetscFunctionReturn(PETSC_SUCCESS);
    248: }

    250: static PetscErrorCode MatSolveTranspose_NEPDeflationNE(Mat M,Vec b,Vec x)
    251: {
    252:   PetscScalar        *h,*alphaC,lambda,*eig;
    253:   PetscInt           i,k;
    254:   NEP_NEDEF_MATSHELL *matctx;

    256:   PetscFunctionBegin;
    257:   PetscCall(MatShellGetContext(M,&matctx));
    258:   if (!matctx->ksp) {
    259:     PetscCall(VecCopy(b,x));
    260:     PetscFunctionReturn(PETSC_SUCCESS);
    261:   }
    262:   PetscCall(KSPSolveTranspose(matctx->ksp,b,x));
    263:   if (matctx->defctx->n && !matctx->defctx->ref) {
    264:     PetscCall(VecConjugate(x));
    265:     k = matctx->defctx->n;
    266:     lambda = matctx->lambda;
    267:     eig = matctx->defctx->eig;
    268:     PetscCall(PetscMalloc2(k,&h,k,&alphaC));
    269:     PetscCall(BVDotVec(matctx->defctx->W,x,h));
    270:     for (i=0;i<k;i++) alphaC[i] = PetscConj((lambda-eig[i]-1.0)/(lambda-eig[i]));
    271:     for (i=0;i<k;i++) h[i] *= alphaC[i]/(1.0-alphaC[i]);
    272:     PetscCall(BVMultVec(matctx->defctx->V,1.0,1.0,x,h));
    273:     PetscCall(PetscFree2(h,alphaC));
    274:     PetscCall(VecConjugate(x));
    275:   }
    276:   PetscFunctionReturn(PETSC_SUCCESS);
    277: }

    279: static PetscErrorCode MatDestroy_NEPDeflationNE(Mat M)
    280: {
    281:   NEP_NEDEF_MATSHELL *matctx;

    283:   PetscFunctionBegin;
    284:   PetscCall(MatShellGetContext(M,&matctx));
    285:   PetscCall(VecDestroy(&matctx->w[0]));
    286:   PetscCall(VecDestroy(&matctx->w[1]));
    287:   PetscCall(PetscFree(matctx));
    288:   PetscFunctionReturn(PETSC_SUCCESS);
    289: }

    291: static PetscErrorCode MatCreateVecs_NEPDeflationNE(Mat M,Vec *right,Vec *left)
    292: {
    293:   NEP_NEDEF_MATSHELL *matctx;

    295:   PetscFunctionBegin;
    296:   PetscCall(MatShellGetContext(M,&matctx));
    297:   PetscCall(MatCreateVecs(matctx->F,right,left));
    298:   PetscFunctionReturn(PETSC_SUCCESS);
    299: }

    301: static PetscErrorCode NEPDeflationNEFunctionCreate(NEP_NEDEF_CTX defctx,NEP nep,Mat F,Mat P,Mat J,KSP ksp,PetscBool isJ,Mat *Mshell)
    302: {
    303:   NEP_NEDEF_MATSHELL *matctx;
    304:   PetscInt           nloc,mloc;

    306:   PetscFunctionBegin;
    307:   /* Create mat shell */
    308:   PetscCall(PetscNew(&matctx));
    309:   PetscCall(MatGetLocalSize(nep->function,&mloc,&nloc));
    310:   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)nep),nloc,mloc,PETSC_DETERMINE,PETSC_DETERMINE,matctx,Mshell));
    311:   matctx->F   = F;
    312:   matctx->P   = P;
    313:   matctx->J   = J;
    314:   matctx->isJ = isJ;
    315:   matctx->ksp = ksp;
    316:   matctx->defctx = defctx;
    317:   matctx->lambda = PETSC_MAX_REAL;
    318:   PetscCall(MatCreateVecs(F,&matctx->w[0],NULL));
    319:   PetscCall(VecDuplicate(matctx->w[0],&matctx->w[1]));
    320:   PetscCall(MatShellSetOperation(*Mshell,MATOP_MULT,(PetscErrorCodeFn*)MatMult_NEPDeflationNE));
    321:   PetscCall(MatShellSetOperation(*Mshell,MATOP_MULT_TRANSPOSE,(PetscErrorCodeFn*)MatMultTranspose_NEPDeflationNE));
    322:   PetscCall(MatShellSetOperation(*Mshell,MATOP_SOLVE,(PetscErrorCodeFn*)MatSolve_NEPDeflationNE));
    323:   PetscCall(MatShellSetOperation(*Mshell,MATOP_SOLVE_TRANSPOSE,(PetscErrorCodeFn*)MatSolveTranspose_NEPDeflationNE));
    324:   PetscCall(MatShellSetOperation(*Mshell,MATOP_DESTROY,(PetscErrorCodeFn*)MatDestroy_NEPDeflationNE));
    325:   PetscCall(MatShellSetOperation(*Mshell,MATOP_CREATE_VECS,(PetscErrorCodeFn*)MatCreateVecs_NEPDeflationNE));
    326:   PetscFunctionReturn(PETSC_SUCCESS);
    327: }

    329: static PetscErrorCode NEPDeflationNERecoverEigenvectors(NEP_NEDEF_CTX defctx,Vec u,Vec w,PetscScalar lambda)
    330: {
    331:   PetscScalar    *h,*alpha,*eig;
    332:   PetscInt       i,k;

    334:   PetscFunctionBegin;
    335:   if (w) PetscCall(VecConjugate(w));
    336:   if (defctx->n && !defctx->ref) {
    337:     eig = defctx->eig;
    338:     k = defctx->n;
    339:     PetscCall(PetscMalloc2(k,&h,k,&alpha));
    340:     for (i=0;i<k;i++) alpha[i] = (lambda-eig[i]-1.0)/(lambda-eig[i]);
    341:     PetscCall(BVDotVec(defctx->V,u,h));
    342:     for (i=0;i<k;i++) h[i] *= alpha[i];
    343:     PetscCall(BVMultVec(defctx->W,-1.0,1.0,u,h));
    344:     PetscCall(VecNormalize(u,NULL));
    345:     if (w) {
    346:       PetscCall(BVDotVec(defctx->W,w,h));
    347:       for (i=0;i<k;i++) alpha[i] = PetscConj((lambda-eig[i]-1.0)/(lambda-eig[i]));
    348:       for (i=0;i<k;i++) h[i] *= alpha[i];
    349:       PetscCall(BVMultVec(defctx->V,-1.0,1.0,w,h));
    350:       PetscCall(VecNormalize(w,NULL));
    351:     }
    352:     PetscCall(PetscFree2(h,alpha));
    353:   }
    354:   PetscFunctionReturn(PETSC_SUCCESS);
    355: }

    357: static PetscErrorCode NEPDeflationNELocking(NEP_NEDEF_CTX defctx,Vec u,Vec w,PetscScalar lambda)
    358: {
    359:   PetscInt       n;

    361:   PetscFunctionBegin;
    362:   n = defctx->n++;
    363:   defctx->eig[n] = lambda;
    364:   PetscCall(BVInsertVec(defctx->V,n,u));
    365:   PetscCall(BVInsertVec(defctx->W,n,w));
    366:   PetscCall(BVSetActiveColumns(defctx->V,0,defctx->n));
    367:   PetscCall(BVSetActiveColumns(defctx->W,0,defctx->n));
    368:   PetscCall(BVBiorthonormalizeColumn(defctx->V,defctx->W,n,NULL));
    369:   PetscFunctionReturn(PETSC_SUCCESS);
    370: }

    372: static PetscErrorCode NEPDeflationNESetRefine(NEP_NEDEF_CTX defctx,PetscBool ref)
    373: {
    374:   PetscFunctionBegin;
    375:   defctx->ref = ref;
    376:   PetscFunctionReturn(PETSC_SUCCESS);
    377: }

    379: PetscErrorCode NEPSolve_SLP_Twosided(NEP nep)
    380: {
    381:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;
    382:   Mat            mF,mJ,M,Mt;
    383:   Vec            u,r,t,w;
    384:   BV             X,Y;
    385:   PetscScalar    sigma,lambda,mu,im=0.0,mu2,im2;
    386:   PetscReal      resnorm,resl;
    387:   PetscInt       nconv,nconv2,i;
    388:   PetscBool      skip=PETSC_FALSE,lock=PETSC_FALSE;
    389:   NEP_NEDEF_CTX  defctx=NULL;    /* Extended operator for deflation */

    391:   PetscFunctionBegin;
    392:   /* get initial approximation of eigenvalue and eigenvector */
    393:   PetscCall(NEPGetDefaultShift(nep,&sigma));
    394:   if (!nep->nini) PetscCall(BVSetRandomColumn(nep->V,0));
    395:   PetscCall(BVSetRandomColumn(nep->W,0));
    396:   lambda = sigma;
    397:   if (!ctx->ksp) PetscCall(NEPSLPGetKSP(nep,&ctx->ksp));
    398:   PetscCall(BVDuplicate(nep->V,&X));
    399:   PetscCall(BVDuplicate(nep->W,&Y));
    400:   PetscCall(NEPDeflationNECreate(nep,X,Y,nep->nev,&defctx));
    401:   PetscCall(BVGetColumn(nep->V,0,&t));
    402:   PetscCall(VecDuplicate(t,&u));
    403:   PetscCall(VecDuplicate(t,&w));
    404:   PetscCall(BVRestoreColumn(nep->V,0,&t));
    405:   PetscCall(BVCopyVec(nep->V,0,u));
    406:   PetscCall(BVCopyVec(nep->W,0,w));
    407:   PetscCall(VecDuplicate(u,&r));
    408:   PetscCall(NEPDeflationNEFunctionCreate(defctx,nep,nep->function,nep->function_pre?nep->function_pre:nep->function,NULL,ctx->ksp,PETSC_FALSE,&mF));
    409:   PetscCall(NEPDeflationNEFunctionCreate(defctx,nep,nep->function,nep->function,nep->jacobian,NULL,PETSC_TRUE,&mJ));
    410:   PetscCall(NEPSLPSetUpEPSMat(nep,mF,mJ,PETSC_FALSE,&M));
    411:   PetscCall(NEPSLPSetUpEPSMat(nep,mF,mJ,PETSC_TRUE,&Mt));
    412:   PetscCall(EPSSetOperators(ctx->eps,M,NULL));
    413:   PetscCall(MatDestroy(&M));
    414:   PetscCall(EPSSetOperators(ctx->epsts,Mt,NULL));
    415:   PetscCall(MatDestroy(&Mt));

    417:   /* Restart loop */
    418:   while (nep->reason == NEP_CONVERGED_ITERATING) {
    419:     nep->its++;

    421:     /* form residual,  r = T(lambda)*u (used in convergence test only) */
    422:     PetscCall(NEPDeflationNEComputeFunction(nep,mF,lambda));
    423:     PetscCall(MatMultTranspose(mF,w,r));
    424:     PetscCall(VecNorm(r,NORM_2,&resl));
    425:     PetscCall(MatMult(mF,u,r));

    427:     /* convergence test */
    428:     PetscCall(VecNorm(r,NORM_2,&resnorm));
    429:     resnorm = PetscMax(resnorm,resl);
    430:     PetscCall((*nep->converged)(nep,lambda,0,resnorm,&nep->errest[nep->nconv],nep->convergedctx));
    431:     nep->eigr[nep->nconv] = lambda;
    432:     if (nep->errest[nep->nconv]<=nep->tol || nep->errest[nep->nconv]<=ctx->deftol) {
    433:       if (nep->errest[nep->nconv]<=ctx->deftol && !defctx->ref && nep->nconv) {
    434:         PetscCall(NEPDeflationNERecoverEigenvectors(defctx,u,w,lambda));
    435:         PetscCall(VecConjugate(w));
    436:         PetscCall(NEPDeflationNESetRefine(defctx,PETSC_TRUE));
    437:         PetscCall(MatMultTranspose(mF,w,r));
    438:         PetscCall(VecNorm(r,NORM_2,&resl));
    439:         PetscCall(MatMult(mF,u,r));
    440:         PetscCall(VecNorm(r,NORM_2,&resnorm));
    441:         resnorm = PetscMax(resnorm,resl);
    442:         PetscCall((*nep->converged)(nep,lambda,0,resnorm,&nep->errest[nep->nconv],nep->convergedctx));
    443:         if (nep->errest[nep->nconv]<=nep->tol) lock = PETSC_TRUE;
    444:       } else if (nep->errest[nep->nconv]<=nep->tol) lock = PETSC_TRUE;
    445:     }
    446:     if (lock) {
    447:       lock = PETSC_FALSE;
    448:       skip = PETSC_TRUE;
    449:       PetscCall(NEPDeflationNERecoverEigenvectors(defctx,u,w,lambda));
    450:       PetscCall(NEPDeflationNELocking(defctx,u,w,lambda));
    451:       PetscCall(NEPDeflationNESetRefine(defctx,PETSC_FALSE));
    452:       PetscCall(BVInsertVec(nep->V,nep->nconv,u));
    453:       PetscCall(BVInsertVec(nep->W,nep->nconv,w));
    454:       PetscCall(VecConjugate(w));
    455:       nep->nconv = nep->nconv + 1;
    456:     }
    457:     PetscCall((*nep->stopping)(nep,nep->its,nep->max_it,nep->nconv,nep->nev,&nep->reason,nep->stoppingctx));
    458:     if (!skip || nep->reason>0) PetscCall(NEPMonitor(nep,nep->its,nep->nconv,nep->eigr,nep->eigi,nep->errest,(nep->reason>0)?nep->nconv:nep->nconv+1));

    460:     if (nep->reason == NEP_CONVERGED_ITERATING) {
    461:       if (!skip) {
    462:         /* evaluate T(lambda) and T'(lambda) */
    463:         PetscCall(NEPDeflationNEComputeFunction(nep,mF,lambda));
    464:         PetscCall(NEPDeflationNEComputeFunction(nep,mJ,lambda));
    465:         PetscCall(EPSSetInitialSpace(ctx->eps,1,&u));
    466:         PetscCall(EPSSetInitialSpace(ctx->epsts,1,&w));

    468:         /* compute new eigenvalue correction mu and eigenvector approximation u */
    469:         PetscCall(EPSSolve(ctx->eps));
    470:         PetscCall(EPSSolve(ctx->epsts));
    471:         PetscCall(EPSGetConverged(ctx->eps,&nconv));
    472:         PetscCall(EPSGetConverged(ctx->epsts,&nconv2));
    473:         if (!nconv||!nconv2) {
    474:           PetscCall(PetscInfo(nep,"iter=%" PetscInt_FMT ", inner iteration failed, stopping solve\n",nep->its));
    475:           nep->reason = NEP_DIVERGED_LINEAR_SOLVE;
    476:           break;
    477:         }
    478:         PetscCall(EPSGetEigenpair(ctx->eps,0,&mu,&im,u,NULL));
    479:         for (i=0;i<nconv2;i++) {
    480:           PetscCall(EPSGetEigenpair(ctx->epsts,i,&mu2,&im2,w,NULL));
    481:           if (SlepcAbsEigenvalue(mu-mu2,im-im2)/SlepcAbsEigenvalue(mu,im)<nep->tol*1000) break;
    482:         }
    483:         if (i==nconv2) {
    484:           PetscCall(PetscInfo(nep,"iter=%" PetscInt_FMT ", inner iteration failed, stopping solve\n",nep->its));
    485:           nep->reason = NEP_DIVERGED_LINEAR_SOLVE;
    486:           break;
    487:         }

    489:         mu = 1.0/mu;
    490:         PetscCheck(PetscAbsScalar(im)<PETSC_MACHINE_EPSILON,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Complex eigenvalue approximation - not implemented in real scalars");
    491:       } else {
    492:         nep->its--;  /* do not count this as a full iteration */
    493:         /* use second eigenpair computed in previous iteration */
    494:         PetscCall(EPSGetConverged(ctx->eps,&nconv));
    495:         if (nconv>=2 && nconv2>=2) {
    496:           PetscCall(EPSGetEigenpair(ctx->eps,1,&mu,&im,u,NULL));
    497:           PetscCall(EPSGetEigenpair(ctx->epsts,1,&mu2,&im2,w,NULL));
    498:           mu = 1.0/mu;
    499:         } else {
    500:           PetscCall(BVSetRandomColumn(nep->V,nep->nconv));
    501:           PetscCall(BVSetRandomColumn(nep->W,nep->nconv));
    502:           PetscCall(BVCopyVec(nep->V,nep->nconv,u));
    503:           PetscCall(BVCopyVec(nep->W,nep->nconv,w));
    504:           mu = lambda-sigma;
    505:         }
    506:         skip = PETSC_FALSE;
    507:       }
    508:       /* correct eigenvalue */
    509:       lambda = lambda - mu;
    510:     }
    511:   }
    512:   PetscCall(VecDestroy(&u));
    513:   PetscCall(VecDestroy(&w));
    514:   PetscCall(VecDestroy(&r));
    515:   PetscCall(MatDestroy(&mF));
    516:   PetscCall(MatDestroy(&mJ));
    517:   PetscCall(BVDestroy(&X));
    518:   PetscCall(BVDestroy(&Y));
    519:   PetscCall(NEPDeflationNEDestroy(defctx));
    520:   PetscFunctionReturn(PETSC_SUCCESS);
    521: }