Actual source code: rii.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:    SLEPc nonlinear eigensolver: "rii"

     13:    Method: Residual inverse iteration

     15:    Algorithm:

     17:        Simple residual inverse iteration with varying shift.

     19:    References:

     21:        [1] A. Neumaier, "Residual inverse iteration for the nonlinear
     22:            eigenvalue problem", SIAM J. Numer. Anal. 22(5):914-923, 1985.
     23: */

     25: #include <slepc/private/nepimpl.h>
     26: #include <../src/nep/impls/nepdefl.h>

     28: typedef struct {
     29:   PetscInt  max_inner_it;     /* maximum number of Newton iterations */
     30:   PetscInt  lag;              /* interval to rebuild preconditioner */
     31:   PetscBool cctol;            /* constant correction tolerance */
     32:   PetscBool herm;             /* whether the Hermitian version of the scalar equation must be used */
     33:   PetscReal deftol;           /* tolerance for the deflation (threshold) */
     34:   KSP       ksp;              /* linear solver object */
     35: } NEP_RII;

     37: static PetscErrorCode NEPSetUp_RII(NEP nep)
     38: {
     39:   PetscFunctionBegin;
     40:   if (nep->ncv!=PETSC_DETERMINE) PetscCall(PetscInfo(nep,"Setting ncv = nev, ignoring user-provided value\n"));
     41:   nep->ncv = nep->nev;
     42:   if (nep->mpd!=PETSC_DETERMINE) PetscCall(PetscInfo(nep,"Setting mpd = nev, ignoring user-provided value\n"));
     43:   nep->mpd = nep->nev;
     44:   if (nep->max_it==PETSC_DETERMINE) nep->max_it = PetscMax(5000,2*nep->n/nep->ncv);
     45:   if (!nep->which) nep->which = NEP_TARGET_MAGNITUDE;
     46:   PetscCheck(nep->which==NEP_TARGET_MAGNITUDE,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"This solver supports only target magnitude eigenvalues");
     47:   NEPCheckUnsupported(nep,NEP_FEATURE_REGION | NEP_FEATURE_TWOSIDED);
     48:   PetscCall(NEPAllocateSolution(nep,0));
     49:   PetscCall(NEPSetWorkVecs(nep,2));
     50:   PetscFunctionReturn(PETSC_SUCCESS);
     51: }

     53: static PetscErrorCode NEPSolve_RII(NEP nep)
     54: {
     55:   NEP_RII            *ctx = (NEP_RII*)nep->data;
     56:   Mat                T,Tp,H,A;
     57:   Vec                uu,u,r,delta,t;
     58:   PetscScalar        lambda,lambda2,sigma,a1,a2,corr;
     59:   PetscReal          nrm,resnorm=1.0,ktol=0.1,perr,rtol;
     60:   PetscBool          skip=PETSC_FALSE,lock=PETSC_FALSE;
     61:   PetscInt           inner_its,its=0;
     62:   NEP_EXT_OP         extop=NULL;
     63:   KSPConvergedReason kspreason;

     65:   PetscFunctionBegin;
     66:   /* get initial approximation of eigenvalue and eigenvector */
     67:   PetscCall(NEPGetDefaultShift(nep,&sigma));
     68:   lambda = sigma;
     69:   if (!nep->nini) {
     70:     PetscCall(BVSetRandomColumn(nep->V,0));
     71:     PetscCall(BVNormColumn(nep->V,0,NORM_2,&nrm));
     72:     PetscCall(BVScaleColumn(nep->V,0,1.0/nrm));
     73:   }
     74:   if (!ctx->ksp) PetscCall(NEPRIIGetKSP(nep,&ctx->ksp));
     75:   PetscCall(NEPDeflationInitialize(nep,nep->V,ctx->ksp,PETSC_FALSE,nep->nev,&extop));
     76:   PetscCall(NEPDeflationCreateVec(extop,&u));
     77:   PetscCall(VecDuplicate(u,&r));
     78:   PetscCall(VecDuplicate(u,&delta));
     79:   PetscCall(BVGetColumn(nep->V,0,&uu));
     80:   PetscCall(NEPDeflationCopyToExtendedVec(extop,uu,NULL,u,PETSC_FALSE));
     81:   PetscCall(BVRestoreColumn(nep->V,0,&uu));

     83:   /* prepare linear solver */
     84:   PetscCall(NEPDeflationSolveSetUp(extop,sigma));
     85:   PetscCall(KSPGetTolerances(ctx->ksp,&rtol,NULL,NULL,NULL));

     87:   PetscCall(VecCopy(u,r));
     88:   PetscCall(NEPDeflationFunctionSolve(extop,r,u));
     89:   PetscCall(VecNorm(u,NORM_2,&nrm));
     90:   PetscCall(VecScale(u,1.0/nrm));

     92:   /* Restart loop */
     93:   while (nep->reason == NEP_CONVERGED_ITERATING) {
     94:     its++;

     96:     /* Use Newton's method to compute nonlinear Rayleigh functional. Current eigenvalue
     97:        estimate as starting value. */
     98:     inner_its=0;
     99:     lambda2 = lambda;
    100:     do {
    101:       PetscCall(NEPDeflationComputeFunction(extop,lambda,&T));
    102:       PetscCall(MatMult(T,u,r));
    103:       if (!ctx->herm) {
    104:         PetscCall(NEPDeflationFunctionSolve(extop,r,delta));
    105:         PetscCall(KSPGetConvergedReason(ctx->ksp,&kspreason));
    106:         if (kspreason<0) PetscCall(PetscInfo(nep,"iter=%" PetscInt_FMT ", linear solve failed\n",nep->its));
    107:         t = delta;
    108:       } else t = r;
    109:       PetscCall(VecDot(t,u,&a1));
    110:       PetscCall(NEPDeflationComputeJacobian(extop,lambda,&Tp));
    111:       PetscCall(MatMult(Tp,u,r));
    112:       if (!ctx->herm) {
    113:         PetscCall(NEPDeflationFunctionSolve(extop,r,delta));
    114:         PetscCall(KSPGetConvergedReason(ctx->ksp,&kspreason));
    115:         if (kspreason<0) PetscCall(PetscInfo(nep,"iter=%" PetscInt_FMT ", linear solve failed\n",nep->its));
    116:         t = delta;
    117:       } else t = r;
    118:       PetscCall(VecDot(t,u,&a2));
    119:       corr = a1/a2;
    120:       lambda = lambda - corr;
    121:       inner_its++;
    122:     } while (PetscAbsScalar(corr)/PetscAbsScalar(lambda)>PETSC_SQRT_MACHINE_EPSILON && inner_its<ctx->max_inner_it);

    124:     /* form residual,  r = T(lambda)*u */
    125:     PetscCall(NEPDeflationComputeFunction(extop,lambda,&T));
    126:     PetscCall(MatMult(T,u,r));

    128:     /* convergence test */
    129:     perr = nep->errest[nep->nconv];
    130:     PetscCall(VecNorm(r,NORM_2,&resnorm));
    131:     PetscCall((*nep->converged)(nep,lambda,0,resnorm,&nep->errest[nep->nconv],nep->convergedctx));
    132:     nep->eigr[nep->nconv] = lambda;
    133:     if (its>1 && (nep->errest[nep->nconv]<=nep->tol || nep->errest[nep->nconv]<=ctx->deftol)) {
    134:       if (nep->errest[nep->nconv]<=ctx->deftol && !extop->ref && nep->nconv) {
    135:         PetscCall(NEPDeflationExtractEigenpair(extop,nep->nconv,u,lambda,nep->ds));
    136:         PetscCall(NEPDeflationSetRefine(extop,PETSC_TRUE));
    137:         PetscCall(MatMult(T,u,r));
    138:         PetscCall(VecNorm(r,NORM_2,&resnorm));
    139:         PetscCall((*nep->converged)(nep,lambda,0,resnorm,&nep->errest[nep->nconv],nep->convergedctx));
    140:         if (nep->errest[nep->nconv]<=nep->tol) lock = PETSC_TRUE;
    141:       } else if (nep->errest[nep->nconv]<=nep->tol) lock = PETSC_TRUE;
    142:     }
    143:     if (lock) {
    144:       PetscCall(NEPDeflationSetRefine(extop,PETSC_FALSE));
    145:       nep->nconv = nep->nconv + 1;
    146:       PetscCall(NEPDeflationLocking(extop,u,lambda));
    147:       nep->its += its;
    148:       skip = PETSC_TRUE;
    149:       lock = PETSC_FALSE;
    150:     }
    151:     PetscCall((*nep->stopping)(nep,nep->its+its,nep->max_it,nep->nconv,nep->nev,&nep->reason,nep->stoppingctx));
    152:     if (!skip || nep->reason>0) PetscCall(NEPMonitor(nep,nep->its+its,nep->nconv,nep->eigr,nep->eigi,nep->errest,(nep->reason>0)?nep->nconv:nep->nconv+1));

    154:     if (nep->reason == NEP_CONVERGED_ITERATING) {
    155:       if (!skip) {
    156:         /* update preconditioner and set adaptive tolerance */
    157:         if (ctx->lag && !(its%ctx->lag) && its>=2*ctx->lag && perr && nep->errest[nep->nconv]>.5*perr) PetscCall(NEPDeflationSolveSetUp(extop,lambda2));
    158:         if (!ctx->cctol) {
    159:           ktol = PetscMax(ktol/2.0,rtol);
    160:           PetscCall(KSPSetTolerances(ctx->ksp,ktol,PETSC_CURRENT,PETSC_CURRENT,PETSC_CURRENT));
    161:         }

    163:         /* eigenvector correction: delta = T(sigma)\r */
    164:         PetscCall(NEPDeflationFunctionSolve(extop,r,delta));
    165:         PetscCall(KSPGetConvergedReason(ctx->ksp,&kspreason));
    166:         if (kspreason<0) {
    167:           PetscCall(PetscInfo(nep,"iter=%" PetscInt_FMT ", linear solve failed, stopping solve\n",nep->its));
    168:           nep->reason = NEP_DIVERGED_LINEAR_SOLVE;
    169:           break;
    170:         }

    172:         /* update eigenvector: u = u - delta */
    173:         PetscCall(VecAXPY(u,-1.0,delta));

    175:         /* normalize eigenvector */
    176:         PetscCall(VecNormalize(u,NULL));
    177:       } else {
    178:         its = -1;
    179:         PetscCall(NEPDeflationSetRandomVec(extop,u));
    180:         PetscCall(NEPDeflationSolveSetUp(extop,sigma));
    181:         PetscCall(VecCopy(u,r));
    182:         PetscCall(NEPDeflationFunctionSolve(extop,r,u));
    183:         PetscCall(VecNorm(u,NORM_2,&nrm));
    184:         PetscCall(VecScale(u,1.0/nrm));
    185:         lambda = sigma;
    186:         skip = PETSC_FALSE;
    187:       }
    188:     }
    189:   }
    190:   PetscCall(NEPDeflationGetInvariantPair(extop,NULL,&H));
    191:   PetscCall(DSSetType(nep->ds,DSNHEP));
    192:   PetscCall(DSAllocate(nep->ds,PetscMax(nep->nconv,1)));
    193:   PetscCall(DSSetDimensions(nep->ds,nep->nconv,0,nep->nconv));
    194:   PetscCall(DSGetMat(nep->ds,DS_MAT_A,&A));
    195:   PetscCall(MatCopy(H,A,SAME_NONZERO_PATTERN));
    196:   PetscCall(DSRestoreMat(nep->ds,DS_MAT_A,&A));
    197:   PetscCall(MatDestroy(&H));
    198:   PetscCall(DSSolve(nep->ds,nep->eigr,nep->eigi));
    199:   PetscCall(NEPDeflationReset(extop));
    200:   PetscCall(VecDestroy(&u));
    201:   PetscCall(VecDestroy(&r));
    202:   PetscCall(VecDestroy(&delta));
    203:   PetscFunctionReturn(PETSC_SUCCESS);
    204: }

    206: static PetscErrorCode NEPSetFromOptions_RII(NEP nep,PetscOptionItems PetscOptionsObject)
    207: {
    208:   NEP_RII        *ctx = (NEP_RII*)nep->data;
    209:   PetscBool      flg;
    210:   PetscInt       i;
    211:   PetscReal      r;

    213:   PetscFunctionBegin;
    214:   PetscOptionsHeadBegin(PetscOptionsObject,"NEP RII Options");

    216:     i = 0;
    217:     PetscCall(PetscOptionsInt("-nep_rii_max_it","Maximum number of Newton iterations for updating Rayleigh functional","NEPRIISetMaximumIterations",ctx->max_inner_it,&i,&flg));
    218:     if (flg) PetscCall(NEPRIISetMaximumIterations(nep,i));

    220:     PetscCall(PetscOptionsBool("-nep_rii_const_correction_tol","Constant correction tolerance for the linear solver","NEPRIISetConstCorrectionTol",ctx->cctol,&ctx->cctol,NULL));

    222:     PetscCall(PetscOptionsBool("-nep_rii_hermitian","Use Hermitian version of the scalar nonlinear equation","NEPRIISetHermitian",ctx->herm,&ctx->herm,NULL));

    224:     i = 0;
    225:     PetscCall(PetscOptionsInt("-nep_rii_lag_preconditioner","Interval to rebuild preconditioner","NEPRIISetLagPreconditioner",ctx->lag,&i,&flg));
    226:     if (flg) PetscCall(NEPRIISetLagPreconditioner(nep,i));

    228:     r = 0.0;
    229:     PetscCall(PetscOptionsReal("-nep_rii_deflation_threshold","Tolerance used as a threshold for including deflated eigenpairs","NEPRIISetDeflationThreshold",ctx->deftol,&r,&flg));
    230:     if (flg) PetscCall(NEPRIISetDeflationThreshold(nep,r));

    232:   PetscOptionsHeadEnd();

    234:   if (!ctx->ksp) PetscCall(NEPRIIGetKSP(nep,&ctx->ksp));
    235:   PetscCall(KSPSetFromOptions(ctx->ksp));
    236:   PetscFunctionReturn(PETSC_SUCCESS);
    237: }

    239: static PetscErrorCode NEPRIISetMaximumIterations_RII(NEP nep,PetscInt its)
    240: {
    241:   NEP_RII *ctx = (NEP_RII*)nep->data;

    243:   PetscFunctionBegin;
    244:   if (its==PETSC_DEFAULT || its==PETSC_DECIDE) ctx->max_inner_it = 10;
    245:   else {
    246:     PetscCheck(its>0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of iterations must be >0");
    247:     ctx->max_inner_it = its;
    248:   }
    249:   PetscFunctionReturn(PETSC_SUCCESS);
    250: }

    252: /*@
    253:    NEPRIISetMaximumIterations - Sets the maximum number of inner iterations to be
    254:    used in the RII solver. These are the Newton iterations related to the computation
    255:    of the nonlinear Rayleigh functional.

    257:    Logically Collective

    259:    Input Parameters:
    260: +  nep - the nonlinear eigensolver context
    261: -  its - maximum inner iterations

    263:    Level: advanced

    265: .seealso: [](ch:nep), `NEPRII`, `NEPRIIGetMaximumIterations()`
    266: @*/
    267: PetscErrorCode NEPRIISetMaximumIterations(NEP nep,PetscInt its)
    268: {
    269:   PetscFunctionBegin;
    272:   PetscTryMethod(nep,"NEPRIISetMaximumIterations_C",(NEP,PetscInt),(nep,its));
    273:   PetscFunctionReturn(PETSC_SUCCESS);
    274: }

    276: static PetscErrorCode NEPRIIGetMaximumIterations_RII(NEP nep,PetscInt *its)
    277: {
    278:   NEP_RII *ctx = (NEP_RII*)nep->data;

    280:   PetscFunctionBegin;
    281:   *its = ctx->max_inner_it;
    282:   PetscFunctionReturn(PETSC_SUCCESS);
    283: }

    285: /*@
    286:    NEPRIIGetMaximumIterations - Gets the maximum number of inner iterations of RII.

    288:    Not Collective

    290:    Input Parameter:
    291: .  nep - the nonlinear eigensolver context

    293:    Output Parameter:
    294: .  its - maximum inner iterations

    296:    Level: advanced

    298: .seealso: [](ch:nep), `NEPRII`, `NEPRIISetMaximumIterations()`
    299: @*/
    300: PetscErrorCode NEPRIIGetMaximumIterations(NEP nep,PetscInt *its)
    301: {
    302:   PetscFunctionBegin;
    304:   PetscAssertPointer(its,2);
    305:   PetscUseMethod(nep,"NEPRIIGetMaximumIterations_C",(NEP,PetscInt*),(nep,its));
    306:   PetscFunctionReturn(PETSC_SUCCESS);
    307: }

    309: static PetscErrorCode NEPRIISetLagPreconditioner_RII(NEP nep,PetscInt lag)
    310: {
    311:   NEP_RII *ctx = (NEP_RII*)nep->data;

    313:   PetscFunctionBegin;
    314:   PetscCheck(lag>=0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Lag must be non-negative");
    315:   ctx->lag = lag;
    316:   PetscFunctionReturn(PETSC_SUCCESS);
    317: }

    319: /*@
    320:    NEPRIISetLagPreconditioner - Determines when the preconditioner is rebuilt in the
    321:    nonlinear solve.

    323:    Logically Collective

    325:    Input Parameters:
    326: +  nep - the nonlinear eigensolver context
    327: -  lag - 0 indicates NEVER rebuild, 1 means rebuild every time the Jacobian is
    328:           computed within the nonlinear iteration, 2 means every second time
    329:           the Jacobian is built, etc.

    331:    Options Database Key:
    332: .  -nep_rii_lag_preconditioner \<lag\> - the lag value

    334:    Notes:
    335:    The default is 1.
    336:    The preconditioner is ALWAYS built in the first iteration of a nonlinear solve.

    338:    Level: intermediate

    340: .seealso: [](ch:nep), `NEPRII`, `NEPRIIGetLagPreconditioner()`
    341: @*/
    342: PetscErrorCode NEPRIISetLagPreconditioner(NEP nep,PetscInt lag)
    343: {
    344:   PetscFunctionBegin;
    347:   PetscTryMethod(nep,"NEPRIISetLagPreconditioner_C",(NEP,PetscInt),(nep,lag));
    348:   PetscFunctionReturn(PETSC_SUCCESS);
    349: }

    351: static PetscErrorCode NEPRIIGetLagPreconditioner_RII(NEP nep,PetscInt *lag)
    352: {
    353:   NEP_RII *ctx = (NEP_RII*)nep->data;

    355:   PetscFunctionBegin;
    356:   *lag = ctx->lag;
    357:   PetscFunctionReturn(PETSC_SUCCESS);
    358: }

    360: /*@
    361:    NEPRIIGetLagPreconditioner - Indicates how often the preconditioner is rebuilt.

    363:    Not Collective

    365:    Input Parameter:
    366: .  nep - the nonlinear eigensolver context

    368:    Output Parameter:
    369: .  lag - the lag parameter

    371:    Level: intermediate

    373: .seealso: [](ch:nep), `NEPRII`, `NEPRIISetLagPreconditioner()`
    374: @*/
    375: PetscErrorCode NEPRIIGetLagPreconditioner(NEP nep,PetscInt *lag)
    376: {
    377:   PetscFunctionBegin;
    379:   PetscAssertPointer(lag,2);
    380:   PetscUseMethod(nep,"NEPRIIGetLagPreconditioner_C",(NEP,PetscInt*),(nep,lag));
    381:   PetscFunctionReturn(PETSC_SUCCESS);
    382: }

    384: static PetscErrorCode NEPRIISetConstCorrectionTol_RII(NEP nep,PetscBool cct)
    385: {
    386:   NEP_RII *ctx = (NEP_RII*)nep->data;

    388:   PetscFunctionBegin;
    389:   ctx->cctol = cct;
    390:   PetscFunctionReturn(PETSC_SUCCESS);
    391: }

    393: /*@
    394:    NEPRIISetConstCorrectionTol - Sets a flag to keep the tolerance used
    395:    in the linear solver constant.

    397:    Logically Collective

    399:    Input Parameters:
    400: +  nep - the nonlinear eigensolver context
    401: -  cct - if `PETSC_FALSE`, the `KSP` relative tolerance is set to $2^{-i}$

    403:    Options Database Key:
    404: .  -nep_rii_const_correction_tol - set a constant or dynamic stopping criterion

    406:    Notes:
    407:    By default, an exponentially decreasing tolerance is set in the `KSP` used
    408:    within the nonlinear iteration, so that each Newton iteration requests
    409:    better accuracy than the previous one. The constant correction tolerance
    410:    flag stops this behavior.

    412:    Level: intermediate

    414: .seealso: [](ch:nep), `NEPRII`, `NEPRIIGetConstCorrectionTol()`, `NEPRIIGetKSP()`
    415: @*/
    416: PetscErrorCode NEPRIISetConstCorrectionTol(NEP nep,PetscBool cct)
    417: {
    418:   PetscFunctionBegin;
    421:   PetscTryMethod(nep,"NEPRIISetConstCorrectionTol_C",(NEP,PetscBool),(nep,cct));
    422:   PetscFunctionReturn(PETSC_SUCCESS);
    423: }

    425: static PetscErrorCode NEPRIIGetConstCorrectionTol_RII(NEP nep,PetscBool *cct)
    426: {
    427:   NEP_RII *ctx = (NEP_RII*)nep->data;

    429:   PetscFunctionBegin;
    430:   *cct = ctx->cctol;
    431:   PetscFunctionReturn(PETSC_SUCCESS);
    432: }

    434: /*@
    435:    NEPRIIGetConstCorrectionTol - Returns the constant tolerance flag.

    437:    Not Collective

    439:    Input Parameter:
    440: .  nep - the nonlinear eigensolver context

    442:    Output Parameter:
    443: .  cct - the value of the constant tolerance flag

    445:    Level: intermediate

    447: .seealso: [](ch:nep), `NEPRII`, `NEPRIISetConstCorrectionTol()`
    448: @*/
    449: PetscErrorCode NEPRIIGetConstCorrectionTol(NEP nep,PetscBool *cct)
    450: {
    451:   PetscFunctionBegin;
    453:   PetscAssertPointer(cct,2);
    454:   PetscUseMethod(nep,"NEPRIIGetConstCorrectionTol_C",(NEP,PetscBool*),(nep,cct));
    455:   PetscFunctionReturn(PETSC_SUCCESS);
    456: }

    458: static PetscErrorCode NEPRIISetHermitian_RII(NEP nep,PetscBool herm)
    459: {
    460:   NEP_RII *ctx = (NEP_RII*)nep->data;

    462:   PetscFunctionBegin;
    463:   ctx->herm = herm;
    464:   PetscFunctionReturn(PETSC_SUCCESS);
    465: }

    467: /*@
    468:    NEPRIISetHermitian - Sets a flag to indicate if the Hermitian version of the
    469:    scalar nonlinear equation must be used by the solver.

    471:    Logically Collective

    473:    Input Parameters:
    474: +  nep  - the nonlinear eigensolver context
    475: -  herm - `PETSC_TRUE` if the Hermitian version is preferred

    477:    Options Database Key:
    478: .  -nep_rii_hermitian - toggle the Hermitian version

    480:    Notes:
    481:    By default, the scalar nonlinear equation $x^*T(\sigma)^{-1}T(z)x=0$ is solved
    482:    at each step of the nonlinear iteration. When this flag is set the simpler
    483:    form $x^*T(z)x=0$ is used, which is supposed to be valid only for Hermitian
    484:    problems.

    486:    Level: intermediate

    488: .seealso: [](ch:nep), `NEPRII`, `NEPRIIGetHermitian()`
    489: @*/
    490: PetscErrorCode NEPRIISetHermitian(NEP nep,PetscBool herm)
    491: {
    492:   PetscFunctionBegin;
    495:   PetscTryMethod(nep,"NEPRIISetHermitian_C",(NEP,PetscBool),(nep,herm));
    496:   PetscFunctionReturn(PETSC_SUCCESS);
    497: }

    499: static PetscErrorCode NEPRIIGetHermitian_RII(NEP nep,PetscBool *herm)
    500: {
    501:   NEP_RII *ctx = (NEP_RII*)nep->data;

    503:   PetscFunctionBegin;
    504:   *herm = ctx->herm;
    505:   PetscFunctionReturn(PETSC_SUCCESS);
    506: }

    508: /*@
    509:    NEPRIIGetHermitian - Returns the flag about using the Hermitian version of
    510:    the scalar nonlinear equation.

    512:    Not Collective

    514:    Input Parameter:
    515: .  nep - the nonlinear eigensolver context

    517:    Output Parameter:
    518: .  herm - the value of the Hermitian flag

    520:    Level: intermediate

    522: .seealso: [](ch:nep), `NEPRII`, `NEPRIISetHermitian()`
    523: @*/
    524: PetscErrorCode NEPRIIGetHermitian(NEP nep,PetscBool *herm)
    525: {
    526:   PetscFunctionBegin;
    528:   PetscAssertPointer(herm,2);
    529:   PetscUseMethod(nep,"NEPRIIGetHermitian_C",(NEP,PetscBool*),(nep,herm));
    530:   PetscFunctionReturn(PETSC_SUCCESS);
    531: }

    533: static PetscErrorCode NEPRIISetDeflationThreshold_RII(NEP nep,PetscReal deftol)
    534: {
    535:   NEP_RII *ctx = (NEP_RII*)nep->data;

    537:   PetscFunctionBegin;
    538:   ctx->deftol = deftol;
    539:   PetscFunctionReturn(PETSC_SUCCESS);
    540: }

    542: /*@
    543:    NEPRIISetDeflationThreshold - Sets the threshold value used to switch between
    544:    deflated and non-deflated iteration.

    546:    Logically Collective

    548:    Input Parameters:
    549: +  nep    - the nonlinear eigensolver context
    550: -  deftol - the threshold value

    552:    Options Database Key:
    553: .  -nep_rii_deflation_threshold \<deftol\> - set the threshold

    555:    Note:
    556:    Normally, the solver iterates on the extended problem in order to deflate
    557:    previously converged eigenpairs. If this threshold is set to a nonzero value,
    558:    then once the residual error is below this threshold the solver will
    559:    continue the iteration without deflation. The intention is to be able to
    560:    improve the current eigenpair further, despite having previous eigenpairs
    561:    with somewhat bad precision.

    563:    Level: advanced

    565: .seealso: [](ch:nep), `NEPRII`, `NEPRIIGetDeflationThreshold()`
    566: @*/
    567: PetscErrorCode NEPRIISetDeflationThreshold(NEP nep,PetscReal deftol)
    568: {
    569:   PetscFunctionBegin;
    572:   PetscTryMethod(nep,"NEPRIISetDeflationThreshold_C",(NEP,PetscReal),(nep,deftol));
    573:   PetscFunctionReturn(PETSC_SUCCESS);
    574: }

    576: static PetscErrorCode NEPRIIGetDeflationThreshold_RII(NEP nep,PetscReal *deftol)
    577: {
    578:   NEP_RII *ctx = (NEP_RII*)nep->data;

    580:   PetscFunctionBegin;
    581:   *deftol = ctx->deftol;
    582:   PetscFunctionReturn(PETSC_SUCCESS);
    583: }

    585: /*@
    586:    NEPRIIGetDeflationThreshold - Returns the threshold value that controls deflation.

    588:    Not Collective

    590:    Input Parameter:
    591: .  nep - the nonlinear eigensolver context

    593:    Output Parameter:
    594: .  deftol - the threshold

    596:    Level: advanced

    598: .seealso: [](ch:nep), `NEPRII`, `NEPRIISetDeflationThreshold()`
    599: @*/
    600: PetscErrorCode NEPRIIGetDeflationThreshold(NEP nep,PetscReal *deftol)
    601: {
    602:   PetscFunctionBegin;
    604:   PetscAssertPointer(deftol,2);
    605:   PetscUseMethod(nep,"NEPRIIGetDeflationThreshold_C",(NEP,PetscReal*),(nep,deftol));
    606:   PetscFunctionReturn(PETSC_SUCCESS);
    607: }

    609: static PetscErrorCode NEPRIISetKSP_RII(NEP nep,KSP ksp)
    610: {
    611:   NEP_RII        *ctx = (NEP_RII*)nep->data;

    613:   PetscFunctionBegin;
    614:   PetscCall(PetscObjectReference((PetscObject)ksp));
    615:   PetscCall(KSPDestroy(&ctx->ksp));
    616:   ctx->ksp = ksp;
    617:   nep->state = NEP_STATE_INITIAL;
    618:   PetscFunctionReturn(PETSC_SUCCESS);
    619: }

    621: /*@
    622:    NEPRIISetKSP - Associate a linear solver object (`KSP`) to the nonlinear
    623:    eigenvalue solver.

    625:    Collective

    627:    Input Parameters:
    628: +  nep - the nonlinear eigensolver context
    629: -  ksp - the linear solver object

    631:    Level: advanced

    633: .seealso: [](ch:nep), `NEPRII`, `NEPRIIGetKSP()`
    634: @*/
    635: PetscErrorCode NEPRIISetKSP(NEP nep,KSP ksp)
    636: {
    637:   PetscFunctionBegin;
    640:   PetscCheckSameComm(nep,1,ksp,2);
    641:   PetscTryMethod(nep,"NEPRIISetKSP_C",(NEP,KSP),(nep,ksp));
    642:   PetscFunctionReturn(PETSC_SUCCESS);
    643: }

    645: static PetscErrorCode NEPRIIGetKSP_RII(NEP nep,KSP *ksp)
    646: {
    647:   NEP_RII        *ctx = (NEP_RII*)nep->data;

    649:   PetscFunctionBegin;
    650:   if (!ctx->ksp) {
    651:     PetscCall(KSPCreate(PetscObjectComm((PetscObject)nep),&ctx->ksp));
    652:     PetscCall(PetscObjectIncrementTabLevel((PetscObject)ctx->ksp,(PetscObject)nep,1));
    653:     PetscCall(KSPSetOptionsPrefix(ctx->ksp,((PetscObject)nep)->prefix));
    654:     PetscCall(KSPAppendOptionsPrefix(ctx->ksp,"nep_rii_"));
    655:     PetscCall(PetscObjectSetOptions((PetscObject)ctx->ksp,((PetscObject)nep)->options));
    656:     PetscCall(KSPSetErrorIfNotConverged(ctx->ksp,PETSC_TRUE));
    657:     PetscCall(KSPSetTolerances(ctx->ksp,SlepcDefaultTol(nep->tol),PETSC_CURRENT,PETSC_CURRENT,PETSC_CURRENT));
    658:   }
    659:   *ksp = ctx->ksp;
    660:   PetscFunctionReturn(PETSC_SUCCESS);
    661: }

    663: /*@
    664:    NEPRIIGetKSP - Retrieve the linear solver object (`KSP`) associated with
    665:    the nonlinear eigenvalue solver.

    667:    Collective

    669:    Input Parameter:
    670: .  nep - the nonlinear eigensolver context

    672:    Output Parameter:
    673: .  ksp - the linear solver object

    675:    Level: advanced

    677: .seealso: [](ch:nep), `NEPRII`, `NEPRIISetKSP()`
    678: @*/
    679: PetscErrorCode NEPRIIGetKSP(NEP nep,KSP *ksp)
    680: {
    681:   PetscFunctionBegin;
    683:   PetscAssertPointer(ksp,2);
    684:   PetscUseMethod(nep,"NEPRIIGetKSP_C",(NEP,KSP*),(nep,ksp));
    685:   PetscFunctionReturn(PETSC_SUCCESS);
    686: }

    688: static PetscErrorCode NEPView_RII(NEP nep,PetscViewer viewer)
    689: {
    690:   NEP_RII        *ctx = (NEP_RII*)nep->data;
    691:   PetscBool      isascii;

    693:   PetscFunctionBegin;
    694:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    695:   if (isascii) {
    696:     PetscCall(PetscViewerASCIIPrintf(viewer,"  maximum number of inner iterations: %" PetscInt_FMT "\n",ctx->max_inner_it));
    697:     if (ctx->cctol) PetscCall(PetscViewerASCIIPrintf(viewer,"  using a constant tolerance for the linear solver\n"));
    698:     if (ctx->herm) PetscCall(PetscViewerASCIIPrintf(viewer,"  using the Hermitian version of the scalar nonlinear equation\n"));
    699:     if (ctx->lag) PetscCall(PetscViewerASCIIPrintf(viewer,"  updating the preconditioner every %" PetscInt_FMT " iterations\n",ctx->lag));
    700:     if (ctx->deftol) PetscCall(PetscViewerASCIIPrintf(viewer,"  deflation threshold: %g\n",(double)ctx->deftol));
    701:     if (!ctx->ksp) PetscCall(NEPRIIGetKSP(nep,&ctx->ksp));
    702:     PetscCall(PetscViewerASCIIPushTab(viewer));
    703:     PetscCall(KSPView(ctx->ksp,viewer));
    704:     PetscCall(PetscViewerASCIIPopTab(viewer));
    705:   }
    706:   PetscFunctionReturn(PETSC_SUCCESS);
    707: }

    709: static PetscErrorCode NEPReset_RII(NEP nep)
    710: {
    711:   NEP_RII        *ctx = (NEP_RII*)nep->data;

    713:   PetscFunctionBegin;
    714:   PetscCall(KSPReset(ctx->ksp));
    715:   PetscFunctionReturn(PETSC_SUCCESS);
    716: }

    718: static PetscErrorCode NEPDestroy_RII(NEP nep)
    719: {
    720:   NEP_RII        *ctx = (NEP_RII*)nep->data;

    722:   PetscFunctionBegin;
    723:   PetscCall(KSPDestroy(&ctx->ksp));
    724:   PetscCall(PetscFree(nep->data));
    725:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetMaximumIterations_C",NULL));
    726:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetMaximumIterations_C",NULL));
    727:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetLagPreconditioner_C",NULL));
    728:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetLagPreconditioner_C",NULL));
    729:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetConstCorrectionTol_C",NULL));
    730:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetConstCorrectionTol_C",NULL));
    731:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetHermitian_C",NULL));
    732:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetHermitian_C",NULL));
    733:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetDeflationThreshold_C",NULL));
    734:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetDeflationThreshold_C",NULL));
    735:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetKSP_C",NULL));
    736:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetKSP_C",NULL));
    737:   PetscFunctionReturn(PETSC_SUCCESS);
    738: }

    740: /*MC
    741:    NEPRII - NEPRII = "rii" - Simple residual inverse iteration with
    742:    varying shift.

    744:    Notes:
    745:    This is the default solver, although it is very basic. Users are
    746:    advised to try other solvers.

    748:    This solver is based on the modification proposed by {cite:t}`Neu85`
    749:    of the classical residual inverse iteration method. At each step,
    750:    this method has to solve a system of linear equations. Call
    751:    `NEPRIIGetKSP()` to configure the `KSP` object used for this.
    752:    When using iterative linear solvers, the preconditioner will be updated
    753:    in each step or not, depending on `NEPRIISetLagPreconditioner()`, and
    754:    the tolerance will be constant or not depending on
    755:    `NEPRIISetConstCorrectionTol()`.

    757:    The solver incorporates deflation, so that several eigenpairs con be
    758:    computed. Details of the implementation in SLEPc can be found in
    759:    {cite:p}`Cam21`.

    761:    Level: beginner

    763: .seealso: [](ch:nep), `NEP`, `NEPType`, `NEPSetType()`, `NEPRIIGetKSP()`, `NEPRIISetLagPreconditioner()`, `NEPRIISetConstCorrectionTol()`
    764: M*/
    765: SLEPC_EXTERN PetscErrorCode NEPCreate_RII(NEP nep)
    766: {
    767:   NEP_RII        *ctx;

    769:   PetscFunctionBegin;
    770:   PetscCall(PetscNew(&ctx));
    771:   nep->data = (void*)ctx;
    772:   ctx->max_inner_it = 10;
    773:   ctx->lag          = 1;
    774:   ctx->cctol        = PETSC_FALSE;
    775:   ctx->herm         = PETSC_FALSE;
    776:   ctx->deftol       = 0.0;

    778:   nep->useds = PETSC_TRUE;

    780:   nep->ops->solve          = NEPSolve_RII;
    781:   nep->ops->setup          = NEPSetUp_RII;
    782:   nep->ops->setfromoptions = NEPSetFromOptions_RII;
    783:   nep->ops->reset          = NEPReset_RII;
    784:   nep->ops->destroy        = NEPDestroy_RII;
    785:   nep->ops->view           = NEPView_RII;
    786:   nep->ops->computevectors = NEPComputeVectors_Schur;

    788:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetMaximumIterations_C",NEPRIISetMaximumIterations_RII));
    789:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetMaximumIterations_C",NEPRIIGetMaximumIterations_RII));
    790:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetLagPreconditioner_C",NEPRIISetLagPreconditioner_RII));
    791:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetLagPreconditioner_C",NEPRIIGetLagPreconditioner_RII));
    792:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetConstCorrectionTol_C",NEPRIISetConstCorrectionTol_RII));
    793:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetConstCorrectionTol_C",NEPRIIGetConstCorrectionTol_RII));
    794:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetHermitian_C",NEPRIISetHermitian_RII));
    795:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetHermitian_C",NEPRIIGetHermitian_RII));
    796:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetDeflationThreshold_C",NEPRIISetDeflationThreshold_RII));
    797:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetDeflationThreshold_C",NEPRIIGetDeflationThreshold_RII));
    798:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIISetKSP_C",NEPRIISetKSP_RII));
    799:   PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPRIIGetKSP_C",NEPRIIGetKSP_RII));
    800:   PetscFunctionReturn(PETSC_SUCCESS);
    801: }