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

Generated by: LCOV version 1.14