Date: 2023-09-05T10:17:51+00:00

Actual source code: power.c
slepc-3.19.2 2023-09-05
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

      6:    This file is part of SLEPc.
      7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
      8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9: */
     10: /*
     11:    SLEPc eigensolver: "power"

     13:    Method: Power Iteration

     15:    Algorithm:

     17:        This solver implements the power iteration for finding dominant
     18:        eigenpairs. It also includes the following well-known methods:
     19:        - Inverse Iteration: when used in combination with shift-and-invert
     20:          spectral transformation.
     21:        - Rayleigh Quotient Iteration (RQI): also with shift-and-invert plus
     22:          a variable shift.

     24:        It can also be used for nonlinear inverse iteration on the problem
     25:        A(x)*x=lambda*B(x)*x, where A and B are not constant but depend on x.

     27:    References:

     29:        [1] "Single Vector Iteration Methods in SLEPc", SLEPc Technical Report
     30:            STR-2, available at https://slepc.upv.es.
     31: */

     33: #include <slepc/private/epsimpl.h>
     34: #include <slepcblaslapack.h>
     35: /* petsc headers */
     36: #include <petscdm.h>
     37: #include <petscsnes.h>

     39: static PetscErrorCode EPSPowerFormFunction_Update(SNES,Vec,Vec,void*);
     40: PetscErrorCode EPSSolve_Power(EPS);
     41: PetscErrorCode EPSSolve_TS_Power(EPS);

     43: typedef struct {
     44:   EPSPowerShiftType shift_type;
     45:   PetscBool         nonlinear;
     46:   PetscBool         update;
     47:   SNES              snes;
     48:   PetscErrorCode    (*formFunctionB)(SNES,Vec,Vec,void*);
     49:   void              *formFunctionBctx;
     50:   PetscErrorCode    (*formFunctionA)(SNES,Vec,Vec,void*);
     51:   void              *formFunctionActx;
     52:   PetscErrorCode    (*formFunctionAB)(SNES,Vec,Vec,Vec,void*);
     53:   PetscInt          idx;  /* index of the first nonzero entry in the iteration vector */
     54:   PetscMPIInt       p;    /* process id of the owner of idx */
     55:   PetscReal         norm0; /* norm of initial vector */
     56: } EPS_POWER;

     58: static PetscErrorCode SNESMonitor_PowerUpdate(SNES snes,PetscInt its,PetscReal fnorm,void *ctx)
     59: {
     60:   EPS            eps;

     62:   PetscFunctionBegin;
     63:   PetscCall(PetscObjectQuery((PetscObject)snes,"eps",(PetscObject *)&eps));
     64:   PetscCheck(eps,PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_NULL,"No composed EPS");
     65:   /* Call EPS monitor on each SNES iteration */
     66:   PetscCall(EPSMonitor(eps,its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
     67:   PetscFunctionReturn(PETSC_SUCCESS);
     68: }

     70: PetscErrorCode EPSSetUp_Power(EPS eps)
     71: {
     72:   EPS_POWER      *power = (EPS_POWER*)eps->data;
     73:   STMatMode      mode;
     74:   Mat            A,B,P;
     75:   Vec            res;
     76:   PetscContainer container;
     77:   PetscErrorCode (*formFunctionA)(SNES,Vec,Vec,void*);
     78:   PetscErrorCode (*formJacobianA)(SNES,Vec,Mat,Mat,void*);
     79:   void           *ctx;

     81:   PetscFunctionBegin;
     82:   if (eps->ncv!=PETSC_DEFAULT) {
     83:     PetscCheck(eps->ncv>=eps->nev,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"The value of ncv must be at least nev");
     84:   } else eps->ncv = eps->nev;
     85:   if (eps->mpd!=PETSC_DEFAULT) PetscCall(PetscInfo(eps,"Warning: parameter mpd ignored\n"));
     86:   if (eps->max_it==PETSC_DEFAULT) {
     87:     /* SNES will directly return the solution for us, and we need to do only one iteration */
     88:     if (power->nonlinear && power->update) eps->max_it = 1;
     89:     else eps->max_it = PetscMax(1000*eps->nev,100*eps->n);
     90:   }
     91:   if (!eps->which) PetscCall(EPSSetWhichEigenpairs_Default(eps));
     92:   PetscCheck(eps->which==EPS_LARGEST_MAGNITUDE || eps->which==EPS_TARGET_MAGNITUDE,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver supports only largest magnitude or target magnitude eigenvalues");
     93:   if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) {
     94:     PetscCheck(!power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Variable shifts not allowed in nonlinear problems");
     95:     EPSCheckSinvertCayleyCondition(eps,PETSC_TRUE," (with variable shifts)");
     96:     PetscCall(STGetMatMode(eps->st,&mode));
     97:     PetscCheck(mode!=ST_MATMODE_INPLACE,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"ST matrix mode inplace does not work with variable shifts");
     98:   }
     99:   EPSCheckUnsupported(eps,EPS_FEATURE_BALANCE | EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_CONVERGENCE);
    100:   EPSCheckIgnored(eps,EPS_FEATURE_EXTRACTION);
    101:   PetscCall(EPSAllocateSolution(eps,0));
    102:   PetscCall(EPS_SetInnerProduct(eps));

    104:   if (power->nonlinear) {
    105:     PetscCheck(eps->nev==1,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Nonlinear inverse iteration cannot compute more than one eigenvalue");
    106:     PetscCall(EPSSetWorkVecs(eps,3));
    107:     PetscCheck(!power->update || eps->max_it==1,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"More than one iteration is not allowed for Newton eigensolver (SNES)");

    109:     /* Set up SNES solver */
    110:     /* If SNES was setup, we need to reset it so that it will be consistent with the current EPS */
    111:     if (power->snes) PetscCall(SNESReset(power->snes));
    112:     else PetscCall(EPSPowerGetSNES(eps,&power->snes));

    114:     /* For nonlinear solver (Newton), we should scale the initial vector back.
    115:        The initial vector will be scaled in EPSSetUp. */
    116:     if (eps->IS) PetscCall(VecNorm((eps->IS)[0],NORM_2,&power->norm0));

    118:     PetscCall(EPSGetOperators(eps,&A,&B));

    120:     PetscCall(PetscObjectQueryFunction((PetscObject)A,"formFunction",&formFunctionA));
    121:     PetscCheck(formFunctionA,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER,"For nonlinear inverse iteration you must compose a callback function 'formFunction' in matrix A");
    122:     PetscCall(PetscObjectQuery((PetscObject)A,"formFunctionCtx",(PetscObject*)&container));
    123:     if (container) PetscCall(PetscContainerGetPointer(container,&ctx));
    124:     else ctx = NULL;
    125:     PetscCall(MatCreateVecs(A,&res,NULL));
    126:     power->formFunctionA = formFunctionA;
    127:     power->formFunctionActx = ctx;
    128:     if (power->update) {
    129:       PetscCall(SNESSetFunction(power->snes,res,EPSPowerFormFunction_Update,ctx));
    130:       PetscCall(PetscObjectQueryFunction((PetscObject)A,"formFunctionAB",&power->formFunctionAB));
    131:       PetscCall(SNESMonitorSet(power->snes,SNESMonitor_PowerUpdate,NULL,NULL));
    132:     }
    133:     else PetscCall(SNESSetFunction(power->snes,res,formFunctionA,ctx));
    134:     PetscCall(VecDestroy(&res));

    136:     PetscCall(PetscObjectQueryFunction((PetscObject)A,"formJacobian",&formJacobianA));
    137:     PetscCheck(formJacobianA,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER,"For nonlinear inverse iteration you must compose a callback function 'formJacobian' in matrix A");
    138:     PetscCall(PetscObjectQuery((PetscObject)A,"formJacobianCtx",(PetscObject*)&container));
    139:     if (container) PetscCall(PetscContainerGetPointer(container,&ctx));
    140:     else ctx = NULL;
    141:     /* This allows users to compute a different preconditioning matrix than A.
    142:      * It is useful when A and B are shell matrices.
    143:      */
    144:     PetscCall(STGetPreconditionerMat(eps->st,&P));
    145:     /* If users do not provide a matrix, we simply use A */
    146:     PetscCall(SNESSetJacobian(power->snes,A,P? P:A,formJacobianA,ctx));
    147:     PetscCall(SNESSetFromOptions(power->snes));
    148:     PetscCall(SNESSetUp(power->snes));
    149:     if (B) {
    150:       PetscCall(PetscObjectQueryFunction((PetscObject)B,"formFunction",&power->formFunctionB));
    151:       PetscCall(PetscObjectQuery((PetscObject)B,"formFunctionCtx",(PetscObject*)&container));
    152:       if (power->formFunctionB && container) PetscCall(PetscContainerGetPointer(container,&power->formFunctionBctx));
    153:       else power->formFunctionBctx = NULL;
    154:     }
    155:   } else {
    156:     if (eps->twosided) PetscCall(EPSSetWorkVecs(eps,3));
    157:     else PetscCall(EPSSetWorkVecs(eps,2));
    158:     PetscCall(DSSetType(eps->ds,DSNHEP));
    159:     PetscCall(DSAllocate(eps->ds,eps->nev));
    160:   }
    161:   /* dispatch solve method */
    162:   if (eps->twosided) {
    163:     PetscCheck(!power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Nonlinear inverse iteration does not have two-sided variant");
    164:     PetscCheck(power->shift_type!=EPS_POWER_SHIFT_WILKINSON,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Two-sided variant does not support Wilkinson shifts");
    165:     eps->ops->solve = EPSSolve_TS_Power;
    166:   } else eps->ops->solve = EPSSolve_Power;
    167:   PetscFunctionReturn(PETSC_SUCCESS);
    168: }

    170: /*
    171:    Find the index of the first nonzero entry of x, and the process that owns it.
    172: */
    173: static PetscErrorCode FirstNonzeroIdx(Vec x,PetscInt *idx,PetscMPIInt *p)
    174: {
    175:   PetscInt          i,first,last,N;
    176:   PetscLayout       map;
    177:   const PetscScalar *xx;

    179:   PetscFunctionBegin;
    180:   PetscCall(VecGetSize(x,&N));
    181:   PetscCall(VecGetOwnershipRange(x,&first,&last));
    182:   PetscCall(VecGetArrayRead(x,&xx));
    183:   for (i=first;i<last;i++) {
    184:     if (PetscAbsScalar(xx[i-first])>10*PETSC_MACHINE_EPSILON) break;
    185:   }
    186:   PetscCall(VecRestoreArrayRead(x,&xx));
    187:   if (i==last) i=N;
    188:   PetscCall(MPIU_Allreduce(&i,idx,1,MPIU_INT,MPI_MIN,PetscObjectComm((PetscObject)x)));
    189:   PetscCheck(*idx!=N,PetscObjectComm((PetscObject)x),PETSC_ERR_PLIB,"Zero vector found");
    190:   PetscCall(VecGetLayout(x,&map));
    191:   PetscCall(PetscLayoutFindOwner(map,*idx,p));
    192:   PetscFunctionReturn(PETSC_SUCCESS);
    193: }

    195: /*
    196:    Normalize a vector x with respect to a given norm as well as the
    197:    sign of the first nonzero entry (assumed to be idx in process p).
    198: */
    199: static PetscErrorCode Normalize(Vec x,PetscReal norm,PetscInt idx,PetscMPIInt p,PetscScalar *sign)
    200: {
    201:   PetscScalar       alpha=1.0;
    202:   PetscInt          first,last;
    203:   PetscReal         absv;
    204:   const PetscScalar *xx;

    206:   PetscFunctionBegin;
    207:   PetscCall(VecGetOwnershipRange(x,&first,&last));
    208:   if (idx>=first && idx<last) {
    209:     PetscCall(VecGetArrayRead(x,&xx));
    210:     absv = PetscAbsScalar(xx[idx-first]);
    211:     if (absv>10*PETSC_MACHINE_EPSILON) alpha = xx[idx-first]/absv;
    212:     PetscCall(VecRestoreArrayRead(x,&xx));
    213:   }
    214:   PetscCallMPI(MPI_Bcast(&alpha,1,MPIU_SCALAR,p,PetscObjectComm((PetscObject)x)));
    215:   if (sign) *sign = alpha;
    216:   alpha *= norm;
    217:   PetscCall(VecScale(x,1.0/alpha));
    218:   PetscFunctionReturn(PETSC_SUCCESS);
    219: }

    221: static PetscErrorCode EPSPowerUpdateFunctionB(EPS eps,Vec x,Vec Bx)
    222: {
    223:   EPS_POWER      *power = (EPS_POWER*)eps->data;
    224:   Mat            B;

    226:   PetscFunctionBegin;
    227:   PetscCall(STResetMatrixState(eps->st));
    228:   PetscCall(EPSGetOperators(eps,NULL,&B));
    229:   if (B) {
    230:     if (power->formFunctionB) PetscCall((*power->formFunctionB)(power->snes,x,Bx,power->formFunctionBctx));
    231:     else PetscCall(MatMult(B,x,Bx));
    232:   } else PetscCall(VecCopy(x,Bx));
    233:   PetscFunctionReturn(PETSC_SUCCESS);
    234: }

    236: static PetscErrorCode EPSPowerUpdateFunctionA(EPS eps,Vec x,Vec Ax)
    237: {
    238:   EPS_POWER      *power = (EPS_POWER*)eps->data;
    239:   Mat            A;

    241:   PetscFunctionBegin;
    242:   PetscCall(STResetMatrixState(eps->st));
    243:   PetscCall(EPSGetOperators(eps,&A,NULL));
    244:   PetscCheck(A,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_NULL,"Matrix A is required for an eigenvalue problem");
    245:   if (power->formFunctionA) PetscCall((*power->formFunctionA)(power->snes,x,Ax,power->formFunctionActx));
    246:   else PetscCall(MatMult(A,x,Ax));
    247:   PetscFunctionReturn(PETSC_SUCCESS);
    248: }

    250: static PetscErrorCode EPSPowerFormFunction_Update(SNES snes,Vec x,Vec y,void *ctx)
    251: {
    252:   EPS            eps;
    253:   PetscReal      bx;
    254:   Vec            Bx;
    255:   PetscScalar    sign;
    256:   EPS_POWER      *power;

    258:   PetscFunctionBegin;
    259:   PetscCall(PetscObjectQuery((PetscObject)snes,"eps",(PetscObject *)&eps));
    260:   PetscCheck(eps,PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_NULL,"No composed EPS");
    261:   PetscCall(STResetMatrixState(eps->st));
    262:   power = (EPS_POWER*)eps->data;
    263:   Bx = eps->work[2];
    264:   if (power->formFunctionAB) PetscCall((*power->formFunctionAB)(snes,x,y,Bx,ctx));
    265:   else {
    266:     PetscCall(EPSPowerUpdateFunctionA(eps,x,y));
    267:     PetscCall(EPSPowerUpdateFunctionB(eps,x,Bx));
    268:   }
    269:   PetscCall(VecNorm(Bx,NORM_2,&bx));
    270:   PetscCall(Normalize(Bx,bx,power->idx,power->p,&sign));
    271:   PetscCall(VecAXPY(y,-1.0,Bx));
    272:   /* Keep tracking eigenvalue update. It would be useful when we want to monitor solver progress via snes monitor. */
    273:   eps->eigr[(eps->nconv < eps->nev)? eps->nconv:(eps->nconv-1)] = 1.0/(bx*sign);
    274:   PetscFunctionReturn(PETSC_SUCCESS);
    275: }

    277: /*
    278:    Use SNES to compute y = A^{-1}*B*x for the nonlinear problem
    279: */
    280: static PetscErrorCode EPSPowerApply_SNES(EPS eps,Vec x,Vec y)
    281: {
    282:   EPS_POWER      *power = (EPS_POWER*)eps->data;
    283:   Vec            Bx;

    285:   PetscFunctionBegin;
    286:   PetscCall(VecCopy(x,y));
    287:   if (power->update) PetscCall(SNESSolve(power->snes,NULL,y));
    288:   else {
    289:     Bx = eps->work[2];
    290:     PetscCall(SNESSolve(power->snes,Bx,y));
    291:   }
    292:   PetscFunctionReturn(PETSC_SUCCESS);
    293: }

    295: /*
    296:    Use nonlinear inverse power to compute an initial guess
    297: */
    298: static PetscErrorCode EPSPowerComputeInitialGuess_Update(EPS eps)
    299: {
    300:   EPS            powereps;
    301:   Mat            A,B,P;
    302:   Vec            v1,v2;
    303:   SNES           snes;
    304:   DM             dm,newdm;

    306:   PetscFunctionBegin;
    307:   PetscCall(EPSCreate(PetscObjectComm((PetscObject)eps),&powereps));
    308:   PetscCall(EPSGetOperators(eps,&A,&B));
    309:   PetscCall(EPSSetType(powereps,EPSPOWER));
    310:   PetscCall(EPSSetOperators(powereps,A,B));
    311:   PetscCall(EPSSetTolerances(powereps,1e-6,4));
    312:   PetscCall(EPSSetOptionsPrefix(powereps,((PetscObject)eps)->prefix));
    313:   PetscCall(EPSAppendOptionsPrefix(powereps,"init_"));
    314:   PetscCall(EPSSetProblemType(powereps,EPS_GNHEP));
    315:   PetscCall(EPSSetWhichEigenpairs(powereps,EPS_TARGET_MAGNITUDE));
    316:   PetscCall(EPSPowerSetNonlinear(powereps,PETSC_TRUE));
    317:   PetscCall(STGetPreconditionerMat(eps->st,&P));
    318:   /* attach dm to initial solve */
    319:   PetscCall(EPSPowerGetSNES(eps,&snes));
    320:   PetscCall(SNESGetDM(snes,&dm));
    321:   /* use  dmshell to temporarily store snes context */
    322:   PetscCall(DMCreate(PetscObjectComm((PetscObject)eps),&newdm));
    323:   PetscCall(DMSetType(newdm,DMSHELL));
    324:   PetscCall(DMSetUp(newdm));
    325:   PetscCall(DMCopyDMSNES(dm,newdm));
    326:   PetscCall(EPSPowerGetSNES(powereps,&snes));
    327:   PetscCall(SNESSetDM(snes,dm));
    328:   PetscCall(EPSSetFromOptions(powereps));
    329:   if (P) PetscCall(STSetPreconditionerMat(powereps->st,P));
    330:   PetscCall(EPSSolve(powereps));
    331:   PetscCall(BVGetColumn(eps->V,0,&v2));
    332:   PetscCall(BVGetColumn(powereps->V,0,&v1));
    333:   PetscCall(VecCopy(v1,v2));
    334:   PetscCall(BVRestoreColumn(powereps->V,0,&v1));
    335:   PetscCall(BVRestoreColumn(eps->V,0,&v2));
    336:   PetscCall(EPSDestroy(&powereps));
    337:   /* restore context back to the old nonlinear solver */
    338:   PetscCall(DMCopyDMSNES(newdm,dm));
    339:   PetscCall(DMDestroy(&newdm));
    340:   PetscFunctionReturn(PETSC_SUCCESS);
    341: }

    343: PetscErrorCode EPSSolve_Power(EPS eps)
    344: {
    345:   EPS_POWER           *power = (EPS_POWER*)eps->data;
    346:   PetscInt            k,ld;
    347:   Vec                 v,y,e,Bx;
    348:   Mat                 A;
    349:   KSP                 ksp;
    350:   PetscReal           relerr,norm,norm1,rt1,rt2,cs1;
    351:   PetscScalar         theta,rho,delta,sigma,alpha2,beta1,sn1,*T,sign;
    352:   PetscBool           breakdown;
    353:   KSPConvergedReason  reason;
    354:   SNESConvergedReason snesreason;

    356:   PetscFunctionBegin;
    357:   e = eps->work[0];
    358:   y = eps->work[1];
    359:   if (power->nonlinear) Bx = eps->work[2];
    360:   else Bx = NULL;

    362:   if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) PetscCall(STGetKSP(eps->st,&ksp));
    363:   if (power->nonlinear) {
    364:     PetscCall(PetscObjectCompose((PetscObject)power->snes,"eps",(PetscObject)eps));
    365:     /* Compute an initial guess only when users do not provide one */
    366:     if (power->update && !eps->nini) PetscCall(EPSPowerComputeInitialGuess_Update(eps));
    367:   } else PetscCall(DSGetLeadingDimension(eps->ds,&ld));
    368:   if (!power->update) PetscCall(EPSGetStartVector(eps,0,NULL));
    369:   if (power->nonlinear) {
    370:     PetscCall(BVGetColumn(eps->V,0,&v));
    371:     if (eps->nini) {
    372:       /* We scale the initial vector back if the initial vector was provided by users */
    373:       PetscCall(VecScale(v,power->norm0));
    374:     }
    375:     PetscCall(EPSPowerUpdateFunctionB(eps,v,Bx));
    376:     PetscCall(VecNorm(Bx,NORM_2,&norm));
    377:     PetscCall(FirstNonzeroIdx(Bx,&power->idx,&power->p));
    378:     PetscCall(Normalize(Bx,norm,power->idx,power->p,NULL));
    379:     PetscCall(BVRestoreColumn(eps->V,0,&v));
    380:   }

    382:   PetscCall(STGetShift(eps->st,&sigma));    /* original shift */
    383:   rho = sigma;

    385:   while (eps->reason == EPS_CONVERGED_ITERATING) {
    386:     eps->its++;
    387:     k = eps->nconv;

    389:     /* y = OP v */
    390:     PetscCall(BVGetColumn(eps->V,k,&v));
    391:     if (power->nonlinear) PetscCall(EPSPowerApply_SNES(eps,v,y));
    392:     else PetscCall(STApply(eps->st,v,y));
    393:     PetscCall(BVRestoreColumn(eps->V,k,&v));

    395:     /* purge previously converged eigenvectors */
    396:     if (PetscUnlikely(power->nonlinear)) {
    397:       /* We do not need to call this for Newton eigensolver since eigenvalue is
    398:        * updated in function evaluations.
    399:        */
    400:       if (!power->update) {
    401:         PetscCall(EPSPowerUpdateFunctionB(eps,y,Bx));
    402:         PetscCall(VecNorm(Bx,NORM_2,&norm));
    403:         PetscCall(Normalize(Bx,norm,power->idx,power->p,&sign));
    404:       }
    405:     } else {
    406:       PetscCall(DSGetArray(eps->ds,DS_MAT_A,&T));
    407:       PetscCall(BVSetActiveColumns(eps->V,0,k));
    408:       PetscCall(BVOrthogonalizeVec(eps->V,y,T+k*ld,&norm,NULL));
    409:     }

    411:     /* theta = (v,y)_B */
    412:     PetscCall(BVSetActiveColumns(eps->V,k,k+1));
    413:     PetscCall(BVDotVec(eps->V,y,&theta));
    414:     if (!power->nonlinear) {
    415:       T[k+k*ld] = theta;
    416:       PetscCall(DSRestoreArray(eps->ds,DS_MAT_A,&T));
    417:     }

    419:     /* Eigenvalue is already stored in function evaluations.
    420:      * Assign eigenvalue to theta to make the rest of the code consistent
    421:      */
    422:     if (power->update) theta = eps->eigr[eps->nconv];
    423:     else if (power->nonlinear) theta = 1.0/norm*sign; /* Eigenvalue: 1/|Bx| */

    425:     if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */

    427:       /* approximate eigenvalue is the Rayleigh quotient */
    428:       eps->eigr[eps->nconv] = theta;

    430:       /**
    431:        * If the Newton method (update, SNES) is used, we do not compute "relerr"
    432:        * since SNES determines the convergence.
    433:        */
    434:       if (PetscUnlikely(power->update)) relerr = 0.;
    435:       else {
    436:         /* compute relative error as ||y-theta v||_2/|theta| */
    437:         PetscCall(VecCopy(y,e));
    438:         PetscCall(BVGetColumn(eps->V,k,&v));
    439:         PetscCall(VecAXPY(e,power->nonlinear?-1.0:-theta,v));
    440:         PetscCall(BVRestoreColumn(eps->V,k,&v));
    441:         PetscCall(VecNorm(e,NORM_2,&relerr));
    442:         if (PetscUnlikely(power->nonlinear)) relerr *= PetscAbsScalar(theta);
    443:         else relerr /= PetscAbsScalar(theta);
    444:       }

    446:     } else {  /* RQI */

    448:       /* delta = ||y||_B */
    449:       delta = norm;

    451:       /* compute relative error */
    452:       if (rho == 0.0) relerr = PETSC_MAX_REAL;
    453:       else relerr = 1.0 / (norm*PetscAbsScalar(rho));

    455:       /* approximate eigenvalue is the shift */
    456:       eps->eigr[eps->nconv] = rho;

    458:       /* compute new shift */
    459:       if (relerr<eps->tol) {
    460:         rho = sigma;  /* if converged, restore original shift */
    461:         PetscCall(STSetShift(eps->st,rho));
    462:       } else {
    463:         rho = rho + PetscConj(theta)/(delta*delta);  /* Rayleigh quotient R(v) */
    464:         if (power->shift_type == EPS_POWER_SHIFT_WILKINSON) {
    465:           /* beta1 is the norm of the residual associated with R(v) */
    466:           PetscCall(BVGetColumn(eps->V,k,&v));
    467:           PetscCall(VecAXPY(v,-PetscConj(theta)/(delta*delta),y));
    468:           PetscCall(BVRestoreColumn(eps->V,k,&v));
    469:           PetscCall(BVScaleColumn(eps->V,k,1.0/delta));
    470:           PetscCall(BVNormColumn(eps->V,k,NORM_2,&norm1));
    471:           beta1 = norm1;

    473:           /* alpha2 = (e'*A*e)/(beta1*beta1), where e is the residual */
    474:           PetscCall(STGetMatrix(eps->st,0,&A));
    475:           PetscCall(BVGetColumn(eps->V,k,&v));
    476:           PetscCall(MatMult(A,v,e));
    477:           PetscCall(VecDot(v,e,&alpha2));
    478:           PetscCall(BVRestoreColumn(eps->V,k,&v));
    479:           alpha2 = alpha2 / (beta1 * beta1);

    481:           /* choose the eigenvalue of [rho beta1; beta1 alpha2] closest to rho */
    482:           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
    483:           PetscCallBLAS("LAPACKlaev2",LAPACKlaev2_(&rho,&beta1,&alpha2,&rt1,&rt2,&cs1,&sn1));
    484:           PetscCall(PetscFPTrapPop());
    485:           if (PetscAbsScalar(rt1-rho) < PetscAbsScalar(rt2-rho)) rho = rt1;
    486:           else rho = rt2;
    487:         }
    488:         /* update operator according to new shift */
    489:         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_FALSE));
    490:         PetscCall(STSetShift(eps->st,rho));
    491:         PetscCall(KSPGetConvergedReason(ksp,&reason));
    492:         if (reason) {
    493:           PetscCall(PetscInfo(eps,"Factorization failed, repeat with a perturbed shift\n"));
    494:           rho *= 1+10*PETSC_MACHINE_EPSILON;
    495:           PetscCall(STSetShift(eps->st,rho));
    496:           PetscCall(KSPGetConvergedReason(ksp,&reason));
    497:           PetscCheck(!reason,PetscObjectComm((PetscObject)ksp),PETSC_ERR_CONV_FAILED,"Second factorization failed");
    498:         }
    499:         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_TRUE));
    500:       }
    501:     }
    502:     eps->errest[eps->nconv] = relerr;

    504:     /* normalize */
    505:     if (!power->nonlinear) PetscCall(Normalize(y,norm,power->idx,power->p,NULL));
    506:     PetscCall(BVInsertVec(eps->V,k,y));

    508:     if (PetscUnlikely(power->update)) {
    509:       PetscCall(SNESGetConvergedReason(power->snes,&snesreason));
    510:       /* For Newton eigensolver, we are ready to return once SNES converged. */
    511:       if (snesreason>0) eps->nconv = 1;
    512:     } else if (PetscUnlikely(relerr<eps->tol)) {   /* accept eigenpair */
    513:       eps->nconv = eps->nconv + 1;
    514:       if (eps->nconv<eps->nev) {
    515:         PetscCall(EPSGetStartVector(eps,eps->nconv,&breakdown));
    516:         if (breakdown) {
    517:           eps->reason = EPS_DIVERGED_BREAKDOWN;
    518:           PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
    519:           break;
    520:         }
    521:       }
    522:     }
    523:     /* For Newton eigensolver, monitor will be called from SNES monitor */
    524:     if (!power->update) PetscCall(EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
    525:     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx));

    527:     /**
    528:      * When a customized stopping test is used, and reason can be set to be converged (EPS_CONVERGED_USER).
    529:      * In this case, we need to increase eps->nconv to "1" so users can retrieve the solution.
    530:      */
    531:     if (PetscUnlikely(power->nonlinear && eps->reason>0)) eps->nconv = 1;
    532:   }

    534:   if (power->nonlinear) PetscCall(PetscObjectCompose((PetscObject)power->snes,"eps",NULL));
    535:   else {
    536:     PetscCall(DSSetDimensions(eps->ds,eps->nconv,0,0));
    537:     PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
    538:   }
    539:   PetscFunctionReturn(PETSC_SUCCESS);
    540: }

    542: PetscErrorCode EPSSolve_TS_Power(EPS eps)
    543: {
    544:   EPS_POWER          *power = (EPS_POWER*)eps->data;
    545:   PetscInt           k,ld;
    546:   Vec                v,w,y,e,z;
    547:   KSP                ksp;
    548:   PetscReal          relerr=1.0,relerrl,delta;
    549:   PetscScalar        theta,rho,alpha,sigma;
    550:   PetscBool          breakdown,breakdownl;
    551:   KSPConvergedReason reason;

    553:   PetscFunctionBegin;
    554:   e = eps->work[0];
    555:   v = eps->work[1];
    556:   w = eps->work[2];

    558:   if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) PetscCall(STGetKSP(eps->st,&ksp));
    559:   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
    560:   PetscCall(EPSGetStartVector(eps,0,NULL));
    561:   PetscCall(EPSGetLeftStartVector(eps,0,NULL));
    562:   PetscCall(BVBiorthonormalizeColumn(eps->V,eps->W,0,NULL));
    563:   PetscCall(BVCopyVec(eps->V,0,v));
    564:   PetscCall(BVCopyVec(eps->W,0,w));
    565:   PetscCall(STGetShift(eps->st,&sigma));    /* original shift */
    566:   rho = sigma;

    568:   while (eps->reason == EPS_CONVERGED_ITERATING) {
    569:     eps->its++;
    570:     k = eps->nconv;

    572:     /* y = OP v, z = OP' w */
    573:     PetscCall(BVGetColumn(eps->V,k,&y));
    574:     PetscCall(STApply(eps->st,v,y));
    575:     PetscCall(BVRestoreColumn(eps->V,k,&y));
    576:     PetscCall(BVGetColumn(eps->W,k,&z));
    577:     PetscCall(STApplyHermitianTranspose(eps->st,w,z));
    578:     PetscCall(BVRestoreColumn(eps->W,k,&z));

    580:     /* purge previously converged eigenvectors */
    581:     PetscCall(BVBiorthogonalizeColumn(eps->V,eps->W,k));

    583:     /* theta = (w,y)_B */
    584:     PetscCall(BVSetActiveColumns(eps->V,k,k+1));
    585:     PetscCall(BVDotVec(eps->V,w,&theta));
    586:     theta = PetscConj(theta);

    588:     if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */

    590:       /* approximate eigenvalue is the Rayleigh quotient */
    591:       eps->eigr[eps->nconv] = theta;

    593:       /* compute relative errors as ||y-theta v||_2/|theta| and ||z-conj(theta) w||_2/|theta|*/
    594:       PetscCall(BVCopyVec(eps->V,k,e));
    595:       PetscCall(VecAXPY(e,-theta,v));
    596:       PetscCall(VecNorm(e,NORM_2,&relerr));
    597:       PetscCall(BVCopyVec(eps->W,k,e));
    598:       PetscCall(VecAXPY(e,-PetscConj(theta),w));
    599:       PetscCall(VecNorm(e,NORM_2,&relerrl));
    600:       relerr = PetscMax(relerr,relerrl)/PetscAbsScalar(theta);
    601:     }

    603:     /* normalize */
    604:     PetscCall(BVSetActiveColumns(eps->V,k,k+1));
    605:     PetscCall(BVGetColumn(eps->W,k,&z));
    606:     PetscCall(BVDotVec(eps->V,z,&alpha));
    607:     PetscCall(BVRestoreColumn(eps->W,k,&z));
    608:     delta = PetscSqrtReal(PetscAbsScalar(alpha));
    609:     PetscCheck(delta!=0.0,PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Breakdown in two-sided Power/RQI");
    610:     PetscCall(BVScaleColumn(eps->V,k,1.0/PetscConj(alpha/delta)));
    611:     PetscCall(BVScaleColumn(eps->W,k,1.0/delta));
    612:     PetscCall(BVCopyVec(eps->V,k,v));
    613:     PetscCall(BVCopyVec(eps->W,k,w));

    615:     if (power->shift_type == EPS_POWER_SHIFT_RAYLEIGH) { /* RQI */

    617:       /* compute relative error */
    618:       if (rho == 0.0) relerr = PETSC_MAX_REAL;
    619:       else relerr = 1.0 / PetscAbsScalar(delta*rho);

    621:       /* approximate eigenvalue is the shift */
    622:       eps->eigr[eps->nconv] = rho;

    624:       /* compute new shift */
    625:       if (relerr<eps->tol) {
    626:         rho = sigma;  /* if converged, restore original shift */
    627:         PetscCall(STSetShift(eps->st,rho));
    628:       } else {
    629:         rho = rho + PetscConj(theta)/(delta*delta);  /* Rayleigh quotient R(v) */
    630:         /* update operator according to new shift */
    631:         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_FALSE));
    632:         PetscCall(STSetShift(eps->st,rho));
    633:         PetscCall(KSPGetConvergedReason(ksp,&reason));
    634:         if (reason) {
    635:           PetscCall(PetscInfo(eps,"Factorization failed, repeat with a perturbed shift\n"));
    636:           rho *= 1+10*PETSC_MACHINE_EPSILON;
    637:           PetscCall(STSetShift(eps->st,rho));
    638:           PetscCall(KSPGetConvergedReason(ksp,&reason));
    639:           PetscCheck(!reason,PetscObjectComm((PetscObject)ksp),PETSC_ERR_CONV_FAILED,"Second factorization failed");
    640:         }
    641:         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_TRUE));
    642:       }
    643:     }
    644:     eps->errest[eps->nconv] = relerr;

    646:     /* if relerr<tol, accept eigenpair */
    647:     if (relerr<eps->tol) {
    648:       eps->nconv = eps->nconv + 1;
    649:       if (eps->nconv<eps->nev) {
    650:         PetscCall(EPSGetStartVector(eps,eps->nconv,&breakdown));
    651:         PetscCall(EPSGetLeftStartVector(eps,eps->nconv,&breakdownl));
    652:         if (breakdown || breakdownl) {
    653:           eps->reason = EPS_DIVERGED_BREAKDOWN;
    654:           PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
    655:           break;
    656:         }
    657:         PetscCall(BVBiorthonormalizeColumn(eps->V,eps->W,eps->nconv,NULL));
    658:       }
    659:     }
    660:     PetscCall(EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
    661:     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx));
    662:   }

    664:   PetscCall(DSSetDimensions(eps->ds,eps->nconv,0,0));
    665:   PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
    666:   PetscFunctionReturn(PETSC_SUCCESS);
    667: }

    669: PetscErrorCode EPSStopping_Power(EPS eps,PetscInt its,PetscInt max_it,PetscInt nconv,PetscInt nev,EPSConvergedReason *reason,void *ctx)
    670: {
    671:   EPS_POWER      *power = (EPS_POWER*)eps->data;
    672:   SNESConvergedReason snesreason;

    674:   PetscFunctionBegin;
    675:   if (PetscUnlikely(power->update)) {
    676:     PetscCall(SNESGetConvergedReason(power->snes,&snesreason));
    677:     if (snesreason < 0) {
    678:       *reason = EPS_DIVERGED_BREAKDOWN;
    679:       PetscFunctionReturn(PETSC_SUCCESS);
    680:     }
    681:   }
    682:   PetscCall(EPSStoppingBasic(eps,its,max_it,nconv,nev,reason,ctx));
    683:   PetscFunctionReturn(PETSC_SUCCESS);
    684: }

    686: PetscErrorCode EPSBackTransform_Power(EPS eps)
    687: {
    688:   EPS_POWER      *power = (EPS_POWER*)eps->data;

    690:   PetscFunctionBegin;
    691:   if (power->nonlinear) eps->eigr[0] = 1.0/eps->eigr[0];
    692:   else if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) PetscCall(EPSBackTransform_Default(eps));
    693:   PetscFunctionReturn(PETSC_SUCCESS);
    694: }

    696: PetscErrorCode EPSSetFromOptions_Power(EPS eps,PetscOptionItems *PetscOptionsObject)
    697: {
    698:   EPS_POWER         *power = (EPS_POWER*)eps->data;
    699:   PetscBool         flg,val;
    700:   EPSPowerShiftType shift;

    702:   PetscFunctionBegin;
    703:   PetscOptionsHeadBegin(PetscOptionsObject,"EPS Power Options");

    705:     PetscCall(PetscOptionsEnum("-eps_power_shift_type","Shift type","EPSPowerSetShiftType",EPSPowerShiftTypes,(PetscEnum)power->shift_type,(PetscEnum*)&shift,&flg));
    706:     if (flg) PetscCall(EPSPowerSetShiftType(eps,shift));

    708:     PetscCall(PetscOptionsBool("-eps_power_nonlinear","Use nonlinear inverse iteration","EPSPowerSetNonlinear",power->nonlinear,&val,&flg));
    709:     if (flg) PetscCall(EPSPowerSetNonlinear(eps,val));

    711:     PetscCall(PetscOptionsBool("-eps_power_update","Update residual monolithically","EPSPowerSetUpdate",power->update,&val,&flg));
    712:     if (flg) PetscCall(EPSPowerSetUpdate(eps,val));

    714:   PetscOptionsHeadEnd();
    715:   PetscFunctionReturn(PETSC_SUCCESS);
    716: }

    718: static PetscErrorCode EPSPowerSetShiftType_Power(EPS eps,EPSPowerShiftType shift)
    719: {
    720:   EPS_POWER *power = (EPS_POWER*)eps->data;

    722:   PetscFunctionBegin;
    723:   switch (shift) {
    724:     case EPS_POWER_SHIFT_CONSTANT:
    725:     case EPS_POWER_SHIFT_RAYLEIGH:
    726:     case EPS_POWER_SHIFT_WILKINSON:
    727:       if (power->shift_type != shift) {
    728:         power->shift_type = shift;
    729:         eps->state = EPS_STATE_INITIAL;
    730:       }
    731:       break;
    732:     default:
    733:       SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid shift type");
    734:   }
    735:   PetscFunctionReturn(PETSC_SUCCESS);
    736: }

    738: /*@
    739:    EPSPowerSetShiftType - Sets the type of shifts used during the power
    740:    iteration. This can be used to emulate the Rayleigh Quotient Iteration
    741:    (RQI) method.

    743:    Logically Collective

    745:    Input Parameters:
    746: +  eps - the eigenproblem solver context
    747: -  shift - the type of shift

    749:    Options Database Key:
    750: .  -eps_power_shift_type - Sets the shift type (either 'constant' or
    751:                            'rayleigh' or 'wilkinson')

    753:    Notes:
    754:    By default, shifts are constant (EPS_POWER_SHIFT_CONSTANT) and the iteration
    755:    is the simple power method (or inverse iteration if a shift-and-invert
    756:    transformation is being used).

    758:    A variable shift can be specified (EPS_POWER_SHIFT_RAYLEIGH or
    759:    EPS_POWER_SHIFT_WILKINSON). In this case, the iteration behaves rather like
    760:    a cubic converging method such as RQI.

    762:    Level: advanced

    764: .seealso: EPSPowerGetShiftType(), STSetShift(), EPSPowerShiftType
    765: @*/
    766: PetscErrorCode EPSPowerSetShiftType(EPS eps,EPSPowerShiftType shift)
    767: {
    768:   PetscFunctionBegin;
    771:   PetscTryMethod(eps,"EPSPowerSetShiftType_C",(EPS,EPSPowerShiftType),(eps,shift));
    772:   PetscFunctionReturn(PETSC_SUCCESS);
    773: }

    775: static PetscErrorCode EPSPowerGetShiftType_Power(EPS eps,EPSPowerShiftType *shift)
    776: {
    777:   EPS_POWER *power = (EPS_POWER*)eps->data;

    779:   PetscFunctionBegin;
    780:   *shift = power->shift_type;
    781:   PetscFunctionReturn(PETSC_SUCCESS);
    782: }

    784: /*@
    785:    EPSPowerGetShiftType - Gets the type of shifts used during the power
    786:    iteration.

    788:    Not Collective

    790:    Input Parameter:
    791: .  eps - the eigenproblem solver context

    793:    Output Parameter:
    794: .  shift - the type of shift

    796:    Level: advanced

    798: .seealso: EPSPowerSetShiftType(), EPSPowerShiftType
    799: @*/
    800: PetscErrorCode EPSPowerGetShiftType(EPS eps,EPSPowerShiftType *shift)
    801: {
    802:   PetscFunctionBegin;
    805:   PetscUseMethod(eps,"EPSPowerGetShiftType_C",(EPS,EPSPowerShiftType*),(eps,shift));
    806:   PetscFunctionReturn(PETSC_SUCCESS);
    807: }

    809: static PetscErrorCode EPSPowerSetNonlinear_Power(EPS eps,PetscBool nonlinear)
    810: {
    811:   EPS_POWER *power = (EPS_POWER*)eps->data;

    813:   PetscFunctionBegin;
    814:   if (power->nonlinear != nonlinear) {
    815:     power->nonlinear = nonlinear;
    816:     eps->useds = PetscNot(nonlinear);
    817:     eps->ops->setupsort = nonlinear? NULL: EPSSetUpSort_Default;
    818:     eps->state = EPS_STATE_INITIAL;
    819:   }
    820:   PetscFunctionReturn(PETSC_SUCCESS);
    821: }

    823: /*@
    824:    EPSPowerSetNonlinear - Sets a flag to indicate that the problem is nonlinear.

    826:    Logically Collective

    828:    Input Parameters:
    829: +  eps - the eigenproblem solver context
    830: -  nonlinear - whether the problem is nonlinear or not

    832:    Options Database Key:
    833: .  -eps_power_nonlinear - Sets the nonlinear flag

    835:    Notes:
    836:    If this flag is set, the solver assumes that the problem is nonlinear,
    837:    that is, the operators that define the eigenproblem are not constant
    838:    matrices, but depend on the eigenvector, A(x)*x=lambda*B(x)*x. This is
    839:    different from the case of nonlinearity with respect to the eigenvalue
    840:    (use the NEP solver class for this kind of problems).

    842:    The way in which nonlinear operators are specified is very similar to
    843:    the case of PETSc's SNES solver. The difference is that the callback
    844:    functions are provided via composed functions "formFunction" and
    845:    "formJacobian" in each of the matrix objects passed as arguments of
    846:    EPSSetOperators(). The application context required for these functions
    847:    can be attached via a composed PetscContainer.

    849:    Level: advanced

    851: .seealso: EPSPowerGetNonlinear(), EPSSetOperators()
    852: @*/
    853: PetscErrorCode EPSPowerSetNonlinear(EPS eps,PetscBool nonlinear)
    854: {
    855:   PetscFunctionBegin;
    858:   PetscTryMethod(eps,"EPSPowerSetNonlinear_C",(EPS,PetscBool),(eps,nonlinear));
    859:   PetscFunctionReturn(PETSC_SUCCESS);
    860: }

    862: static PetscErrorCode EPSPowerGetNonlinear_Power(EPS eps,PetscBool *nonlinear)
    863: {
    864:   EPS_POWER *power = (EPS_POWER*)eps->data;

    866:   PetscFunctionBegin;
    867:   *nonlinear = power->nonlinear;
    868:   PetscFunctionReturn(PETSC_SUCCESS);
    869: }

    871: /*@
    872:    EPSPowerGetNonlinear - Returns a flag indicating if the problem is nonlinear.

    874:    Not Collective

    876:    Input Parameter:
    877: .  eps - the eigenproblem solver context

    879:    Output Parameter:
    880: .  nonlinear - the nonlinear flag

    882:    Level: advanced

    884: .seealso: EPSPowerSetUpdate(), EPSPowerSetNonlinear()
    885: @*/
    886: PetscErrorCode EPSPowerGetNonlinear(EPS eps,PetscBool *nonlinear)
    887: {
    888:   PetscFunctionBegin;
    891:   PetscUseMethod(eps,"EPSPowerGetNonlinear_C",(EPS,PetscBool*),(eps,nonlinear));
    892:   PetscFunctionReturn(PETSC_SUCCESS);
    893: }

    895: static PetscErrorCode EPSPowerSetUpdate_Power(EPS eps,PetscBool update)
    896: {
    897:   EPS_POWER *power = (EPS_POWER*)eps->data;

    899:   PetscFunctionBegin;
    900:   PetscCheck(power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_INCOMP,"This option does not make sense for linear problems");
    901:   power->update = update;
    902:   eps->state = EPS_STATE_INITIAL;
    903:   PetscFunctionReturn(PETSC_SUCCESS);
    904: }

    906: /*@
    907:    EPSPowerSetUpdate - Sets a flag to indicate that the residual is updated monolithically
    908:    for nonlinear problems. This potentially has a better convergence.

    910:    Logically Collective

    912:    Input Parameters:
    913: +  eps - the eigenproblem solver context
    914: -  update - whether the residual is updated monolithically or not

    916:    Options Database Key:
    917: .  -eps_power_update - Sets the update flag

    919:    Level: advanced

    921: .seealso: EPSPowerGetUpdate(), EPSPowerGetNonlinear(), EPSSetOperators()
    922: @*/
    923: PetscErrorCode EPSPowerSetUpdate(EPS eps,PetscBool update)
    924: {
    925:   PetscFunctionBegin;
    928:   PetscTryMethod(eps,"EPSPowerSetUpdate_C",(EPS,PetscBool),(eps,update));
    929:   PetscFunctionReturn(PETSC_SUCCESS);
    930: }

    932: static PetscErrorCode EPSPowerGetUpdate_Power(EPS eps,PetscBool *update)
    933: {
    934:   EPS_POWER *power = (EPS_POWER*)eps->data;

    936:   PetscFunctionBegin;
    937:   *update = power->update;
    938:   PetscFunctionReturn(PETSC_SUCCESS);
    939: }

    941: /*@
    942:    EPSPowerGetUpdate - Returns a flag indicating if the residual is updated monolithically
    943:    for nonlinear problems.

    945:    Not Collective

    947:    Input Parameter:
    948: .  eps - the eigenproblem solver context

    950:    Output Parameter:
    951: .  update - the update flag

    953:    Level: advanced

    955: .seealso: EPSPowerSetUpdate(), EPSPowerSetNonlinear()
    956: @*/
    957: PetscErrorCode EPSPowerGetUpdate(EPS eps,PetscBool *update)
    958: {
    959:   PetscFunctionBegin;
    962:   PetscUseMethod(eps,"EPSPowerGetUpdate_C",(EPS,PetscBool*),(eps,update));
    963:   PetscFunctionReturn(PETSC_SUCCESS);
    964: }

    966: static PetscErrorCode EPSPowerSetSNES_Power(EPS eps,SNES snes)
    967: {
    968:   EPS_POWER      *power = (EPS_POWER*)eps->data;

    970:   PetscFunctionBegin;
    971:   PetscCall(PetscObjectReference((PetscObject)snes));
    972:   PetscCall(SNESDestroy(&power->snes));
    973:   power->snes = snes;
    974:   eps->state = EPS_STATE_INITIAL;
    975:   PetscFunctionReturn(PETSC_SUCCESS);
    976: }

    978: /*@
    979:    EPSPowerSetSNES - Associate a nonlinear solver object (SNES) to the
    980:    eigenvalue solver (to be used in nonlinear inverse iteration).

    982:    Collective

    984:    Input Parameters:
    985: +  eps  - the eigenvalue solver
    986: -  snes - the nonlinear solver object

    988:    Level: advanced

    990: .seealso: EPSPowerGetSNES()
    991: @*/
    992: PetscErrorCode EPSPowerSetSNES(EPS eps,SNES snes)
    993: {
    994:   PetscFunctionBegin;
    997:   PetscCheckSameComm(eps,1,snes,2);
    998:   PetscTryMethod(eps,"EPSPowerSetSNES_C",(EPS,SNES),(eps,snes));
    999:   PetscFunctionReturn(PETSC_SUCCESS);
    1000: }

    1002: static PetscErrorCode EPSPowerGetSNES_Power(EPS eps,SNES *snes)
    1003: {
    1004:   EPS_POWER      *power = (EPS_POWER*)eps->data;

    1006:   PetscFunctionBegin;
    1007:   if (!power->snes) {
    1008:     PetscCall(SNESCreate(PetscObjectComm((PetscObject)eps),&power->snes));
    1009:     PetscCall(PetscObjectIncrementTabLevel((PetscObject)power->snes,(PetscObject)eps,1));
    1010:     PetscCall(SNESSetOptionsPrefix(power->snes,((PetscObject)eps)->prefix));
    1011:     PetscCall(SNESAppendOptionsPrefix(power->snes,"eps_power_"));
    1012:     PetscCall(PetscObjectSetOptions((PetscObject)power->snes,((PetscObject)eps)->options));
    1013:   }
    1014:   *snes = power->snes;
    1015:   PetscFunctionReturn(PETSC_SUCCESS);
    1016: }

    1018: /*@
    1019:    EPSPowerGetSNES - Retrieve the nonlinear solver object (SNES) associated
    1020:    with the eigenvalue solver.

    1022:    Not Collective

    1024:    Input Parameter:
    1025: .  eps - the eigenvalue solver

    1027:    Output Parameter:
    1028: .  snes - the nonlinear solver object

    1030:    Level: advanced

    1032: .seealso: EPSPowerSetSNES()
    1033: @*/
    1034: PetscErrorCode EPSPowerGetSNES(EPS eps,SNES *snes)
    1035: {
    1036:   PetscFunctionBegin;
    1039:   PetscUseMethod(eps,"EPSPowerGetSNES_C",(EPS,SNES*),(eps,snes));
    1040:   PetscFunctionReturn(PETSC_SUCCESS);
    1041: }

    1043: PetscErrorCode EPSReset_Power(EPS eps)
    1044: {
    1045:   EPS_POWER      *power = (EPS_POWER*)eps->data;

    1047:   PetscFunctionBegin;
    1048:   if (power->snes) PetscCall(SNESReset(power->snes));
    1049:   PetscFunctionReturn(PETSC_SUCCESS);
    1050: }

    1052: PetscErrorCode EPSDestroy_Power(EPS eps)
    1053: {
    1054:   EPS_POWER      *power = (EPS_POWER*)eps->data;

    1056:   PetscFunctionBegin;
    1057:   if (power->nonlinear) PetscCall(SNESDestroy(&power->snes));
    1058:   PetscCall(PetscFree(eps->data));
    1059:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",NULL));
    1060:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",NULL));
    1061:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetNonlinear_C",NULL));
    1062:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetNonlinear_C",NULL));
    1063:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetUpdate_C",NULL));
    1064:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetUpdate_C",NULL));
    1065:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSNES_C",NULL));
    1066:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSNES_C",NULL));
    1067:   PetscFunctionReturn(PETSC_SUCCESS);
    1068: }

    1070: PetscErrorCode EPSView_Power(EPS eps,PetscViewer viewer)
    1071: {
    1072:   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1073:   PetscBool      isascii;

    1075:   PetscFunctionBegin;
    1076:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    1077:   if (isascii) {
    1078:     if (power->nonlinear) {
    1079:       PetscCall(PetscViewerASCIIPrintf(viewer,"  using nonlinear inverse iteration\n"));
    1080:       if (power->update) PetscCall(PetscViewerASCIIPrintf(viewer,"  updating the residual monolithically\n"));
    1081:       if (!power->snes) PetscCall(EPSPowerGetSNES(eps,&power->snes));
    1082:       PetscCall(PetscViewerASCIIPushTab(viewer));
    1083:       PetscCall(SNESView(power->snes,viewer));
    1084:       PetscCall(PetscViewerASCIIPopTab(viewer));
    1085:     } else PetscCall(PetscViewerASCIIPrintf(viewer,"  %s shifts\n",EPSPowerShiftTypes[power->shift_type]));
    1086:   }
    1087:   PetscFunctionReturn(PETSC_SUCCESS);
    1088: }

    1090: PetscErrorCode EPSComputeVectors_Power(EPS eps)
    1091: {
    1092:   EPS_POWER      *power = (EPS_POWER*)eps->data;

    1094:   PetscFunctionBegin;
    1095:   if (eps->twosided) {
    1096:     PetscCall(EPSComputeVectors_Twosided(eps));
    1097:     PetscCall(BVNormalize(eps->V,NULL));
    1098:     PetscCall(BVNormalize(eps->W,NULL));
    1099:   } else if (!power->nonlinear) PetscCall(EPSComputeVectors_Schur(eps));
    1100:   PetscFunctionReturn(PETSC_SUCCESS);
    1101: }

    1103: PetscErrorCode EPSSetDefaultST_Power(EPS eps)
    1104: {
    1105:   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1106:   KSP            ksp;
    1107:   PC             pc;

    1109:   PetscFunctionBegin;
    1110:   if (power->nonlinear) {
    1111:     eps->categ=EPS_CATEGORY_PRECOND;
    1112:     PetscCall(STGetKSP(eps->st,&ksp));
    1113:     /* Set ST as STPRECOND so it can carry one preconditioning matrix
    1114:      * It is useful when A and B are shell matrices
    1115:      */
    1116:     PetscCall(STSetType(eps->st,STPRECOND));
    1117:     PetscCall(KSPGetPC(ksp,&pc));
    1118:     PetscCall(PCSetType(pc,PCNONE));
    1119:   }
    1120:   PetscFunctionReturn(PETSC_SUCCESS);
    1121: }

    1123: SLEPC_EXTERN PetscErrorCode EPSCreate_Power(EPS eps)
    1124: {
    1125:   EPS_POWER      *ctx;

    1127:   PetscFunctionBegin;
    1128:   PetscCall(PetscNew(&ctx));
    1129:   eps->data = (void*)ctx;

    1131:   eps->useds = PETSC_TRUE;
    1132:   eps->categ = EPS_CATEGORY_OTHER;

    1134:   eps->ops->setup          = EPSSetUp_Power;
    1135:   eps->ops->setupsort      = EPSSetUpSort_Default;
    1136:   eps->ops->setfromoptions = EPSSetFromOptions_Power;
    1137:   eps->ops->reset          = EPSReset_Power;
    1138:   eps->ops->destroy        = EPSDestroy_Power;
    1139:   eps->ops->view           = EPSView_Power;
    1140:   eps->ops->backtransform  = EPSBackTransform_Power;
    1141:   eps->ops->computevectors = EPSComputeVectors_Power;
    1142:   eps->ops->setdefaultst   = EPSSetDefaultST_Power;
    1143:   eps->stopping            = EPSStopping_Power;

    1145:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",EPSPowerSetShiftType_Power));
    1146:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",EPSPowerGetShiftType_Power));
    1147:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetNonlinear_C",EPSPowerSetNonlinear_Power));
    1148:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetNonlinear_C",EPSPowerGetNonlinear_Power));
    1149:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetUpdate_C",EPSPowerSetUpdate_Power));
    1150:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetUpdate_C",EPSPowerGetUpdate_Power));
    1151:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSNES_C",EPSPowerSetSNES_Power));
    1152:   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSNES_C",EPSPowerGetSNES_Power));
    1153:   PetscFunctionReturn(PETSC_SUCCESS);
    1154: }