LCOV - code coverage report
Current view: top level - eps/impls/power - power.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 622 679 91.6 %
Date: 2024-04-19 00:31:36 Functions: 37 40 92.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3             :    SLEPc - Scalable Library for Eigenvalue Problem Computations
       4             :    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
       5             : 
       6             :    This file is part of SLEPc.
       7             :    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
       8             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       9             : */
      10             : /*
      11             :    SLEPc eigensolver: "power"
      12             : 
      13             :    Method: Power Iteration
      14             : 
      15             :    Algorithm:
      16             : 
      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.
      23             : 
      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.
      26             : 
      27             :    References:
      28             : 
      29             :        [1] "Single Vector Iteration Methods in SLEPc", SLEPc Technical Report
      30             :            STR-2, available at https://slepc.upv.es.
      31             : */
      32             : 
      33             : #include <slepc/private/epsimpl.h>                /*I "slepceps.h" I*/
      34             : #include <slepcblaslapack.h>
      35             : /* petsc headers */
      36             : #include <petscdm.h>
      37             : #include <petscsnes.h>
      38             : 
      39             : static PetscErrorCode EPSPowerFormFunction_Update(SNES,Vec,Vec,void*);
      40             : static PetscErrorCode EPSSolve_Power(EPS);
      41             : static PetscErrorCode EPSSolve_TS_Power(EPS);
      42             : 
      43             : typedef struct {
      44             :   EPSPowerShiftType shift_type;
      45             :   PetscBool         nonlinear;
      46             :   PetscBool         update;
      47             :   PetscBool         sign_normalization;
      48             :   SNES              snes;
      49             :   PetscErrorCode    (*formFunctionB)(SNES,Vec,Vec,void*);
      50             :   void              *formFunctionBctx;
      51             :   PetscErrorCode    (*formFunctionA)(SNES,Vec,Vec,void*);
      52             :   void              *formFunctionActx;
      53             :   PetscErrorCode    (*formFunctionAB)(SNES,Vec,Vec,Vec,void*);
      54             :   PetscErrorCode    (*formNorm)(SNES,Vec,PetscReal*,void*);
      55             :   void              *formNormCtx;
      56             :   PetscInt          idx;  /* index of the first nonzero entry in the iteration vector */
      57             :   PetscMPIInt       p;    /* process id of the owner of idx */
      58             :   PetscReal         norm0; /* norm of initial vector */
      59             : } EPS_POWER;
      60             : 
      61         104 : static PetscErrorCode SNESMonitor_PowerUpdate(SNES snes,PetscInt its,PetscReal fnorm,void *ctx)
      62             : {
      63         104 :   EPS            eps;
      64             : 
      65         104 :   PetscFunctionBegin;
      66         104 :   PetscCall(PetscObjectQuery((PetscObject)snes,"eps",(PetscObject *)&eps));
      67         104 :   PetscCheck(eps,PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_NULL,"No composed EPS");
      68             :   /* Call EPS monitor on each SNES iteration */
      69         104 :   PetscCall(EPSMonitor(eps,its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
      70         104 :   PetscFunctionReturn(PETSC_SUCCESS);
      71             : }
      72             : 
      73          48 : static PetscErrorCode EPSSetUp_Power(EPS eps)
      74             : {
      75          48 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
      76          48 :   STMatMode      mode;
      77          48 :   Mat            A,B,P;
      78          48 :   Vec            res;
      79          48 :   PetscContainer container;
      80          48 :   PetscErrorCode (*formFunctionA)(SNES,Vec,Vec,void*);
      81          48 :   PetscErrorCode (*formJacobianA)(SNES,Vec,Mat,Mat,void*);
      82          48 :   PetscErrorCode (*formNorm)(SNES,Vec,PetscReal*,void*);
      83          48 :   void           *ctx;
      84             : 
      85          48 :   PetscFunctionBegin;
      86          48 :   if (eps->ncv!=PETSC_DEFAULT) {
      87           5 :     PetscCheck(eps->ncv>=eps->nev,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"The value of ncv must be at least nev");
      88          43 :   } else eps->ncv = eps->nev;
      89          48 :   if (eps->mpd!=PETSC_DEFAULT) PetscCall(PetscInfo(eps,"Warning: parameter mpd ignored\n"));
      90          48 :   if (eps->max_it==PETSC_DEFAULT) {
      91             :     /* SNES will directly return the solution for us, and we need to do only one iteration */
      92          28 :     if (power->nonlinear && power->update) eps->max_it = 1;
      93          16 :     else eps->max_it = PetscMax(1000*eps->nev,100*eps->n);
      94             :   }
      95          48 :   if (!eps->which) PetscCall(EPSSetWhichEigenpairs_Default(eps));
      96          48 :   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");
      97          48 :   if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) {
      98           4 :     PetscCheck(!power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Variable shifts not allowed in nonlinear problems");
      99           4 :     EPSCheckSinvertCayleyCondition(eps,PETSC_TRUE," (with variable shifts)");
     100           4 :     PetscCall(STGetMatMode(eps->st,&mode));
     101           4 :     PetscCheck(mode!=ST_MATMODE_INPLACE,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"ST matrix mode inplace does not work with variable shifts");
     102             :   }
     103          48 :   EPSCheckUnsupported(eps,EPS_FEATURE_BALANCE | EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_CONVERGENCE);
     104          48 :   EPSCheckIgnored(eps,EPS_FEATURE_EXTRACTION);
     105          48 :   PetscCall(EPSAllocateSolution(eps,0));
     106          48 :   PetscCall(EPS_SetInnerProduct(eps));
     107             : 
     108          48 :   if (power->nonlinear) {
     109          31 :     PetscCheck(eps->nev==1,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Nonlinear inverse iteration cannot compute more than one eigenvalue");
     110          31 :     PetscCall(EPSSetWorkVecs(eps,3));
     111          31 :     PetscCheck(!power->update || eps->max_it==1,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"More than one iteration is not allowed for Newton eigensolver (SNES)");
     112             : 
     113             :     /* Set up SNES solver */
     114             :     /* If SNES was setup, we need to reset it so that it will be consistent with the current EPS */
     115          31 :     if (power->snes) PetscCall(SNESReset(power->snes));
     116           0 :     else PetscCall(EPSPowerGetSNES(eps,&power->snes));
     117             : 
     118             :     /* For nonlinear solver (Newton), we should scale the initial vector back.
     119             :        The initial vector will be scaled in EPSSetUp. */
     120          31 :     if (eps->IS) PetscCall(VecNorm(eps->IS[0],NORM_2,&power->norm0));
     121             : 
     122          31 :     PetscCall(EPSGetOperators(eps,&A,&B));
     123             : 
     124             :     /* form function */
     125          31 :     PetscCall(PetscObjectQueryFunction((PetscObject)A,"formFunction",&formFunctionA));
     126          31 :     PetscCheck(formFunctionA,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER,"For nonlinear inverse iteration you must compose a callback function 'formFunction' in matrix A");
     127          31 :     PetscCall(PetscObjectQuery((PetscObject)A,"formFunctionCtx",(PetscObject*)&container));
     128          31 :     if (container) PetscCall(PetscContainerGetPointer(container,&ctx));
     129           0 :     else ctx = NULL;
     130          31 :     PetscCall(MatCreateVecs(A,&res,NULL));
     131          31 :     power->formFunctionA = formFunctionA;
     132          31 :     power->formFunctionActx = ctx;
     133          31 :     if (power->update) {
     134          14 :       PetscCall(SNESSetFunction(power->snes,res,EPSPowerFormFunction_Update,ctx));
     135          14 :       PetscCall(PetscObjectQueryFunction((PetscObject)A,"formFunctionAB",&power->formFunctionAB));
     136          14 :       PetscCall(SNESMonitorSet(power->snes,SNESMonitor_PowerUpdate,NULL,NULL));
     137             :     }
     138          17 :     else PetscCall(SNESSetFunction(power->snes,res,formFunctionA,ctx));
     139          31 :     PetscCall(VecDestroy(&res));
     140             : 
     141             :     /* form Jacobian */
     142          31 :     PetscCall(PetscObjectQueryFunction((PetscObject)A,"formJacobian",&formJacobianA));
     143          31 :     PetscCheck(formJacobianA,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER,"For nonlinear inverse iteration you must compose a callback function 'formJacobian' in matrix A");
     144          31 :     PetscCall(PetscObjectQuery((PetscObject)A,"formJacobianCtx",(PetscObject*)&container));
     145          31 :     if (container) PetscCall(PetscContainerGetPointer(container,&ctx));
     146           0 :     else ctx = NULL;
     147             :     /* This allows users to compute a different preconditioning matrix than A.
     148             :      * It is useful when A and B are shell matrices.
     149             :      */
     150          31 :     PetscCall(STGetPreconditionerMat(eps->st,&P));
     151             :     /* If users do not provide a matrix, we simply use A */
     152          31 :     PetscCall(SNESSetJacobian(power->snes,A,P? P:A,formJacobianA,ctx));
     153          31 :     PetscCall(SNESSetFromOptions(power->snes));
     154          31 :     PetscCall(SNESSetUp(power->snes));
     155             : 
     156          31 :     ctx = NULL;
     157          31 :     formNorm = NULL;
     158          31 :     if (B) {
     159          31 :       PetscCall(PetscObjectQueryFunction((PetscObject)B,"formFunction",&power->formFunctionB));
     160          31 :       PetscCall(PetscObjectQuery((PetscObject)B,"formFunctionCtx",(PetscObject*)&container));
     161          31 :       if (power->formFunctionB && container) PetscCall(PetscContainerGetPointer(container,&power->formFunctionBctx));
     162           0 :       else power->formFunctionBctx = NULL;
     163             : 
     164             :       /* form norm */
     165          31 :       PetscCall(PetscObjectQueryFunction((PetscObject)B,"formNorm",&formNorm));
     166          31 :       if (formNorm) {
     167           8 :         PetscCall(PetscObjectQuery((PetscObject)B,"formNormCtx",(PetscObject*)&container));
     168           8 :         if (container) PetscCall(PetscContainerGetPointer(container,&ctx));
     169             :       }
     170             :     }
     171          31 :     power->formNorm = formNorm;
     172          31 :     power->formNormCtx = ctx;
     173             :   } else {
     174          17 :     if (eps->twosided) PetscCall(EPSSetWorkVecs(eps,3));
     175          14 :     else PetscCall(EPSSetWorkVecs(eps,2));
     176          17 :     PetscCall(DSSetType(eps->ds,DSNHEP));
     177          17 :     PetscCall(DSAllocate(eps->ds,eps->nev));
     178             :   }
     179             :   /* dispatch solve method */
     180          48 :   if (eps->twosided) {
     181           3 :     PetscCheck(!power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Nonlinear inverse iteration does not have two-sided variant");
     182           3 :     PetscCheck(power->shift_type!=EPS_POWER_SHIFT_WILKINSON,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Two-sided variant does not support Wilkinson shifts");
     183           3 :     eps->ops->solve = EPSSolve_TS_Power;
     184          45 :   } else eps->ops->solve = EPSSolve_Power;
     185          48 :   PetscFunctionReturn(PETSC_SUCCESS);
     186             : }
     187             : 
     188             : /*
     189             :    Find the index of the first nonzero entry of x, and the process that owns it.
     190             : */
     191          31 : static PetscErrorCode FirstNonzeroIdx(Vec x,PetscInt *idx,PetscMPIInt *p)
     192             : {
     193          31 :   PetscInt          i,first,last,N;
     194          31 :   PetscLayout       map;
     195          31 :   const PetscScalar *xx;
     196             : 
     197          31 :   PetscFunctionBegin;
     198          31 :   PetscCall(VecGetSize(x,&N));
     199          31 :   PetscCall(VecGetOwnershipRange(x,&first,&last));
     200          31 :   PetscCall(VecGetArrayRead(x,&xx));
     201         341 :   for (i=first;i<last;i++) {
     202         341 :     if (PetscAbsScalar(xx[i-first])>10*PETSC_MACHINE_EPSILON) break;
     203             :   }
     204          31 :   PetscCall(VecRestoreArrayRead(x,&xx));
     205          31 :   if (i==last) i=N;
     206         124 :   PetscCall(MPIU_Allreduce(&i,idx,1,MPIU_INT,MPI_MIN,PetscObjectComm((PetscObject)x)));
     207          31 :   PetscCheck(*idx!=N,PetscObjectComm((PetscObject)x),PETSC_ERR_PLIB,"Zero vector found");
     208          31 :   PetscCall(VecGetLayout(x,&map));
     209          31 :   PetscCall(PetscLayoutFindOwner(map,*idx,p));
     210          31 :   PetscFunctionReturn(PETSC_SUCCESS);
     211             : }
     212             : 
     213             : /*
     214             :    Normalize a vector x with respect to a given norm as well as, optionally, the
     215             :    sign of the first nonzero entry (assumed to be idx in process p).
     216             : */
     217       29308 : static PetscErrorCode Normalize(Vec x,PetscReal norm,PetscInt idx,PetscMPIInt p,PetscBool sign_normalization,PetscScalar *sign)
     218             : {
     219       29308 :   PetscScalar       alpha=1.0;
     220       29308 :   PetscInt          first,last;
     221       29308 :   PetscReal         absv;
     222       29308 :   const PetscScalar *xx;
     223             : 
     224       29308 :   PetscFunctionBegin;
     225       29308 :   if (sign_normalization) {
     226       29022 :     PetscCall(VecGetOwnershipRange(x,&first,&last));
     227       29022 :     if (idx>=first && idx<last) {
     228       29022 :       PetscCall(VecGetArrayRead(x,&xx));
     229       29022 :       absv = PetscAbsScalar(xx[idx-first]);
     230       29022 :       if (absv>10*PETSC_MACHINE_EPSILON) alpha = xx[idx-first]/absv;
     231       29022 :       PetscCall(VecRestoreArrayRead(x,&xx));
     232             :     }
     233       58044 :     PetscCallMPI(MPI_Bcast(&alpha,1,MPIU_SCALAR,p,PetscObjectComm((PetscObject)x)));
     234             :   }
     235       29308 :   if (sign) *sign = alpha;
     236       29308 :   alpha *= norm;
     237       29308 :   PetscCall(VecScale(x,1.0/alpha));
     238       29308 :   PetscFunctionReturn(PETSC_SUCCESS);
     239             : }
     240             : 
     241         661 : static PetscErrorCode EPSPowerUpdateFunctionB(EPS eps,Vec x,Vec Bx)
     242             : {
     243         661 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     244         661 :   Mat            B;
     245             : 
     246         661 :   PetscFunctionBegin;
     247         661 :   PetscCall(STResetMatrixState(eps->st));
     248         661 :   PetscCall(EPSGetOperators(eps,NULL,&B));
     249         661 :   if (B) {
     250         661 :     if (power->formFunctionB) PetscCall((*power->formFunctionB)(power->snes,x,Bx,power->formFunctionBctx));
     251           0 :     else PetscCall(MatMult(B,x,Bx));
     252           0 :   } else PetscCall(VecCopy(x,Bx));
     253         661 :   PetscFunctionReturn(PETSC_SUCCESS);
     254             : }
     255             : 
     256         445 : static PetscErrorCode EPSPowerUpdateFunctionA(EPS eps,Vec x,Vec Ax)
     257             : {
     258         445 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     259         445 :   Mat            A;
     260             : 
     261         445 :   PetscFunctionBegin;
     262         445 :   PetscCall(STResetMatrixState(eps->st));
     263         445 :   PetscCall(EPSGetOperators(eps,&A,NULL));
     264         445 :   PetscCheck(A,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_NULL,"Matrix A is required for an eigenvalue problem");
     265         445 :   if (power->formFunctionA) PetscCall((*power->formFunctionA)(power->snes,x,Ax,power->formFunctionActx));
     266           0 :   else PetscCall(MatMult(A,x,Ax));
     267         445 :   PetscFunctionReturn(PETSC_SUCCESS);
     268             : }
     269             : 
     270         682 : static PetscErrorCode EPSPowerFormFunction_Update(SNES snes,Vec x,Vec y,void *ctx)
     271             : {
     272         682 :   EPS            eps;
     273         682 :   PetscReal      bx;
     274         682 :   Vec            Bx;
     275         682 :   PetscScalar    sign;
     276         682 :   EPS_POWER      *power;
     277             : 
     278         682 :   PetscFunctionBegin;
     279         682 :   PetscCall(PetscObjectQuery((PetscObject)snes,"eps",(PetscObject *)&eps));
     280         682 :   PetscCheck(eps,PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_NULL,"No composed EPS");
     281         682 :   PetscCall(STResetMatrixState(eps->st));
     282         682 :   power = (EPS_POWER*)eps->data;
     283         682 :   Bx = eps->work[2];
     284         682 :   if (power->formFunctionAB) PetscCall((*power->formFunctionAB)(snes,x,y,Bx,ctx));
     285             :   else {
     286         445 :     PetscCall(EPSPowerUpdateFunctionA(eps,x,y));
     287         445 :     PetscCall(EPSPowerUpdateFunctionB(eps,x,Bx));
     288             :   }
     289         682 :   if (power->formNorm) PetscCall((*power->formNorm)(snes,Bx,&bx,power->formNormCtx));
     290         472 :   else PetscCall(VecNorm(Bx,NORM_2,&bx));
     291         682 :   PetscCall(Normalize(Bx,bx,power->idx,power->p,power->sign_normalization,&sign));
     292         682 :   PetscCall(VecAXPY(y,-1.0,Bx));
     293             :   /* Keep tracking eigenvalue update. It would be useful when we want to monitor solver progress via snes monitor. */
     294         682 :   eps->eigr[(eps->nconv < eps->nev)? eps->nconv:(eps->nconv-1)] = 1.0/(bx*sign);
     295         682 :   PetscFunctionReturn(PETSC_SUCCESS);
     296             : }
     297             : 
     298             : /*
     299             :    Use SNES to compute y = A^{-1}*B*x for the nonlinear problem
     300             : */
     301         199 : static PetscErrorCode EPSPowerApply_SNES(EPS eps,Vec x,Vec y)
     302             : {
     303         199 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     304         199 :   Vec            Bx;
     305             : 
     306         199 :   PetscFunctionBegin;
     307         199 :   PetscCall(VecCopy(x,y));
     308         199 :   if (power->update) PetscCall(SNESSolve(power->snes,NULL,y));
     309             :   else {
     310         185 :     Bx = eps->work[2];
     311         185 :     PetscCall(SNESSolve(power->snes,Bx,y));
     312             :   }
     313         199 :   PetscFunctionReturn(PETSC_SUCCESS);
     314             : }
     315             : 
     316             : /*
     317             :    Use nonlinear inverse power to compute an initial guess
     318             : */
     319          12 : static PetscErrorCode EPSPowerComputeInitialGuess_Update(EPS eps)
     320             : {
     321          12 :   EPS            powereps;
     322          12 :   Mat            A,B,P;
     323          12 :   Vec            v1,v2;
     324          12 :   SNES           snes;
     325          12 :   DM             dm,newdm;
     326          12 :   PetscBool      sign_normalization;
     327             : 
     328          12 :   PetscFunctionBegin;
     329          12 :   PetscCall(EPSCreate(PetscObjectComm((PetscObject)eps),&powereps));
     330          12 :   PetscCall(EPSGetOperators(eps,&A,&B));
     331          12 :   PetscCall(EPSSetType(powereps,EPSPOWER));
     332          12 :   PetscCall(EPSSetOperators(powereps,A,B));
     333          12 :   PetscCall(EPSSetTolerances(powereps,1e-6,4));
     334          12 :   PetscCall(EPSSetOptionsPrefix(powereps,((PetscObject)eps)->prefix));
     335          12 :   PetscCall(EPSAppendOptionsPrefix(powereps,"init_"));
     336          12 :   PetscCall(EPSSetProblemType(powereps,EPS_GNHEP));
     337          12 :   PetscCall(EPSSetWhichEigenpairs(powereps,EPS_TARGET_MAGNITUDE));
     338          12 :   PetscCall(EPSPowerSetNonlinear(powereps,PETSC_TRUE));
     339          12 :   PetscCall(STGetPreconditionerMat(eps->st,&P));
     340             :   /* attach dm to initial solve */
     341          12 :   PetscCall(EPSPowerGetSNES(eps,&snes));
     342          12 :   PetscCall(SNESGetDM(snes,&dm));
     343             :   /* use  dmshell to temporarily store snes context */
     344          12 :   PetscCall(DMCreate(PetscObjectComm((PetscObject)eps),&newdm));
     345          12 :   PetscCall(DMSetType(newdm,DMSHELL));
     346          12 :   PetscCall(DMSetUp(newdm));
     347          12 :   PetscCall(DMCopyDMSNES(dm,newdm));
     348          12 :   PetscCall(EPSPowerGetSNES(powereps,&snes));
     349          12 :   PetscCall(SNESSetDM(snes,dm));
     350          12 :   PetscCall(EPSPowerGetSignNormalization(eps,&sign_normalization));
     351          12 :   PetscCall(EPSPowerSetSignNormalization(powereps,sign_normalization));
     352          12 :   PetscCall(EPSSetFromOptions(powereps));
     353          12 :   if (P) PetscCall(STSetPreconditionerMat(powereps->st,P));
     354          12 :   PetscCall(EPSSolve(powereps));
     355          12 :   PetscCall(BVGetColumn(eps->V,0,&v2));
     356          12 :   PetscCall(BVGetColumn(powereps->V,0,&v1));
     357          12 :   PetscCall(VecCopy(v1,v2));
     358          12 :   PetscCall(BVRestoreColumn(powereps->V,0,&v1));
     359          12 :   PetscCall(BVRestoreColumn(eps->V,0,&v2));
     360          12 :   PetscCall(EPSDestroy(&powereps));
     361             :   /* restore context back to the old nonlinear solver */
     362          12 :   PetscCall(DMCopyDMSNES(newdm,dm));
     363          12 :   PetscCall(DMDestroy(&newdm));
     364          12 :   PetscFunctionReturn(PETSC_SUCCESS);
     365             : }
     366             : 
     367          45 : static PetscErrorCode EPSSolve_Power(EPS eps)
     368             : {
     369          45 :   EPS_POWER           *power = (EPS_POWER*)eps->data;
     370          45 :   PetscInt            k,ld;
     371          45 :   Vec                 v,y,e,Bx;
     372          45 :   Mat                 A;
     373          45 :   KSP                 ksp;
     374          45 :   PetscReal           relerr,norm,norm1,rt1,rt2,cs1;
     375          45 :   PetscScalar         theta,rho,delta,sigma,alpha2,beta1,sn1,*T,sign;
     376          45 :   PetscBool           breakdown;
     377          45 :   KSPConvergedReason  reason;
     378          45 :   SNESConvergedReason snesreason;
     379             : 
     380          45 :   PetscFunctionBegin;
     381          45 :   e = eps->work[0];
     382          45 :   y = eps->work[1];
     383          45 :   if (power->nonlinear) Bx = eps->work[2];
     384             :   else Bx = NULL;
     385             : 
     386          45 :   if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) PetscCall(STGetKSP(eps->st,&ksp));
     387          45 :   if (power->nonlinear) {
     388          31 :     PetscCall(PetscObjectCompose((PetscObject)power->snes,"eps",(PetscObject)eps));
     389             :     /* Compute an initial guess only when users do not provide one */
     390          31 :     if (power->update && !eps->nini) PetscCall(EPSPowerComputeInitialGuess_Update(eps));
     391          14 :   } else PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     392          45 :   if (!power->update) PetscCall(EPSGetStartVector(eps,0,NULL));
     393          45 :   if (power->nonlinear) {
     394          31 :     PetscCall(BVGetColumn(eps->V,0,&v));
     395          31 :     if (eps->nini) {
     396             :       /* We scale the initial vector back if the initial vector was provided by users */
     397           2 :       PetscCall(VecScale(v,power->norm0));
     398             :     }
     399             :     /* Do a couple things:
     400             :      * 1) Determine the first non-zero index for Bx and the proc that owns it. This will be
     401             :      *    used if performing normalization by the sign of the first nonzero element of Bx.
     402             :      * 2) Scale Bx by its norm. For non-update power iterations, Bx (in code terms) is used
     403             :      *    as the RHS argument to SNESSolve. And recall that the formula for generalized
     404             :      *    inverse power iterations in this case is: (Ax)_n = (Bx)_{n-1}/|(Bx)_{n-1}| (in
     405             :      *    math terms)
     406             :      */
     407          31 :     PetscCall(EPSPowerUpdateFunctionB(eps,v,Bx));
     408          31 :     PetscCall(BVRestoreColumn(eps->V,0,&v));
     409          31 :     if (power->formNorm) PetscCall((*power->formNorm)(power->snes,Bx,&norm,power->formNormCtx));
     410          23 :     else PetscCall(VecNorm(Bx,NORM_2,&norm));
     411          31 :     PetscCall(FirstNonzeroIdx(Bx,&power->idx,&power->p));
     412          31 :     PetscCall(Normalize(Bx,norm,power->idx,power->p,power->sign_normalization,NULL));
     413             :   }
     414             : 
     415          45 :   PetscCall(STGetShift(eps->st,&sigma));    /* original shift */
     416          45 :   rho = sigma;
     417             : 
     418       28654 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     419       28609 :     eps->its++;
     420       28609 :     k = eps->nconv;
     421             : 
     422             :     /* y = OP v */
     423       28609 :     PetscCall(BVGetColumn(eps->V,k,&v));
     424       28609 :     if (power->nonlinear) PetscCall(EPSPowerApply_SNES(eps,v,y));
     425       28410 :     else PetscCall(STApply(eps->st,v,y));
     426       28609 :     PetscCall(BVRestoreColumn(eps->V,k,&v));
     427             : 
     428             :     /* purge previously converged eigenvectors */
     429       28609 :     if (PetscUnlikely(power->nonlinear)) {
     430             :       /* We do not need to call this for Newton eigensolver since eigenvalue is
     431             :        * updated in function evaluations.
     432             :        */
     433         199 :       if (!power->update) {
     434         185 :         PetscCall(EPSPowerUpdateFunctionB(eps,y,Bx));
     435         185 :         if (power->formNorm) PetscCall((*power->formNorm)(power->snes,Bx,&norm,power->formNormCtx));
     436         115 :         else PetscCall(VecNorm(Bx,NORM_2,&norm));
     437         185 :         PetscCall(Normalize(Bx,norm,power->idx,power->p,power->sign_normalization,&sign));
     438             :       }
     439             :     } else {
     440       28410 :       PetscCall(DSGetArray(eps->ds,DS_MAT_A,&T));
     441       28410 :       PetscCall(BVSetActiveColumns(eps->V,0,k));
     442       28410 :       PetscCall(BVOrthogonalizeVec(eps->V,y,T+k*ld,&norm,NULL));
     443             :     }
     444             : 
     445             :     /* theta = (v,y)_B */
     446       28609 :     PetscCall(BVSetActiveColumns(eps->V,k,k+1));
     447       28609 :     PetscCall(BVDotVec(eps->V,y,&theta));
     448       28609 :     if (!power->nonlinear) {
     449       28410 :       T[k+k*ld] = theta;
     450       28410 :       PetscCall(DSRestoreArray(eps->ds,DS_MAT_A,&T));
     451             :     }
     452             : 
     453             :     /* Eigenvalue is already stored in function evaluations.
     454             :      * Assign eigenvalue to theta to make the rest of the code consistent
     455             :      */
     456       28609 :     if (power->update) theta = eps->eigr[eps->nconv];
     457       28595 :     else if (power->nonlinear) theta = 1.0/(norm*sign); /* Eigenvalue: 1/|Bx| */
     458             : 
     459       28609 :     if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */
     460             : 
     461             :       /* approximate eigenvalue is the Rayleigh quotient */
     462       28575 :       eps->eigr[eps->nconv] = theta;
     463             : 
     464             :       /**
     465             :        * If the Newton method (update, SNES) is used, we do not compute "relerr"
     466             :        * since SNES determines the convergence.
     467             :        */
     468       28575 :       if (PetscUnlikely(power->update)) relerr = 0.;
     469             :       else {
     470             :         /* compute relative error as ||y-theta v||_2/|theta| */
     471       28561 :         PetscCall(VecCopy(y,e));
     472       28561 :         PetscCall(BVGetColumn(eps->V,k,&v));
     473       28561 :         PetscCall(VecAXPY(e,power->nonlinear?-1.0:-theta,v));
     474       28561 :         PetscCall(BVRestoreColumn(eps->V,k,&v));
     475       28561 :         PetscCall(VecNorm(e,NORM_2,&relerr));
     476       28561 :         if (PetscUnlikely(power->nonlinear)) relerr *= PetscAbsScalar(theta);
     477       28376 :         else relerr /= PetscAbsScalar(theta);
     478             :       }
     479             : 
     480             :     } else {  /* RQI */
     481             : 
     482             :       /* delta = ||y||_B */
     483          34 :       delta = norm;
     484             : 
     485             :       /* compute relative error */
     486          34 :       if (rho == 0.0) relerr = PETSC_MAX_REAL;
     487          34 :       else relerr = 1.0 / (norm*PetscAbsScalar(rho));
     488             : 
     489             :       /* approximate eigenvalue is the shift */
     490          34 :       eps->eigr[eps->nconv] = rho;
     491             : 
     492             :       /* compute new shift */
     493          34 :       if (relerr<eps->tol) {
     494           8 :         rho = sigma;  /* if converged, restore original shift */
     495           8 :         PetscCall(STSetShift(eps->st,rho));
     496             :       } else {
     497          26 :         rho = rho + PetscConj(theta)/(delta*delta);  /* Rayleigh quotient R(v) */
     498          26 :         if (power->shift_type == EPS_POWER_SHIFT_WILKINSON) {
     499             :           /* beta1 is the norm of the residual associated with R(v) */
     500           9 :           PetscCall(BVGetColumn(eps->V,k,&v));
     501           9 :           PetscCall(VecAXPY(v,-PetscConj(theta)/(delta*delta),y));
     502           9 :           PetscCall(BVRestoreColumn(eps->V,k,&v));
     503           9 :           PetscCall(BVScaleColumn(eps->V,k,1.0/delta));
     504           9 :           PetscCall(BVNormColumn(eps->V,k,NORM_2,&norm1));
     505           9 :           beta1 = norm1;
     506             : 
     507             :           /* alpha2 = (e'*A*e)/(beta1*beta1), where e is the residual */
     508           9 :           PetscCall(STGetMatrix(eps->st,0,&A));
     509           9 :           PetscCall(BVGetColumn(eps->V,k,&v));
     510           9 :           PetscCall(MatMult(A,v,e));
     511           9 :           PetscCall(VecDot(v,e,&alpha2));
     512           9 :           PetscCall(BVRestoreColumn(eps->V,k,&v));
     513           9 :           alpha2 = alpha2 / (beta1 * beta1);
     514             : 
     515             :           /* choose the eigenvalue of [rho beta1; beta1 alpha2] closest to rho */
     516           9 :           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     517           9 :           PetscCallBLAS("LAPACKlaev2",LAPACKlaev2_(&rho,&beta1,&alpha2,&rt1,&rt2,&cs1,&sn1));
     518           9 :           PetscCall(PetscFPTrapPop());
     519           9 :           if (PetscAbsScalar(rt1-rho) < PetscAbsScalar(rt2-rho)) rho = rt1;
     520           3 :           else rho = rt2;
     521             :         }
     522             :         /* update operator according to new shift */
     523          26 :         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_FALSE));
     524          26 :         PetscCall(STSetShift(eps->st,rho));
     525          26 :         PetscCall(KSPGetConvergedReason(ksp,&reason));
     526          26 :         if (reason) {
     527           0 :           PetscCall(PetscInfo(eps,"Factorization failed, repeat with a perturbed shift\n"));
     528           0 :           rho *= 1+10*PETSC_MACHINE_EPSILON;
     529           0 :           PetscCall(STSetShift(eps->st,rho));
     530           0 :           PetscCall(KSPGetConvergedReason(ksp,&reason));
     531           0 :           PetscCheck(!reason,PetscObjectComm((PetscObject)ksp),PETSC_ERR_CONV_FAILED,"Second factorization failed");
     532             :         }
     533          26 :         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_TRUE));
     534             :       }
     535             :     }
     536       28609 :     eps->errest[eps->nconv] = relerr;
     537             : 
     538             :     /* normalize */
     539       28609 :     if (!power->nonlinear) PetscCall(Normalize(y,norm,power->idx,power->p,power->sign_normalization,NULL));
     540       28609 :     PetscCall(BVInsertVec(eps->V,k,y));
     541             : 
     542       28609 :     if (PetscUnlikely(power->update)) {
     543          14 :       PetscCall(SNESGetConvergedReason(power->snes,&snesreason));
     544             :       /* For Newton eigensolver, we are ready to return once SNES converged. */
     545          14 :       if (snesreason>0) eps->nconv = 1;
     546       28595 :     } else if (PetscUnlikely(relerr<eps->tol)) {   /* accept eigenpair */
     547          50 :       eps->nconv = eps->nconv + 1;
     548          50 :       if (eps->nconv<eps->nev) {
     549          31 :         PetscCall(EPSGetStartVector(eps,eps->nconv,&breakdown));
     550          31 :         if (breakdown) {
     551           0 :           eps->reason = EPS_DIVERGED_BREAKDOWN;
     552           0 :           PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
     553             :           break;
     554             :         }
     555             :       }
     556             :     }
     557             :     /* For Newton eigensolver, monitor will be called from SNES monitor */
     558       28609 :     if (!power->update) PetscCall(EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
     559       28609 :     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx));
     560             : 
     561             :     /**
     562             :      * When a customized stopping test is used, and reason can be set to be converged (EPS_CONVERGED_USER).
     563             :      * In this case, we need to increase eps->nconv to "1" so users can retrieve the solution.
     564             :      */
     565       28609 :     if (PetscUnlikely(power->nonlinear && eps->reason>0)) eps->nconv = 1;
     566             :   }
     567             : 
     568          45 :   if (power->nonlinear) PetscCall(PetscObjectCompose((PetscObject)power->snes,"eps",NULL));
     569             :   else {
     570          14 :     PetscCall(DSSetDimensions(eps->ds,eps->nconv,0,0));
     571          14 :     PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
     572             :   }
     573          45 :   PetscFunctionReturn(PETSC_SUCCESS);
     574             : }
     575             : 
     576           3 : static PetscErrorCode EPSSolve_TS_Power(EPS eps)
     577             : {
     578           3 :   EPS_POWER          *power = (EPS_POWER*)eps->data;
     579           3 :   PetscInt           k,ld;
     580           3 :   Vec                v,w,y,e,z;
     581           3 :   KSP                ksp;
     582           3 :   PetscReal          relerr=1.0,relerrl,delta;
     583           3 :   PetscScalar        theta,rho,alpha,sigma;
     584           3 :   PetscBool          breakdown,breakdownl;
     585           3 :   KSPConvergedReason reason;
     586             : 
     587           3 :   PetscFunctionBegin;
     588           3 :   e = eps->work[0];
     589           3 :   v = eps->work[1];
     590           3 :   w = eps->work[2];
     591             : 
     592           3 :   if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) PetscCall(STGetKSP(eps->st,&ksp));
     593           3 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     594           3 :   PetscCall(EPSGetStartVector(eps,0,NULL));
     595           3 :   PetscCall(EPSGetLeftStartVector(eps,0,NULL));
     596           3 :   PetscCall(BVBiorthonormalizeColumn(eps->V,eps->W,0,NULL));
     597           3 :   PetscCall(BVCopyVec(eps->V,0,v));
     598           3 :   PetscCall(BVCopyVec(eps->W,0,w));
     599           3 :   PetscCall(STGetShift(eps->st,&sigma));    /* original shift */
     600           3 :   rho = sigma;
     601             : 
     602           3 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     603         423 :     eps->its++;
     604         423 :     k = eps->nconv;
     605             : 
     606             :     /* y = OP v, z = OP' w */
     607         423 :     PetscCall(BVGetColumn(eps->V,k,&y));
     608         423 :     PetscCall(STApply(eps->st,v,y));
     609         423 :     PetscCall(BVRestoreColumn(eps->V,k,&y));
     610         423 :     PetscCall(BVGetColumn(eps->W,k,&z));
     611         423 :     PetscCall(STApplyHermitianTranspose(eps->st,w,z));
     612         423 :     PetscCall(BVRestoreColumn(eps->W,k,&z));
     613             : 
     614             :     /* purge previously converged eigenvectors */
     615         423 :     PetscCall(BVBiorthogonalizeColumn(eps->V,eps->W,k));
     616             : 
     617             :     /* theta = (w,y)_B */
     618         423 :     PetscCall(BVSetActiveColumns(eps->V,k,k+1));
     619         423 :     PetscCall(BVDotVec(eps->V,w,&theta));
     620         423 :     theta = PetscConj(theta);
     621             : 
     622         423 :     if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */
     623             : 
     624             :       /* approximate eigenvalue is the Rayleigh quotient */
     625         411 :       eps->eigr[eps->nconv] = theta;
     626             : 
     627             :       /* compute relative errors as ||y-theta v||_2/|theta| and ||z-conj(theta) w||_2/|theta|*/
     628         411 :       PetscCall(BVCopyVec(eps->V,k,e));
     629         411 :       PetscCall(VecAXPY(e,-theta,v));
     630         411 :       PetscCall(VecNorm(e,NORM_2,&relerr));
     631         411 :       PetscCall(BVCopyVec(eps->W,k,e));
     632         411 :       PetscCall(VecAXPY(e,-PetscConj(theta),w));
     633         411 :       PetscCall(VecNorm(e,NORM_2,&relerrl));
     634         792 :       relerr = PetscMax(relerr,relerrl)/PetscAbsScalar(theta);
     635             :     }
     636             : 
     637             :     /* normalize */
     638         423 :     PetscCall(BVSetActiveColumns(eps->V,k,k+1));
     639         423 :     PetscCall(BVGetColumn(eps->W,k,&z));
     640         423 :     PetscCall(BVDotVec(eps->V,z,&alpha));
     641         423 :     PetscCall(BVRestoreColumn(eps->W,k,&z));
     642         423 :     delta = PetscSqrtReal(PetscAbsScalar(alpha));
     643         423 :     PetscCheck(delta!=0.0,PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Breakdown in two-sided Power/RQI");
     644         423 :     PetscCall(BVScaleColumn(eps->V,k,1.0/PetscConj(alpha/delta)));
     645         423 :     PetscCall(BVScaleColumn(eps->W,k,1.0/delta));
     646         423 :     PetscCall(BVCopyVec(eps->V,k,v));
     647         423 :     PetscCall(BVCopyVec(eps->W,k,w));
     648             : 
     649         423 :     if (power->shift_type == EPS_POWER_SHIFT_RAYLEIGH) { /* RQI */
     650             : 
     651             :       /* compute relative error */
     652          12 :       if (rho == 0.0) relerr = PETSC_MAX_REAL;
     653          12 :       else relerr = 1.0 / PetscAbsScalar(delta*rho);
     654             : 
     655             :       /* approximate eigenvalue is the shift */
     656          12 :       eps->eigr[eps->nconv] = rho;
     657             : 
     658             :       /* compute new shift */
     659          12 :       if (relerr<eps->tol) {
     660           2 :         rho = sigma;  /* if converged, restore original shift */
     661           2 :         PetscCall(STSetShift(eps->st,rho));
     662             :       } else {
     663          10 :         rho = rho + PetscConj(theta)/(delta*delta);  /* Rayleigh quotient R(v) */
     664             :         /* update operator according to new shift */
     665          10 :         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_FALSE));
     666          10 :         PetscCall(STSetShift(eps->st,rho));
     667          10 :         PetscCall(KSPGetConvergedReason(ksp,&reason));
     668          10 :         if (reason) {
     669           0 :           PetscCall(PetscInfo(eps,"Factorization failed, repeat with a perturbed shift\n"));
     670           0 :           rho *= 1+10*PETSC_MACHINE_EPSILON;
     671           0 :           PetscCall(STSetShift(eps->st,rho));
     672           0 :           PetscCall(KSPGetConvergedReason(ksp,&reason));
     673           0 :           PetscCheck(!reason,PetscObjectComm((PetscObject)ksp),PETSC_ERR_CONV_FAILED,"Second factorization failed");
     674             :         }
     675          10 :         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_TRUE));
     676             :       }
     677             :     }
     678         423 :     eps->errest[eps->nconv] = relerr;
     679             : 
     680             :     /* if relerr<tol, accept eigenpair */
     681         423 :     if (relerr<eps->tol) {
     682           8 :       eps->nconv = eps->nconv + 1;
     683           8 :       if (eps->nconv<eps->nev) {
     684           5 :         PetscCall(EPSGetStartVector(eps,eps->nconv,&breakdown));
     685           5 :         PetscCall(EPSGetLeftStartVector(eps,eps->nconv,&breakdownl));
     686           5 :         if (breakdown || breakdownl) {
     687           0 :           eps->reason = EPS_DIVERGED_BREAKDOWN;
     688           0 :           PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
     689             :           break;
     690             :         }
     691           5 :         PetscCall(BVBiorthonormalizeColumn(eps->V,eps->W,eps->nconv,NULL));
     692             :       }
     693             :     }
     694         423 :     PetscCall(EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
     695         426 :     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx));
     696             :   }
     697             : 
     698           3 :   PetscCall(DSSetDimensions(eps->ds,eps->nconv,0,0));
     699           3 :   PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
     700           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     701             : }
     702             : 
     703       29032 : static PetscErrorCode EPSStopping_Power(EPS eps,PetscInt its,PetscInt max_it,PetscInt nconv,PetscInt nev,EPSConvergedReason *reason,void *ctx)
     704             : {
     705       29032 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     706       29032 :   SNESConvergedReason snesreason;
     707             : 
     708       29032 :   PetscFunctionBegin;
     709       29032 :   if (PetscUnlikely(power->update)) {
     710          14 :     PetscCall(SNESGetConvergedReason(power->snes,&snesreason));
     711          14 :     if (snesreason < 0) {
     712           0 :       *reason = EPS_DIVERGED_BREAKDOWN;
     713           0 :       PetscFunctionReturn(PETSC_SUCCESS);
     714             :     }
     715             :   }
     716       29032 :   PetscCall(EPSStoppingBasic(eps,its,max_it,nconv,nev,reason,ctx));
     717       29032 :   PetscFunctionReturn(PETSC_SUCCESS);
     718             : }
     719             : 
     720          17 : static PetscErrorCode EPSBackTransform_Power(EPS eps)
     721             : {
     722          17 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     723             : 
     724          17 :   PetscFunctionBegin;
     725          17 :   if (power->nonlinear) eps->eigr[0] = 1.0/eps->eigr[0];
     726          17 :   else if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) PetscCall(EPSBackTransform_Default(eps));
     727          17 :   PetscFunctionReturn(PETSC_SUCCESS);
     728             : }
     729             : 
     730          44 : static PetscErrorCode EPSSetFromOptions_Power(EPS eps,PetscOptionItems *PetscOptionsObject)
     731             : {
     732          44 :   EPS_POWER         *power = (EPS_POWER*)eps->data;
     733          44 :   PetscBool         flg,val;
     734          44 :   EPSPowerShiftType shift;
     735             : 
     736          44 :   PetscFunctionBegin;
     737          44 :   PetscOptionsHeadBegin(PetscOptionsObject,"EPS Power Options");
     738             : 
     739          44 :     PetscCall(PetscOptionsEnum("-eps_power_shift_type","Shift type","EPSPowerSetShiftType",EPSPowerShiftTypes,(PetscEnum)power->shift_type,(PetscEnum*)&shift,&flg));
     740          44 :     if (flg) PetscCall(EPSPowerSetShiftType(eps,shift));
     741             : 
     742          44 :     PetscCall(PetscOptionsBool("-eps_power_nonlinear","Use nonlinear inverse iteration","EPSPowerSetNonlinear",power->nonlinear,&val,&flg));
     743          44 :     if (flg) PetscCall(EPSPowerSetNonlinear(eps,val));
     744             : 
     745          44 :     PetscCall(PetscOptionsBool("-eps_power_update","Update residual monolithically","EPSPowerSetUpdate",power->update,&val,&flg));
     746          44 :     if (flg) PetscCall(EPSPowerSetUpdate(eps,val));
     747             : 
     748          44 :     PetscCall(PetscOptionsBool("-eps_power_sign_normalization","Normalize Bx with sign of first nonzero entry","EPSPowerSetSignNormalization",power->sign_normalization,&power->sign_normalization,&flg));
     749             : 
     750          44 :   PetscOptionsHeadEnd();
     751          44 :   PetscFunctionReturn(PETSC_SUCCESS);
     752             : }
     753             : 
     754           7 : static PetscErrorCode EPSPowerSetShiftType_Power(EPS eps,EPSPowerShiftType shift)
     755             : {
     756           7 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     757             : 
     758           7 :   PetscFunctionBegin;
     759           7 :   switch (shift) {
     760           7 :     case EPS_POWER_SHIFT_CONSTANT:
     761             :     case EPS_POWER_SHIFT_RAYLEIGH:
     762             :     case EPS_POWER_SHIFT_WILKINSON:
     763           7 :       if (power->shift_type != shift) {
     764           4 :         power->shift_type = shift;
     765           4 :         eps->state = EPS_STATE_INITIAL;
     766             :       }
     767           7 :       break;
     768           0 :     default:
     769           0 :       SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid shift type");
     770             :   }
     771           7 :   PetscFunctionReturn(PETSC_SUCCESS);
     772             : }
     773             : 
     774             : /*@
     775             :    EPSPowerSetShiftType - Sets the type of shifts used during the power
     776             :    iteration. This can be used to emulate the Rayleigh Quotient Iteration
     777             :    (RQI) method.
     778             : 
     779             :    Logically Collective
     780             : 
     781             :    Input Parameters:
     782             : +  eps - the eigenproblem solver context
     783             : -  shift - the type of shift
     784             : 
     785             :    Options Database Key:
     786             : .  -eps_power_shift_type - Sets the shift type (either 'constant' or
     787             :                            'rayleigh' or 'wilkinson')
     788             : 
     789             :    Notes:
     790             :    By default, shifts are constant (EPS_POWER_SHIFT_CONSTANT) and the iteration
     791             :    is the simple power method (or inverse iteration if a shift-and-invert
     792             :    transformation is being used).
     793             : 
     794             :    A variable shift can be specified (EPS_POWER_SHIFT_RAYLEIGH or
     795             :    EPS_POWER_SHIFT_WILKINSON). In this case, the iteration behaves rather like
     796             :    a cubic converging method such as RQI.
     797             : 
     798             :    Level: advanced
     799             : 
     800             : .seealso: EPSPowerGetShiftType(), STSetShift(), EPSPowerShiftType
     801             : @*/
     802           7 : PetscErrorCode EPSPowerSetShiftType(EPS eps,EPSPowerShiftType shift)
     803             : {
     804           7 :   PetscFunctionBegin;
     805           7 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     806          28 :   PetscValidLogicalCollectiveEnum(eps,shift,2);
     807           7 :   PetscTryMethod(eps,"EPSPowerSetShiftType_C",(EPS,EPSPowerShiftType),(eps,shift));
     808           7 :   PetscFunctionReturn(PETSC_SUCCESS);
     809             : }
     810             : 
     811           1 : static PetscErrorCode EPSPowerGetShiftType_Power(EPS eps,EPSPowerShiftType *shift)
     812             : {
     813           1 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     814             : 
     815           1 :   PetscFunctionBegin;
     816           1 :   *shift = power->shift_type;
     817           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     818             : }
     819             : 
     820             : /*@
     821             :    EPSPowerGetShiftType - Gets the type of shifts used during the power
     822             :    iteration.
     823             : 
     824             :    Not Collective
     825             : 
     826             :    Input Parameter:
     827             : .  eps - the eigenproblem solver context
     828             : 
     829             :    Output Parameter:
     830             : .  shift - the type of shift
     831             : 
     832             :    Level: advanced
     833             : 
     834             : .seealso: EPSPowerSetShiftType(), EPSPowerShiftType
     835             : @*/
     836           1 : PetscErrorCode EPSPowerGetShiftType(EPS eps,EPSPowerShiftType *shift)
     837             : {
     838           1 :   PetscFunctionBegin;
     839           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     840           1 :   PetscAssertPointer(shift,2);
     841           1 :   PetscUseMethod(eps,"EPSPowerGetShiftType_C",(EPS,EPSPowerShiftType*),(eps,shift));
     842           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     843             : }
     844             : 
     845          29 : static PetscErrorCode EPSPowerSetNonlinear_Power(EPS eps,PetscBool nonlinear)
     846             : {
     847          29 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     848             : 
     849          29 :   PetscFunctionBegin;
     850          29 :   if (power->nonlinear != nonlinear) {
     851          29 :     power->nonlinear = nonlinear;
     852          29 :     eps->useds = PetscNot(nonlinear);
     853          29 :     eps->ops->setupsort = nonlinear? NULL: EPSSetUpSort_Default;
     854          29 :     eps->state = EPS_STATE_INITIAL;
     855             :   }
     856          29 :   PetscFunctionReturn(PETSC_SUCCESS);
     857             : }
     858             : 
     859             : /*@
     860             :    EPSPowerSetNonlinear - Sets a flag to indicate that the problem is nonlinear.
     861             : 
     862             :    Logically Collective
     863             : 
     864             :    Input Parameters:
     865             : +  eps - the eigenproblem solver context
     866             : -  nonlinear - whether the problem is nonlinear or not
     867             : 
     868             :    Options Database Key:
     869             : .  -eps_power_nonlinear - Sets the nonlinear flag
     870             : 
     871             :    Notes:
     872             :    If this flag is set, the solver assumes that the problem is nonlinear,
     873             :    that is, the operators that define the eigenproblem are not constant
     874             :    matrices, but depend on the eigenvector, A(x)*x=lambda*B(x)*x. This is
     875             :    different from the case of nonlinearity with respect to the eigenvalue
     876             :    (use the NEP solver class for this kind of problems).
     877             : 
     878             :    The way in which nonlinear operators are specified is very similar to
     879             :    the case of PETSc's SNES solver. The difference is that the callback
     880             :    functions are provided via composed functions "formFunction" and
     881             :    "formJacobian" in each of the matrix objects passed as arguments of
     882             :    EPSSetOperators(). The application context required for these functions
     883             :    can be attached via a composed PetscContainer.
     884             : 
     885             :    Level: advanced
     886             : 
     887             : .seealso: EPSPowerGetNonlinear(), EPSSetOperators()
     888             : @*/
     889          29 : PetscErrorCode EPSPowerSetNonlinear(EPS eps,PetscBool nonlinear)
     890             : {
     891          29 :   PetscFunctionBegin;
     892          29 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     893         116 :   PetscValidLogicalCollectiveBool(eps,nonlinear,2);
     894          29 :   PetscTryMethod(eps,"EPSPowerSetNonlinear_C",(EPS,PetscBool),(eps,nonlinear));
     895          29 :   PetscFunctionReturn(PETSC_SUCCESS);
     896             : }
     897             : 
     898          17 : static PetscErrorCode EPSPowerGetNonlinear_Power(EPS eps,PetscBool *nonlinear)
     899             : {
     900          17 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     901             : 
     902          17 :   PetscFunctionBegin;
     903          17 :   *nonlinear = power->nonlinear;
     904          17 :   PetscFunctionReturn(PETSC_SUCCESS);
     905             : }
     906             : 
     907             : /*@
     908             :    EPSPowerGetNonlinear - Returns a flag indicating if the problem is nonlinear.
     909             : 
     910             :    Not Collective
     911             : 
     912             :    Input Parameter:
     913             : .  eps - the eigenproblem solver context
     914             : 
     915             :    Output Parameter:
     916             : .  nonlinear - the nonlinear flag
     917             : 
     918             :    Level: advanced
     919             : 
     920             : .seealso: EPSPowerSetUpdate(), EPSPowerSetNonlinear()
     921             : @*/
     922          17 : PetscErrorCode EPSPowerGetNonlinear(EPS eps,PetscBool *nonlinear)
     923             : {
     924          17 :   PetscFunctionBegin;
     925          17 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     926          17 :   PetscAssertPointer(nonlinear,2);
     927          17 :   PetscUseMethod(eps,"EPSPowerGetNonlinear_C",(EPS,PetscBool*),(eps,nonlinear));
     928          17 :   PetscFunctionReturn(PETSC_SUCCESS);
     929             : }
     930             : 
     931          12 : static PetscErrorCode EPSPowerSetUpdate_Power(EPS eps,PetscBool update)
     932             : {
     933          12 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     934             : 
     935          12 :   PetscFunctionBegin;
     936          12 :   PetscCheck(power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_INCOMP,"This option does not make sense for linear problems");
     937          12 :   power->update = update;
     938          12 :   eps->state = EPS_STATE_INITIAL;
     939          12 :   PetscFunctionReturn(PETSC_SUCCESS);
     940             : }
     941             : 
     942             : /*@
     943             :    EPSPowerSetUpdate - Sets a flag to indicate that the residual is updated monolithically
     944             :    for nonlinear problems. This potentially has a better convergence.
     945             : 
     946             :    Logically Collective
     947             : 
     948             :    Input Parameters:
     949             : +  eps - the eigenproblem solver context
     950             : -  update - whether the residual is updated monolithically or not
     951             : 
     952             :    Options Database Key:
     953             : .  -eps_power_update - Sets the update flag
     954             : 
     955             :    Level: advanced
     956             : 
     957             : .seealso: EPSPowerGetUpdate(), EPSPowerGetNonlinear(), EPSSetOperators()
     958             : @*/
     959          12 : PetscErrorCode EPSPowerSetUpdate(EPS eps,PetscBool update)
     960             : {
     961          12 :   PetscFunctionBegin;
     962          12 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     963          48 :   PetscValidLogicalCollectiveBool(eps,update,2);
     964          12 :   PetscTryMethod(eps,"EPSPowerSetUpdate_C",(EPS,PetscBool),(eps,update));
     965          12 :   PetscFunctionReturn(PETSC_SUCCESS);
     966             : }
     967             : 
     968          17 : static PetscErrorCode EPSPowerGetUpdate_Power(EPS eps,PetscBool *update)
     969             : {
     970          17 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     971             : 
     972          17 :   PetscFunctionBegin;
     973          17 :   *update = power->update;
     974          17 :   PetscFunctionReturn(PETSC_SUCCESS);
     975             : }
     976             : 
     977             : /*@
     978             :    EPSPowerGetUpdate - Returns a flag indicating if the residual is updated monolithically
     979             :    for nonlinear problems.
     980             : 
     981             :    Not Collective
     982             : 
     983             :    Input Parameter:
     984             : .  eps - the eigenproblem solver context
     985             : 
     986             :    Output Parameter:
     987             : .  update - the update flag
     988             : 
     989             :    Level: advanced
     990             : 
     991             : .seealso: EPSPowerSetUpdate(), EPSPowerSetNonlinear()
     992             : @*/
     993          17 : PetscErrorCode EPSPowerGetUpdate(EPS eps,PetscBool *update)
     994             : {
     995          17 :   PetscFunctionBegin;
     996          17 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     997          17 :   PetscAssertPointer(update,2);
     998          17 :   PetscUseMethod(eps,"EPSPowerGetUpdate_C",(EPS,PetscBool*),(eps,update));
     999          17 :   PetscFunctionReturn(PETSC_SUCCESS);
    1000             : }
    1001             : 
    1002          29 : static PetscErrorCode EPSPowerSetSignNormalization_Power(EPS eps,PetscBool sign_normalization)
    1003             : {
    1004          29 :   EPS_POWER *power = (EPS_POWER*)eps->data;
    1005             : 
    1006          29 :   PetscFunctionBegin;
    1007          29 :   power->sign_normalization = sign_normalization;
    1008          29 :   PetscFunctionReturn(PETSC_SUCCESS);
    1009             : }
    1010             : 
    1011             : /*@
    1012             :    EPSPowerSetSignNormalization - Sets a flag to indicate whether the Bx vector
    1013             :    should be normalized by the sign of the first non-zero element in the vector.
    1014             :    E.g., if this is true, the post-normalization value of the first non-zero element
    1015             :    in the vector is guaranteed to be positive.
    1016             : 
    1017             :    Logically Collective
    1018             : 
    1019             :    Input Parameters:
    1020             : +  eps - the eigenproblem solver context
    1021             : -  sign_normalization - whether Bx should be multiplied by the sign of the first non-zero
    1022             :                         element when performing normalization steps
    1023             : 
    1024             :    Options Database Key:
    1025             : .  -eps_power_sign_normalization - Sets the sign normalization flag
    1026             : 
    1027             :    Level: advanced
    1028             : 
    1029             : .seealso: EPSPowerGetSignNormalization()
    1030             : @*/
    1031          29 : PetscErrorCode EPSPowerSetSignNormalization(EPS eps,PetscBool sign_normalization)
    1032             : {
    1033          29 :   PetscFunctionBegin;
    1034          29 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1035         116 :   PetscValidLogicalCollectiveBool(eps,sign_normalization,2);
    1036          29 :   PetscTryMethod(eps,"EPSPowerSetSignNormalization_C",(EPS,PetscBool),(eps,sign_normalization));
    1037          29 :   PetscFunctionReturn(PETSC_SUCCESS);
    1038             : }
    1039             : 
    1040          12 : static PetscErrorCode EPSPowerGetSignNormalization_Power(EPS eps,PetscBool *sign_normalization)
    1041             : {
    1042          12 :   EPS_POWER *power = (EPS_POWER*)eps->data;
    1043             : 
    1044          12 :   PetscFunctionBegin;
    1045          12 :   *sign_normalization = power->sign_normalization;
    1046          12 :   PetscFunctionReturn(PETSC_SUCCESS);
    1047             : }
    1048             : 
    1049             : /*@
    1050             :    EPSPowerGetSignNormalization - Returns a flag indicating whether the Bx vector
    1051             :    is normalized by the sign of the first non-zero element in the vector. E.g.,
    1052             :    if this is true, the post-normalization value of the first non-zero element in
    1053             :    the vector is guaranteed to be positive.
    1054             : 
    1055             :    Not Collective
    1056             : 
    1057             :    Input Parameter:
    1058             : .  eps - the eigenproblem solver context
    1059             : 
    1060             :    Output Parameter:
    1061             : .  sign_normalization - the sign normalization flag
    1062             : 
    1063             :    Level: advanced
    1064             : 
    1065             : .seealso: EPSPowerSetSignNormalization()
    1066             : @*/
    1067          12 : PetscErrorCode EPSPowerGetSignNormalization(EPS eps,PetscBool *sign_normalization)
    1068             : {
    1069          12 :   PetscFunctionBegin;
    1070          12 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1071          12 :   PetscAssertPointer(sign_normalization,2);
    1072          12 :   PetscUseMethod(eps,"EPSPowerGetSignNormalization_C",(EPS,PetscBool*),(eps,sign_normalization));
    1073          12 :   PetscFunctionReturn(PETSC_SUCCESS);
    1074             : }
    1075             : 
    1076           0 : static PetscErrorCode EPSPowerSetSNES_Power(EPS eps,SNES snes)
    1077             : {
    1078           0 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1079             : 
    1080           0 :   PetscFunctionBegin;
    1081           0 :   PetscCall(PetscObjectReference((PetscObject)snes));
    1082           0 :   PetscCall(SNESDestroy(&power->snes));
    1083           0 :   power->snes = snes;
    1084           0 :   eps->state = EPS_STATE_INITIAL;
    1085           0 :   PetscFunctionReturn(PETSC_SUCCESS);
    1086             : }
    1087             : 
    1088             : /*@
    1089             :    EPSPowerSetSNES - Associate a nonlinear solver object (SNES) to the
    1090             :    eigenvalue solver (to be used in nonlinear inverse iteration).
    1091             : 
    1092             :    Collective
    1093             : 
    1094             :    Input Parameters:
    1095             : +  eps  - the eigenvalue solver
    1096             : -  snes - the nonlinear solver object
    1097             : 
    1098             :    Level: advanced
    1099             : 
    1100             : .seealso: EPSPowerGetSNES()
    1101             : @*/
    1102           0 : PetscErrorCode EPSPowerSetSNES(EPS eps,SNES snes)
    1103             : {
    1104           0 :   PetscFunctionBegin;
    1105           0 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1106           0 :   PetscValidHeaderSpecific(snes,SNES_CLASSID,2);
    1107           0 :   PetscCheckSameComm(eps,1,snes,2);
    1108           0 :   PetscTryMethod(eps,"EPSPowerSetSNES_C",(EPS,SNES),(eps,snes));
    1109           0 :   PetscFunctionReturn(PETSC_SUCCESS);
    1110             : }
    1111             : 
    1112          41 : static PetscErrorCode EPSPowerGetSNES_Power(EPS eps,SNES *snes)
    1113             : {
    1114          41 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1115             : 
    1116          41 :   PetscFunctionBegin;
    1117          41 :   if (!power->snes) {
    1118          29 :     PetscCall(SNESCreate(PetscObjectComm((PetscObject)eps),&power->snes));
    1119          29 :     PetscCall(PetscObjectIncrementTabLevel((PetscObject)power->snes,(PetscObject)eps,1));
    1120          29 :     PetscCall(SNESSetOptionsPrefix(power->snes,((PetscObject)eps)->prefix));
    1121          29 :     PetscCall(SNESAppendOptionsPrefix(power->snes,"eps_power_"));
    1122          29 :     PetscCall(PetscObjectSetOptions((PetscObject)power->snes,((PetscObject)eps)->options));
    1123             :   }
    1124          41 :   *snes = power->snes;
    1125          41 :   PetscFunctionReturn(PETSC_SUCCESS);
    1126             : }
    1127             : 
    1128             : /*@
    1129             :    EPSPowerGetSNES - Retrieve the nonlinear solver object (SNES) associated
    1130             :    with the eigenvalue solver.
    1131             : 
    1132             :    Not Collective
    1133             : 
    1134             :    Input Parameter:
    1135             : .  eps - the eigenvalue solver
    1136             : 
    1137             :    Output Parameter:
    1138             : .  snes - the nonlinear solver object
    1139             : 
    1140             :    Level: advanced
    1141             : 
    1142             : .seealso: EPSPowerSetSNES()
    1143             : @*/
    1144          41 : PetscErrorCode EPSPowerGetSNES(EPS eps,SNES *snes)
    1145             : {
    1146          41 :   PetscFunctionBegin;
    1147          41 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1148          41 :   PetscAssertPointer(snes,2);
    1149          41 :   PetscUseMethod(eps,"EPSPowerGetSNES_C",(EPS,SNES*),(eps,snes));
    1150          41 :   PetscFunctionReturn(PETSC_SUCCESS);
    1151             : }
    1152             : 
    1153          45 : static PetscErrorCode EPSReset_Power(EPS eps)
    1154             : {
    1155          45 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1156             : 
    1157          45 :   PetscFunctionBegin;
    1158          45 :   if (power->snes) PetscCall(SNESReset(power->snes));
    1159          45 :   PetscFunctionReturn(PETSC_SUCCESS);
    1160             : }
    1161             : 
    1162          44 : static PetscErrorCode EPSDestroy_Power(EPS eps)
    1163             : {
    1164          44 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1165             : 
    1166          44 :   PetscFunctionBegin;
    1167          44 :   if (power->nonlinear) PetscCall(SNESDestroy(&power->snes));
    1168          44 :   PetscCall(PetscFree(eps->data));
    1169          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",NULL));
    1170          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",NULL));
    1171          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetNonlinear_C",NULL));
    1172          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetNonlinear_C",NULL));
    1173          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetUpdate_C",NULL));
    1174          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetUpdate_C",NULL));
    1175          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSignNormalization_C",NULL));
    1176          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSignNormalization_C",NULL));
    1177          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSNES_C",NULL));
    1178          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSNES_C",NULL));
    1179          44 :   PetscFunctionReturn(PETSC_SUCCESS);
    1180             : }
    1181             : 
    1182           0 : static PetscErrorCode EPSView_Power(EPS eps,PetscViewer viewer)
    1183             : {
    1184           0 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1185           0 :   PetscBool      isascii;
    1186             : 
    1187           0 :   PetscFunctionBegin;
    1188           0 :   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    1189           0 :   if (isascii) {
    1190           0 :     if (power->nonlinear) {
    1191           0 :       if (power->sign_normalization) PetscCall(PetscViewerASCIIPrintf(viewer,"  normalizing Bx by the sign of the first nonzero element\n"));
    1192           0 :       else PetscCall(PetscViewerASCIIPrintf(viewer,"  not normalizing Bx by the sign of the first nonzero element\n"));
    1193           0 :       PetscCall(PetscViewerASCIIPrintf(viewer,"  using nonlinear inverse iteration\n"));
    1194           0 :       if (power->update) PetscCall(PetscViewerASCIIPrintf(viewer,"  updating the residual monolithically\n"));
    1195           0 :       if (!power->snes) PetscCall(EPSPowerGetSNES(eps,&power->snes));
    1196           0 :       PetscCall(PetscViewerASCIIPushTab(viewer));
    1197           0 :       PetscCall(SNESView(power->snes,viewer));
    1198           0 :       PetscCall(PetscViewerASCIIPopTab(viewer));
    1199           0 :     } else PetscCall(PetscViewerASCIIPrintf(viewer,"  %s shifts\n",EPSPowerShiftTypes[power->shift_type]));
    1200             :   }
    1201           0 :   PetscFunctionReturn(PETSC_SUCCESS);
    1202             : }
    1203             : 
    1204          36 : static PetscErrorCode EPSComputeVectors_Power(EPS eps)
    1205             : {
    1206          36 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1207             : 
    1208          36 :   PetscFunctionBegin;
    1209          36 :   if (eps->twosided) {
    1210           3 :     PetscCall(EPSComputeVectors_Twosided(eps));
    1211           3 :     PetscCall(BVNormalize(eps->V,NULL));
    1212           3 :     PetscCall(BVNormalize(eps->W,NULL));
    1213          33 :   } else if (!power->nonlinear) PetscCall(EPSComputeVectors_Schur(eps));
    1214          36 :   PetscFunctionReturn(PETSC_SUCCESS);
    1215             : }
    1216             : 
    1217          92 : static PetscErrorCode EPSSetDefaultST_Power(EPS eps)
    1218             : {
    1219          92 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1220          92 :   KSP            ksp;
    1221          92 :   PC             pc;
    1222             : 
    1223          92 :   PetscFunctionBegin;
    1224          92 :   if (power->nonlinear) {
    1225          60 :     eps->categ=EPS_CATEGORY_PRECOND;
    1226          60 :     PetscCall(STGetKSP(eps->st,&ksp));
    1227             :     /* Set ST as STPRECOND so it can carry one preconditioning matrix
    1228             :      * It is useful when A and B are shell matrices
    1229             :      */
    1230          60 :     PetscCall(STSetType(eps->st,STPRECOND));
    1231          60 :     PetscCall(KSPGetPC(ksp,&pc));
    1232          60 :     PetscCall(PCSetType(pc,PCNONE));
    1233             :   }
    1234          92 :   PetscFunctionReturn(PETSC_SUCCESS);
    1235             : }
    1236             : 
    1237          44 : SLEPC_EXTERN PetscErrorCode EPSCreate_Power(EPS eps)
    1238             : {
    1239          44 :   EPS_POWER      *ctx;
    1240             : 
    1241          44 :   PetscFunctionBegin;
    1242          44 :   PetscCall(PetscNew(&ctx));
    1243          44 :   eps->data = (void*)ctx;
    1244             : 
    1245          44 :   eps->useds = PETSC_TRUE;
    1246          44 :   eps->categ = EPS_CATEGORY_OTHER;
    1247             : 
    1248          44 :   eps->ops->setup          = EPSSetUp_Power;
    1249          44 :   eps->ops->setupsort      = EPSSetUpSort_Default;
    1250          44 :   eps->ops->setfromoptions = EPSSetFromOptions_Power;
    1251          44 :   eps->ops->reset          = EPSReset_Power;
    1252          44 :   eps->ops->destroy        = EPSDestroy_Power;
    1253          44 :   eps->ops->view           = EPSView_Power;
    1254          44 :   eps->ops->backtransform  = EPSBackTransform_Power;
    1255          44 :   eps->ops->computevectors = EPSComputeVectors_Power;
    1256          44 :   eps->ops->setdefaultst   = EPSSetDefaultST_Power;
    1257          44 :   eps->stopping            = EPSStopping_Power;
    1258          44 :   ctx->sign_normalization  = PETSC_TRUE;
    1259             : 
    1260          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",EPSPowerSetShiftType_Power));
    1261          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",EPSPowerGetShiftType_Power));
    1262          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetNonlinear_C",EPSPowerSetNonlinear_Power));
    1263          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetNonlinear_C",EPSPowerGetNonlinear_Power));
    1264          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetUpdate_C",EPSPowerSetUpdate_Power));
    1265          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetUpdate_C",EPSPowerGetUpdate_Power));
    1266          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSignNormalization_C",EPSPowerSetSignNormalization_Power));
    1267          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSignNormalization_C",EPSPowerGetSignNormalization_Power));
    1268          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSNES_C",EPSPowerSetSNES_Power));
    1269          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSNES_C",EPSPowerGetSNES_Power));
    1270          44 :   PetscFunctionReturn(PETSC_SUCCESS);
    1271             : }

Generated by: LCOV version 1.14