LCOV - code coverage report
Current view: top level - eps/impls/power - power.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 624 681 91.6 %
Date: 2024-12-18 00:51:33 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 :   EPSCheckNotStructured(eps);
      87          48 :   if (eps->nev==0) eps->nev = 1;
      88          48 :   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          43 :   } else eps->ncv = eps->nev;
      91          48 :   if (eps->mpd!=PETSC_DETERMINE) PetscCall(PetscInfo(eps,"Warning: parameter mpd ignored\n"));
      92          48 :   if (eps->max_it==PETSC_DETERMINE) {
      93             :     /* SNES will directly return the solution for us, and we need to do only one iteration */
      94          28 :     if (power->nonlinear && power->update) eps->max_it = 1;
      95          16 :     else eps->max_it = PetscMax(1000*eps->nev,100*eps->n);
      96             :   }
      97          48 :   if (!eps->which) PetscCall(EPSSetWhichEigenpairs_Default(eps));
      98          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");
      99          48 :   if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) {
     100           4 :     PetscCheck(!power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Variable shifts not allowed in nonlinear problems");
     101           4 :     EPSCheckSinvertCayleyCondition(eps,PETSC_TRUE," (with variable shifts)");
     102           4 :     PetscCall(STGetMatMode(eps->st,&mode));
     103           4 :     PetscCheck(mode!=ST_MATMODE_INPLACE,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"ST matrix mode inplace does not work with variable shifts");
     104             :   }
     105          48 :   EPSCheckUnsupported(eps,EPS_FEATURE_BALANCE | EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_CONVERGENCE | EPS_FEATURE_THRESHOLD);
     106          48 :   EPSCheckIgnored(eps,EPS_FEATURE_EXTRACTION);
     107          48 :   PetscCall(EPSAllocateSolution(eps,0));
     108          48 :   PetscCall(EPS_SetInnerProduct(eps));
     109             : 
     110          48 :   if (power->nonlinear) {
     111          31 :     PetscCheck(eps->nev==1,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Nonlinear inverse iteration cannot compute more than one eigenvalue");
     112          31 :     PetscCall(EPSSetWorkVecs(eps,3));
     113          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)");
     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          31 :     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          31 :     if (eps->IS) PetscCall(VecNorm(eps->IS[0],NORM_2,&power->norm0));
     123             : 
     124          31 :     PetscCall(EPSGetOperators(eps,&A,&B));
     125             : 
     126             :     /* form function */
     127          31 :     PetscCall(PetscObjectQueryFunction((PetscObject)A,"formFunction",&formFunctionA));
     128          31 :     PetscCheck(formFunctionA,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER,"For nonlinear inverse iteration you must compose a callback function 'formFunction' in matrix A");
     129          31 :     PetscCall(PetscObjectQuery((PetscObject)A,"formFunctionCtx",(PetscObject*)&container));
     130          31 :     if (container) PetscCall(PetscContainerGetPointer(container,&ctx));
     131           0 :     else ctx = NULL;
     132          31 :     PetscCall(MatCreateVecs(A,&res,NULL));
     133          31 :     power->formFunctionA = formFunctionA;
     134          31 :     power->formFunctionActx = ctx;
     135          31 :     if (power->update) {
     136          14 :       PetscCall(SNESSetFunction(power->snes,res,EPSPowerFormFunction_Update,ctx));
     137          14 :       PetscCall(PetscObjectQueryFunction((PetscObject)A,"formFunctionAB",&power->formFunctionAB));
     138          14 :       PetscCall(SNESMonitorSet(power->snes,SNESMonitor_PowerUpdate,NULL,NULL));
     139             :     }
     140          17 :     else PetscCall(SNESSetFunction(power->snes,res,formFunctionA,ctx));
     141          31 :     PetscCall(VecDestroy(&res));
     142             : 
     143             :     /* form Jacobian */
     144          31 :     PetscCall(PetscObjectQueryFunction((PetscObject)A,"formJacobian",&formJacobianA));
     145          31 :     PetscCheck(formJacobianA,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER,"For nonlinear inverse iteration you must compose a callback function 'formJacobian' in matrix A");
     146          31 :     PetscCall(PetscObjectQuery((PetscObject)A,"formJacobianCtx",(PetscObject*)&container));
     147          31 :     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          31 :     PetscCall(STGetPreconditionerMat(eps->st,&P));
     153             :     /* If users do not provide a matrix, we simply use A */
     154          31 :     PetscCall(SNESSetJacobian(power->snes,A,P? P:A,formJacobianA,ctx));
     155          31 :     PetscCall(SNESSetFromOptions(power->snes));
     156          31 :     PetscCall(SNESSetUp(power->snes));
     157             : 
     158          31 :     ctx = NULL;
     159          31 :     formNorm = NULL;
     160          31 :     if (B) {
     161          31 :       PetscCall(PetscObjectQueryFunction((PetscObject)B,"formFunction",&power->formFunctionB));
     162          31 :       PetscCall(PetscObjectQuery((PetscObject)B,"formFunctionCtx",(PetscObject*)&container));
     163          31 :       if (power->formFunctionB && container) PetscCall(PetscContainerGetPointer(container,&power->formFunctionBctx));
     164           0 :       else power->formFunctionBctx = NULL;
     165             : 
     166             :       /* form norm */
     167          31 :       PetscCall(PetscObjectQueryFunction((PetscObject)B,"formNorm",&formNorm));
     168          31 :       if (formNorm) {
     169           8 :         PetscCall(PetscObjectQuery((PetscObject)B,"formNormCtx",(PetscObject*)&container));
     170           8 :         if (container) PetscCall(PetscContainerGetPointer(container,&ctx));
     171             :       }
     172             :     }
     173          31 :     power->formNorm = formNorm;
     174          31 :     power->formNormCtx = ctx;
     175             :   } else {
     176          17 :     if (eps->twosided) PetscCall(EPSSetWorkVecs(eps,3));
     177          14 :     else PetscCall(EPSSetWorkVecs(eps,2));
     178          17 :     PetscCall(DSSetType(eps->ds,DSNHEP));
     179          17 :     PetscCall(DSAllocate(eps->ds,eps->nev));
     180             :   }
     181             :   /* dispatch solve method */
     182          48 :   if (eps->twosided) {
     183           3 :     PetscCheck(!power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Nonlinear inverse iteration does not have two-sided variant");
     184           3 :     PetscCheck(power->shift_type!=EPS_POWER_SHIFT_WILKINSON,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Two-sided variant does not support Wilkinson shifts");
     185           3 :     eps->ops->solve = EPSSolve_TS_Power;
     186          45 :   } else eps->ops->solve = EPSSolve_Power;
     187          48 :   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          31 : static PetscErrorCode FirstNonzeroIdx(Vec x,PetscInt *idx,PetscMPIInt *p)
     194             : {
     195          31 :   PetscInt          i,first,last,N;
     196          31 :   PetscLayout       map;
     197          31 :   const PetscScalar *xx;
     198             : 
     199          31 :   PetscFunctionBegin;
     200          31 :   PetscCall(VecGetSize(x,&N));
     201          31 :   PetscCall(VecGetOwnershipRange(x,&first,&last));
     202          31 :   PetscCall(VecGetArrayRead(x,&xx));
     203         341 :   for (i=first;i<last;i++) {
     204         341 :     if (PetscAbsScalar(xx[i-first])>10*PETSC_MACHINE_EPSILON) break;
     205             :   }
     206          31 :   PetscCall(VecRestoreArrayRead(x,&xx));
     207          31 :   if (i==last) i=N;
     208          93 :   PetscCallMPI(MPIU_Allreduce(&i,idx,1,MPIU_INT,MPI_MIN,PetscObjectComm((PetscObject)x)));
     209          31 :   PetscCheck(*idx!=N,PetscObjectComm((PetscObject)x),PETSC_ERR_PLIB,"Zero vector found");
     210          31 :   PetscCall(VecGetLayout(x,&map));
     211          31 :   PetscCall(PetscLayoutFindOwner(map,*idx,p));
     212          31 :   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       29308 : static PetscErrorCode Normalize(Vec x,PetscReal norm,PetscInt idx,PetscMPIInt p,PetscBool sign_normalization,PetscScalar *sign)
     220             : {
     221       29308 :   PetscScalar       alpha=1.0;
     222       29308 :   PetscInt          first,last;
     223       29308 :   PetscReal         absv;
     224       29308 :   const PetscScalar *xx;
     225             : 
     226       29308 :   PetscFunctionBegin;
     227       29308 :   if (sign_normalization) {
     228       29022 :     PetscCall(VecGetOwnershipRange(x,&first,&last));
     229       29022 :     if (idx>=first && idx<last) {
     230       29022 :       PetscCall(VecGetArrayRead(x,&xx));
     231       29022 :       absv = PetscAbsScalar(xx[idx-first]);
     232       29022 :       if (absv>10*PETSC_MACHINE_EPSILON) alpha = xx[idx-first]/absv;
     233       29022 :       PetscCall(VecRestoreArrayRead(x,&xx));
     234             :     }
     235       58044 :     PetscCallMPI(MPI_Bcast(&alpha,1,MPIU_SCALAR,p,PetscObjectComm((PetscObject)x)));
     236             :   }
     237       29308 :   if (sign) *sign = alpha;
     238       29308 :   alpha *= norm;
     239       29308 :   PetscCall(VecScale(x,1.0/alpha));
     240       29308 :   PetscFunctionReturn(PETSC_SUCCESS);
     241             : }
     242             : 
     243         661 : static PetscErrorCode EPSPowerUpdateFunctionB(EPS eps,Vec x,Vec Bx)
     244             : {
     245         661 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     246         661 :   Mat            B;
     247             : 
     248         661 :   PetscFunctionBegin;
     249         661 :   PetscCall(STResetMatrixState(eps->st));
     250         661 :   PetscCall(EPSGetOperators(eps,NULL,&B));
     251         661 :   if (B) {
     252         661 :     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         661 :   PetscFunctionReturn(PETSC_SUCCESS);
     256             : }
     257             : 
     258         445 : static PetscErrorCode EPSPowerUpdateFunctionA(EPS eps,Vec x,Vec Ax)
     259             : {
     260         445 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     261         445 :   Mat            A;
     262             : 
     263         445 :   PetscFunctionBegin;
     264         445 :   PetscCall(STResetMatrixState(eps->st));
     265         445 :   PetscCall(EPSGetOperators(eps,&A,NULL));
     266         445 :   PetscCheck(A,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_NULL,"Matrix A is required for an eigenvalue problem");
     267         445 :   if (power->formFunctionA) PetscCall((*power->formFunctionA)(power->snes,x,Ax,power->formFunctionActx));
     268           0 :   else PetscCall(MatMult(A,x,Ax));
     269         445 :   PetscFunctionReturn(PETSC_SUCCESS);
     270             : }
     271             : 
     272         682 : static PetscErrorCode EPSPowerFormFunction_Update(SNES snes,Vec x,Vec y,void *ctx)
     273             : {
     274         682 :   EPS            eps;
     275         682 :   PetscReal      bx;
     276         682 :   Vec            Bx;
     277         682 :   PetscScalar    sign;
     278         682 :   EPS_POWER      *power;
     279             : 
     280         682 :   PetscFunctionBegin;
     281         682 :   PetscCall(PetscObjectQuery((PetscObject)snes,"eps",(PetscObject *)&eps));
     282         682 :   PetscCheck(eps,PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_NULL,"No composed EPS");
     283         682 :   PetscCall(STResetMatrixState(eps->st));
     284         682 :   power = (EPS_POWER*)eps->data;
     285         682 :   Bx = eps->work[2];
     286         682 :   if (power->formFunctionAB) PetscCall((*power->formFunctionAB)(snes,x,y,Bx,ctx));
     287             :   else {
     288         445 :     PetscCall(EPSPowerUpdateFunctionA(eps,x,y));
     289         445 :     PetscCall(EPSPowerUpdateFunctionB(eps,x,Bx));
     290             :   }
     291         682 :   if (power->formNorm) PetscCall((*power->formNorm)(snes,Bx,&bx,power->formNormCtx));
     292         472 :   else PetscCall(VecNorm(Bx,NORM_2,&bx));
     293         682 :   PetscCall(Normalize(Bx,bx,power->idx,power->p,power->sign_normalization,&sign));
     294         682 :   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         682 :   eps->eigr[(eps->nconv < eps->nev)? eps->nconv:(eps->nconv-1)] = 1.0/(bx*sign);
     297         682 :   PetscFunctionReturn(PETSC_SUCCESS);
     298             : }
     299             : 
     300             : /*
     301             :    Use SNES to compute y = A^{-1}*B*x for the nonlinear problem
     302             : */
     303         199 : static PetscErrorCode EPSPowerApply_SNES(EPS eps,Vec x,Vec y)
     304             : {
     305         199 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     306         199 :   Vec            Bx;
     307             : 
     308         199 :   PetscFunctionBegin;
     309         199 :   PetscCall(VecCopy(x,y));
     310         199 :   if (power->update) PetscCall(SNESSolve(power->snes,NULL,y));
     311             :   else {
     312         185 :     Bx = eps->work[2];
     313         185 :     PetscCall(SNESSolve(power->snes,Bx,y));
     314             :   }
     315         199 :   PetscFunctionReturn(PETSC_SUCCESS);
     316             : }
     317             : 
     318             : /*
     319             :    Use nonlinear inverse power to compute an initial guess
     320             : */
     321          12 : static PetscErrorCode EPSPowerComputeInitialGuess_Update(EPS eps)
     322             : {
     323          12 :   EPS            powereps;
     324          12 :   Mat            A,B,P;
     325          12 :   Vec            v1,v2;
     326          12 :   SNES           snes;
     327          12 :   DM             dm,newdm;
     328          12 :   PetscBool      sign_normalization;
     329             : 
     330          12 :   PetscFunctionBegin;
     331          12 :   PetscCall(EPSCreate(PetscObjectComm((PetscObject)eps),&powereps));
     332          12 :   PetscCall(EPSGetOperators(eps,&A,&B));
     333          12 :   PetscCall(EPSSetType(powereps,EPSPOWER));
     334          12 :   PetscCall(EPSSetOperators(powereps,A,B));
     335          12 :   PetscCall(EPSSetTolerances(powereps,1e-6,4));
     336          12 :   PetscCall(EPSSetOptionsPrefix(powereps,((PetscObject)eps)->prefix));
     337          12 :   PetscCall(EPSAppendOptionsPrefix(powereps,"init_"));
     338          12 :   PetscCall(EPSSetProblemType(powereps,EPS_GNHEP));
     339          12 :   PetscCall(EPSSetWhichEigenpairs(powereps,EPS_TARGET_MAGNITUDE));
     340          12 :   PetscCall(EPSPowerSetNonlinear(powereps,PETSC_TRUE));
     341          12 :   PetscCall(STGetPreconditionerMat(eps->st,&P));
     342             :   /* attach dm to initial solve */
     343          12 :   PetscCall(EPSPowerGetSNES(eps,&snes));
     344          12 :   PetscCall(SNESGetDM(snes,&dm));
     345             :   /* use  dmshell to temporarily store snes context */
     346          12 :   PetscCall(DMCreate(PetscObjectComm((PetscObject)eps),&newdm));
     347          12 :   PetscCall(DMSetType(newdm,DMSHELL));
     348          12 :   PetscCall(DMSetUp(newdm));
     349          12 :   PetscCall(DMCopyDMSNES(dm,newdm));
     350          12 :   PetscCall(EPSPowerGetSNES(powereps,&snes));
     351          12 :   PetscCall(SNESSetDM(snes,dm));
     352          12 :   PetscCall(EPSPowerGetSignNormalization(eps,&sign_normalization));
     353          12 :   PetscCall(EPSPowerSetSignNormalization(powereps,sign_normalization));
     354          12 :   PetscCall(EPSSetFromOptions(powereps));
     355          12 :   if (P) PetscCall(STSetPreconditionerMat(powereps->st,P));
     356          12 :   PetscCall(EPSSolve(powereps));
     357          12 :   PetscCall(BVGetColumn(eps->V,0,&v2));
     358          12 :   PetscCall(BVGetColumn(powereps->V,0,&v1));
     359          12 :   PetscCall(VecCopy(v1,v2));
     360          12 :   PetscCall(BVRestoreColumn(powereps->V,0,&v1));
     361          12 :   PetscCall(BVRestoreColumn(eps->V,0,&v2));
     362          12 :   PetscCall(EPSDestroy(&powereps));
     363             :   /* restore context back to the old nonlinear solver */
     364          12 :   PetscCall(DMCopyDMSNES(newdm,dm));
     365          12 :   PetscCall(DMDestroy(&newdm));
     366          12 :   PetscFunctionReturn(PETSC_SUCCESS);
     367             : }
     368             : 
     369          45 : static PetscErrorCode EPSSolve_Power(EPS eps)
     370             : {
     371          45 :   EPS_POWER           *power = (EPS_POWER*)eps->data;
     372          45 :   PetscInt            k,ld;
     373          45 :   Vec                 v,y,e,Bx;
     374          45 :   Mat                 A;
     375          45 :   KSP                 ksp;
     376          45 :   PetscReal           relerr,norm,norm1,rt1,rt2,cs1;
     377          45 :   PetscScalar         theta,rho,delta,sigma,alpha2,beta1,sn1,*T,sign;
     378          45 :   PetscBool           breakdown;
     379          45 :   KSPConvergedReason  reason;
     380          45 :   SNESConvergedReason snesreason;
     381             : 
     382          45 :   PetscFunctionBegin;
     383          45 :   e = eps->work[0];
     384          45 :   y = eps->work[1];
     385          45 :   if (power->nonlinear) Bx = eps->work[2];
     386             :   else Bx = NULL;
     387             : 
     388          45 :   if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) PetscCall(STGetKSP(eps->st,&ksp));
     389          45 :   if (power->nonlinear) {
     390          31 :     PetscCall(PetscObjectCompose((PetscObject)power->snes,"eps",(PetscObject)eps));
     391             :     /* Compute an initial guess only when users do not provide one */
     392          31 :     if (power->update && !eps->nini) PetscCall(EPSPowerComputeInitialGuess_Update(eps));
     393          14 :   } else PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     394          45 :   if (!power->update) PetscCall(EPSGetStartVector(eps,0,NULL));
     395          45 :   if (power->nonlinear) {
     396          31 :     PetscCall(BVGetColumn(eps->V,0,&v));
     397          31 :     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          31 :     PetscCall(EPSPowerUpdateFunctionB(eps,v,Bx));
     410          31 :     PetscCall(BVRestoreColumn(eps->V,0,&v));
     411          31 :     if (power->formNorm) PetscCall((*power->formNorm)(power->snes,Bx,&norm,power->formNormCtx));
     412          23 :     else PetscCall(VecNorm(Bx,NORM_2,&norm));
     413          31 :     PetscCall(FirstNonzeroIdx(Bx,&power->idx,&power->p));
     414          31 :     PetscCall(Normalize(Bx,norm,power->idx,power->p,power->sign_normalization,NULL));
     415             :   }
     416             : 
     417          45 :   PetscCall(STGetShift(eps->st,&sigma));    /* original shift */
     418          45 :   rho = sigma;
     419             : 
     420       28654 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     421       28609 :     eps->its++;
     422       28609 :     k = eps->nconv;
     423             : 
     424             :     /* y = OP v */
     425       28609 :     PetscCall(BVGetColumn(eps->V,k,&v));
     426       28609 :     if (power->nonlinear) PetscCall(EPSPowerApply_SNES(eps,v,y));
     427       28410 :     else PetscCall(STApply(eps->st,v,y));
     428       28609 :     PetscCall(BVRestoreColumn(eps->V,k,&v));
     429             : 
     430             :     /* purge previously converged eigenvectors */
     431       28609 :     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         199 :       if (!power->update) {
     436         185 :         PetscCall(EPSPowerUpdateFunctionB(eps,y,Bx));
     437         185 :         if (power->formNorm) PetscCall((*power->formNorm)(power->snes,Bx,&norm,power->formNormCtx));
     438         115 :         else PetscCall(VecNorm(Bx,NORM_2,&norm));
     439         185 :         PetscCall(Normalize(Bx,norm,power->idx,power->p,power->sign_normalization,&sign));
     440             :       }
     441             :     } else {
     442       28410 :       PetscCall(DSGetArray(eps->ds,DS_MAT_A,&T));
     443       28410 :       PetscCall(BVSetActiveColumns(eps->V,0,k));
     444       28410 :       PetscCall(BVOrthogonalizeVec(eps->V,y,T+k*ld,&norm,NULL));
     445             :     }
     446             : 
     447             :     /* theta = (v,y)_B */
     448       28609 :     PetscCall(BVSetActiveColumns(eps->V,k,k+1));
     449       28609 :     PetscCall(BVDotVec(eps->V,y,&theta));
     450       28609 :     if (!power->nonlinear) {
     451       28410 :       T[k+k*ld] = theta;
     452       28410 :       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       28609 :     if (power->update) theta = eps->eigr[eps->nconv];
     459       28595 :     else if (power->nonlinear) theta = 1.0/(norm*sign); /* Eigenvalue: 1/|Bx| */
     460             : 
     461       28609 :     if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */
     462             : 
     463             :       /* approximate eigenvalue is the Rayleigh quotient */
     464       28575 :       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       28575 :       if (PetscUnlikely(power->update)) relerr = 0.;
     471             :       else {
     472             :         /* compute relative error as ||y-theta v||_2/|theta| */
     473       28561 :         PetscCall(VecCopy(y,e));
     474       28561 :         PetscCall(BVGetColumn(eps->V,k,&v));
     475       28561 :         PetscCall(VecAXPY(e,power->nonlinear?-1.0:-theta,v));
     476       28561 :         PetscCall(BVRestoreColumn(eps->V,k,&v));
     477       28561 :         PetscCall(VecNorm(e,NORM_2,&relerr));
     478       28561 :         if (PetscUnlikely(power->nonlinear)) relerr *= PetscAbsScalar(theta);
     479       28376 :         else relerr /= PetscAbsScalar(theta);
     480             :       }
     481             : 
     482             :     } else {  /* RQI */
     483             : 
     484             :       /* delta = ||y||_B */
     485          34 :       delta = norm;
     486             : 
     487             :       /* compute relative error */
     488          34 :       if (rho == 0.0) relerr = PETSC_MAX_REAL;
     489          34 :       else relerr = 1.0 / (norm*PetscAbsScalar(rho));
     490             : 
     491             :       /* approximate eigenvalue is the shift */
     492          34 :       eps->eigr[eps->nconv] = rho;
     493             : 
     494             :       /* compute new shift */
     495          34 :       if (relerr<eps->tol) {
     496           8 :         rho = sigma;  /* if converged, restore original shift */
     497           8 :         PetscCall(STSetShift(eps->st,rho));
     498             :       } else {
     499          26 :         rho = rho + PetscConj(theta)/(delta*delta);  /* Rayleigh quotient R(v) */
     500          26 :         if (power->shift_type == EPS_POWER_SHIFT_WILKINSON) {
     501             :           /* beta1 is the norm of the residual associated with R(v) */
     502           9 :           PetscCall(BVGetColumn(eps->V,k,&v));
     503           9 :           PetscCall(VecAXPY(v,-PetscConj(theta)/(delta*delta),y));
     504           9 :           PetscCall(BVRestoreColumn(eps->V,k,&v));
     505           9 :           PetscCall(BVScaleColumn(eps->V,k,1.0/delta));
     506           9 :           PetscCall(BVNormColumn(eps->V,k,NORM_2,&norm1));
     507           9 :           beta1 = norm1;
     508             : 
     509             :           /* alpha2 = (e'*A*e)/(beta1*beta1), where e is the residual */
     510           9 :           PetscCall(STGetMatrix(eps->st,0,&A));
     511           9 :           PetscCall(BVGetColumn(eps->V,k,&v));
     512           9 :           PetscCall(MatMult(A,v,e));
     513           9 :           PetscCall(VecDot(v,e,&alpha2));
     514           9 :           PetscCall(BVRestoreColumn(eps->V,k,&v));
     515           9 :           alpha2 = alpha2 / (beta1 * beta1);
     516             : 
     517             :           /* choose the eigenvalue of [rho beta1; beta1 alpha2] closest to rho */
     518           9 :           PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     519           9 :           PetscCallBLAS("LAPACKlaev2",LAPACKlaev2_(&rho,&beta1,&alpha2,&rt1,&rt2,&cs1,&sn1));
     520           9 :           PetscCall(PetscFPTrapPop());
     521           9 :           if (PetscAbsScalar(rt1-rho) < PetscAbsScalar(rt2-rho)) rho = rt1;
     522           3 :           else rho = rt2;
     523             :         }
     524             :         /* update operator according to new shift */
     525          26 :         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_FALSE));
     526          26 :         PetscCall(STSetShift(eps->st,rho));
     527          26 :         PetscCall(KSPGetConvergedReason(ksp,&reason));
     528          26 :         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          26 :         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_TRUE));
     536             :       }
     537             :     }
     538       28609 :     eps->errest[eps->nconv] = relerr;
     539             : 
     540             :     /* normalize */
     541       28609 :     if (!power->nonlinear) PetscCall(Normalize(y,norm,power->idx,power->p,power->sign_normalization,NULL));
     542       28609 :     PetscCall(BVInsertVec(eps->V,k,y));
     543             : 
     544       28609 :     if (PetscUnlikely(power->update)) {
     545          14 :       PetscCall(SNESGetConvergedReason(power->snes,&snesreason));
     546             :       /* For Newton eigensolver, we are ready to return once SNES converged. */
     547          14 :       if (snesreason>0) eps->nconv = 1;
     548       28595 :     } 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       28609 :     if (!power->update) PetscCall(EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
     561       28609 :     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       28609 :     if (PetscUnlikely(power->nonlinear && eps->reason>0)) eps->nconv = 1;
     568             :   }
     569             : 
     570          45 :   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          45 :   PetscFunctionReturn(PETSC_SUCCESS);
     576             : }
     577             : 
     578           3 : static PetscErrorCode EPSSolve_TS_Power(EPS eps)
     579             : {
     580           3 :   EPS_POWER          *power = (EPS_POWER*)eps->data;
     581           3 :   PetscInt           k,ld;
     582           3 :   Vec                v,w,y,e,z;
     583           3 :   KSP                ksp;
     584           3 :   PetscReal          relerr=1.0,relerrl,delta;
     585           3 :   PetscScalar        theta,rho,alpha,sigma;
     586           3 :   PetscBool          breakdown,breakdownl;
     587           3 :   KSPConvergedReason reason;
     588             : 
     589           3 :   PetscFunctionBegin;
     590           3 :   e = eps->work[0];
     591           3 :   v = eps->work[1];
     592           3 :   w = eps->work[2];
     593             : 
     594           3 :   if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) PetscCall(STGetKSP(eps->st,&ksp));
     595           3 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     596           3 :   PetscCall(EPSGetStartVector(eps,0,NULL));
     597           3 :   PetscCall(EPSGetLeftStartVector(eps,0,NULL));
     598           3 :   PetscCall(BVBiorthonormalizeColumn(eps->V,eps->W,0,NULL));
     599           3 :   PetscCall(BVCopyVec(eps->V,0,v));
     600           3 :   PetscCall(BVCopyVec(eps->W,0,w));
     601           3 :   PetscCall(STGetShift(eps->st,&sigma));    /* original shift */
     602           3 :   rho = sigma;
     603             : 
     604           3 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     605         394 :     eps->its++;
     606         394 :     k = eps->nconv;
     607             : 
     608             :     /* y = OP v, z = OP' w */
     609         394 :     PetscCall(BVGetColumn(eps->V,k,&y));
     610         394 :     PetscCall(STApply(eps->st,v,y));
     611         394 :     PetscCall(BVRestoreColumn(eps->V,k,&y));
     612         394 :     PetscCall(BVGetColumn(eps->W,k,&z));
     613         394 :     PetscCall(STApplyHermitianTranspose(eps->st,w,z));
     614         394 :     PetscCall(BVRestoreColumn(eps->W,k,&z));
     615             : 
     616             :     /* purge previously converged eigenvectors */
     617         394 :     PetscCall(BVBiorthogonalizeColumn(eps->V,eps->W,k));
     618             : 
     619             :     /* theta = (w,y)_B */
     620         394 :     PetscCall(BVSetActiveColumns(eps->V,k,k+1));
     621         394 :     PetscCall(BVDotVec(eps->V,w,&theta));
     622         394 :     theta = PetscConj(theta);
     623             : 
     624         394 :     if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */
     625             : 
     626             :       /* approximate eigenvalue is the Rayleigh quotient */
     627         382 :       eps->eigr[eps->nconv] = theta;
     628             : 
     629             :       /* compute relative errors as ||y-theta v||_2/|theta| and ||z-conj(theta) w||_2/|theta|*/
     630         382 :       PetscCall(BVCopyVec(eps->V,k,e));
     631         382 :       PetscCall(VecAXPY(e,-theta,v));
     632         382 :       PetscCall(VecNorm(e,NORM_2,&relerr));
     633         382 :       PetscCall(BVCopyVec(eps->W,k,e));
     634         382 :       PetscCall(VecAXPY(e,-PetscConj(theta),w));
     635         382 :       PetscCall(VecNorm(e,NORM_2,&relerrl));
     636         735 :       relerr = PetscMax(relerr,relerrl)/PetscAbsScalar(theta);
     637             :     }
     638             : 
     639             :     /* normalize */
     640         394 :     PetscCall(BVSetActiveColumns(eps->V,k,k+1));
     641         394 :     PetscCall(BVGetColumn(eps->W,k,&z));
     642         394 :     PetscCall(BVDotVec(eps->V,z,&alpha));
     643         394 :     PetscCall(BVRestoreColumn(eps->W,k,&z));
     644         394 :     delta = PetscSqrtReal(PetscAbsScalar(alpha));
     645         394 :     PetscCheck(delta!=0.0,PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Breakdown in two-sided Power/RQI");
     646         394 :     PetscCall(BVScaleColumn(eps->V,k,1.0/PetscConj(alpha/delta)));
     647         394 :     PetscCall(BVScaleColumn(eps->W,k,1.0/delta));
     648         394 :     PetscCall(BVCopyVec(eps->V,k,v));
     649         394 :     PetscCall(BVCopyVec(eps->W,k,w));
     650             : 
     651         394 :     if (power->shift_type == EPS_POWER_SHIFT_RAYLEIGH) { /* RQI */
     652             : 
     653             :       /* compute relative error */
     654          12 :       if (rho == 0.0) relerr = PETSC_MAX_REAL;
     655          12 :       else relerr = 1.0 / PetscAbsScalar(delta*rho);
     656             : 
     657             :       /* approximate eigenvalue is the shift */
     658          12 :       eps->eigr[eps->nconv] = rho;
     659             : 
     660             :       /* compute new shift */
     661          12 :       if (relerr<eps->tol) {
     662           2 :         rho = sigma;  /* if converged, restore original shift */
     663           2 :         PetscCall(STSetShift(eps->st,rho));
     664             :       } else {
     665          10 :         rho = rho + PetscConj(theta)/(delta*delta);  /* Rayleigh quotient R(v) */
     666             :         /* update operator according to new shift */
     667          10 :         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_FALSE));
     668          10 :         PetscCall(STSetShift(eps->st,rho));
     669          10 :         PetscCall(KSPGetConvergedReason(ksp,&reason));
     670          10 :         if (reason) {
     671           0 :           PetscCall(PetscInfo(eps,"Factorization failed, repeat with a perturbed shift\n"));
     672           0 :           rho *= 1+10*PETSC_MACHINE_EPSILON;
     673           0 :           PetscCall(STSetShift(eps->st,rho));
     674           0 :           PetscCall(KSPGetConvergedReason(ksp,&reason));
     675           0 :           PetscCheck(!reason,PetscObjectComm((PetscObject)ksp),PETSC_ERR_CONV_FAILED,"Second factorization failed");
     676             :         }
     677          10 :         PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_TRUE));
     678             :       }
     679             :     }
     680         394 :     eps->errest[eps->nconv] = relerr;
     681             : 
     682             :     /* if relerr<tol, accept eigenpair */
     683         394 :     if (relerr<eps->tol) {
     684           8 :       eps->nconv = eps->nconv + 1;
     685           8 :       if (eps->nconv<eps->nev) {
     686           5 :         PetscCall(EPSGetStartVector(eps,eps->nconv,&breakdown));
     687           5 :         PetscCall(EPSGetLeftStartVector(eps,eps->nconv,&breakdownl));
     688           5 :         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           5 :         PetscCall(BVBiorthonormalizeColumn(eps->V,eps->W,eps->nconv,NULL));
     694             :       }
     695             :     }
     696         394 :     PetscCall(EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
     697         397 :     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx));
     698             :   }
     699             : 
     700           3 :   PetscCall(DSSetDimensions(eps->ds,eps->nconv,0,0));
     701           3 :   PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
     702           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     703             : }
     704             : 
     705       29003 : static PetscErrorCode EPSStopping_Power(EPS eps,PetscInt its,PetscInt max_it,PetscInt nconv,PetscInt nev,EPSConvergedReason *reason,void *ctx)
     706             : {
     707       29003 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     708       29003 :   SNESConvergedReason snesreason;
     709             : 
     710       29003 :   PetscFunctionBegin;
     711       29003 :   if (PetscUnlikely(power->update)) {
     712          14 :     PetscCall(SNESGetConvergedReason(power->snes,&snesreason));
     713          14 :     if (snesreason < 0) {
     714           0 :       *reason = EPS_DIVERGED_BREAKDOWN;
     715           0 :       PetscFunctionReturn(PETSC_SUCCESS);
     716             :     }
     717             :   }
     718       29003 :   PetscCall(EPSStoppingBasic(eps,its,max_it,nconv,nev,reason,ctx));
     719       29003 :   PetscFunctionReturn(PETSC_SUCCESS);
     720             : }
     721             : 
     722          17 : static PetscErrorCode EPSBackTransform_Power(EPS eps)
     723             : {
     724          17 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
     725             : 
     726          17 :   PetscFunctionBegin;
     727          17 :   if (power->nonlinear) eps->eigr[0] = 1.0/eps->eigr[0];
     728          17 :   else if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) PetscCall(EPSBackTransform_Default(eps));
     729          17 :   PetscFunctionReturn(PETSC_SUCCESS);
     730             : }
     731             : 
     732          44 : static PetscErrorCode EPSSetFromOptions_Power(EPS eps,PetscOptionItems *PetscOptionsObject)
     733             : {
     734          44 :   EPS_POWER         *power = (EPS_POWER*)eps->data;
     735          44 :   PetscBool         flg,val;
     736          44 :   EPSPowerShiftType shift;
     737             : 
     738          44 :   PetscFunctionBegin;
     739          44 :   PetscOptionsHeadBegin(PetscOptionsObject,"EPS Power Options");
     740             : 
     741          44 :     PetscCall(PetscOptionsEnum("-eps_power_shift_type","Shift type","EPSPowerSetShiftType",EPSPowerShiftTypes,(PetscEnum)power->shift_type,(PetscEnum*)&shift,&flg));
     742          44 :     if (flg) PetscCall(EPSPowerSetShiftType(eps,shift));
     743             : 
     744          44 :     PetscCall(PetscOptionsBool("-eps_power_nonlinear","Use nonlinear inverse iteration","EPSPowerSetNonlinear",power->nonlinear,&val,&flg));
     745          44 :     if (flg) PetscCall(EPSPowerSetNonlinear(eps,val));
     746             : 
     747          44 :     PetscCall(PetscOptionsBool("-eps_power_update","Update residual monolithically","EPSPowerSetUpdate",power->update,&val,&flg));
     748          44 :     if (flg) PetscCall(EPSPowerSetUpdate(eps,val));
     749             : 
     750          44 :     PetscCall(PetscOptionsBool("-eps_power_sign_normalization","Normalize Bx with sign of first nonzero entry","EPSPowerSetSignNormalization",power->sign_normalization,&power->sign_normalization,&flg));
     751             : 
     752          44 :   PetscOptionsHeadEnd();
     753          44 :   PetscFunctionReturn(PETSC_SUCCESS);
     754             : }
     755             : 
     756           7 : static PetscErrorCode EPSPowerSetShiftType_Power(EPS eps,EPSPowerShiftType shift)
     757             : {
     758           7 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     759             : 
     760           7 :   PetscFunctionBegin;
     761           7 :   switch (shift) {
     762           7 :     case EPS_POWER_SHIFT_CONSTANT:
     763             :     case EPS_POWER_SHIFT_RAYLEIGH:
     764             :     case EPS_POWER_SHIFT_WILKINSON:
     765           7 :       if (power->shift_type != shift) {
     766           4 :         power->shift_type = shift;
     767           4 :         eps->state = EPS_STATE_INITIAL;
     768             :       }
     769           7 :       break;
     770           0 :     default:
     771           0 :       SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid shift type");
     772             :   }
     773           7 :   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           7 : PetscErrorCode EPSPowerSetShiftType(EPS eps,EPSPowerShiftType shift)
     805             : {
     806           7 :   PetscFunctionBegin;
     807           7 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     808          21 :   PetscValidLogicalCollectiveEnum(eps,shift,2);
     809           7 :   PetscTryMethod(eps,"EPSPowerSetShiftType_C",(EPS,EPSPowerShiftType),(eps,shift));
     810           7 :   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          29 : static PetscErrorCode EPSPowerSetNonlinear_Power(EPS eps,PetscBool nonlinear)
     848             : {
     849          29 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     850             : 
     851          29 :   PetscFunctionBegin;
     852          29 :   if (power->nonlinear != nonlinear) {
     853          29 :     power->nonlinear = nonlinear;
     854          29 :     eps->useds = PetscNot(nonlinear);
     855          29 :     eps->ops->setupsort = nonlinear? NULL: EPSSetUpSort_Default;
     856          29 :     eps->state = EPS_STATE_INITIAL;
     857             :   }
     858          29 :   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          29 : PetscErrorCode EPSPowerSetNonlinear(EPS eps,PetscBool nonlinear)
     892             : {
     893          29 :   PetscFunctionBegin;
     894          29 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     895          87 :   PetscValidLogicalCollectiveBool(eps,nonlinear,2);
     896          29 :   PetscTryMethod(eps,"EPSPowerSetNonlinear_C",(EPS,PetscBool),(eps,nonlinear));
     897          29 :   PetscFunctionReturn(PETSC_SUCCESS);
     898             : }
     899             : 
     900          17 : static PetscErrorCode EPSPowerGetNonlinear_Power(EPS eps,PetscBool *nonlinear)
     901             : {
     902          17 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     903             : 
     904          17 :   PetscFunctionBegin;
     905          17 :   *nonlinear = power->nonlinear;
     906          17 :   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          17 : PetscErrorCode EPSPowerGetNonlinear(EPS eps,PetscBool *nonlinear)
     925             : {
     926          17 :   PetscFunctionBegin;
     927          17 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     928          17 :   PetscAssertPointer(nonlinear,2);
     929          17 :   PetscUseMethod(eps,"EPSPowerGetNonlinear_C",(EPS,PetscBool*),(eps,nonlinear));
     930          17 :   PetscFunctionReturn(PETSC_SUCCESS);
     931             : }
     932             : 
     933          12 : static PetscErrorCode EPSPowerSetUpdate_Power(EPS eps,PetscBool update)
     934             : {
     935          12 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     936             : 
     937          12 :   PetscFunctionBegin;
     938          12 :   PetscCheck(power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_INCOMP,"This option does not make sense for linear problems");
     939          12 :   power->update = update;
     940          12 :   eps->state = EPS_STATE_INITIAL;
     941          12 :   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          12 : PetscErrorCode EPSPowerSetUpdate(EPS eps,PetscBool update)
     962             : {
     963          12 :   PetscFunctionBegin;
     964          12 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     965          36 :   PetscValidLogicalCollectiveBool(eps,update,2);
     966          12 :   PetscTryMethod(eps,"EPSPowerSetUpdate_C",(EPS,PetscBool),(eps,update));
     967          12 :   PetscFunctionReturn(PETSC_SUCCESS);
     968             : }
     969             : 
     970          17 : static PetscErrorCode EPSPowerGetUpdate_Power(EPS eps,PetscBool *update)
     971             : {
     972          17 :   EPS_POWER *power = (EPS_POWER*)eps->data;
     973             : 
     974          17 :   PetscFunctionBegin;
     975          17 :   *update = power->update;
     976          17 :   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          17 : PetscErrorCode EPSPowerGetUpdate(EPS eps,PetscBool *update)
     996             : {
     997          17 :   PetscFunctionBegin;
     998          17 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     999          17 :   PetscAssertPointer(update,2);
    1000          17 :   PetscUseMethod(eps,"EPSPowerGetUpdate_C",(EPS,PetscBool*),(eps,update));
    1001          17 :   PetscFunctionReturn(PETSC_SUCCESS);
    1002             : }
    1003             : 
    1004          29 : static PetscErrorCode EPSPowerSetSignNormalization_Power(EPS eps,PetscBool sign_normalization)
    1005             : {
    1006          29 :   EPS_POWER *power = (EPS_POWER*)eps->data;
    1007             : 
    1008          29 :   PetscFunctionBegin;
    1009          29 :   power->sign_normalization = sign_normalization;
    1010          29 :   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          29 : PetscErrorCode EPSPowerSetSignNormalization(EPS eps,PetscBool sign_normalization)
    1034             : {
    1035          29 :   PetscFunctionBegin;
    1036          29 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1037          87 :   PetscValidLogicalCollectiveBool(eps,sign_normalization,2);
    1038          29 :   PetscTryMethod(eps,"EPSPowerSetSignNormalization_C",(EPS,PetscBool),(eps,sign_normalization));
    1039          29 :   PetscFunctionReturn(PETSC_SUCCESS);
    1040             : }
    1041             : 
    1042          12 : static PetscErrorCode EPSPowerGetSignNormalization_Power(EPS eps,PetscBool *sign_normalization)
    1043             : {
    1044          12 :   EPS_POWER *power = (EPS_POWER*)eps->data;
    1045             : 
    1046          12 :   PetscFunctionBegin;
    1047          12 :   *sign_normalization = power->sign_normalization;
    1048          12 :   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          12 : PetscErrorCode EPSPowerGetSignNormalization(EPS eps,PetscBool *sign_normalization)
    1070             : {
    1071          12 :   PetscFunctionBegin;
    1072          12 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1073          12 :   PetscAssertPointer(sign_normalization,2);
    1074          12 :   PetscUseMethod(eps,"EPSPowerGetSignNormalization_C",(EPS,PetscBool*),(eps,sign_normalization));
    1075          12 :   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          41 : static PetscErrorCode EPSPowerGetSNES_Power(EPS eps,SNES *snes)
    1115             : {
    1116          41 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1117             : 
    1118          41 :   PetscFunctionBegin;
    1119          41 :   if (!power->snes) {
    1120          29 :     PetscCall(SNESCreate(PetscObjectComm((PetscObject)eps),&power->snes));
    1121          29 :     PetscCall(PetscObjectIncrementTabLevel((PetscObject)power->snes,(PetscObject)eps,1));
    1122          29 :     PetscCall(SNESSetOptionsPrefix(power->snes,((PetscObject)eps)->prefix));
    1123          29 :     PetscCall(SNESAppendOptionsPrefix(power->snes,"eps_power_"));
    1124          29 :     PetscCall(PetscObjectSetOptions((PetscObject)power->snes,((PetscObject)eps)->options));
    1125             :   }
    1126          41 :   *snes = power->snes;
    1127          41 :   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          41 : PetscErrorCode EPSPowerGetSNES(EPS eps,SNES *snes)
    1147             : {
    1148          41 :   PetscFunctionBegin;
    1149          41 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
    1150          41 :   PetscAssertPointer(snes,2);
    1151          41 :   PetscUseMethod(eps,"EPSPowerGetSNES_C",(EPS,SNES*),(eps,snes));
    1152          41 :   PetscFunctionReturn(PETSC_SUCCESS);
    1153             : }
    1154             : 
    1155          45 : static PetscErrorCode EPSReset_Power(EPS eps)
    1156             : {
    1157          45 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1158             : 
    1159          45 :   PetscFunctionBegin;
    1160          45 :   if (power->snes) PetscCall(SNESReset(power->snes));
    1161          45 :   PetscFunctionReturn(PETSC_SUCCESS);
    1162             : }
    1163             : 
    1164          44 : static PetscErrorCode EPSDestroy_Power(EPS eps)
    1165             : {
    1166          44 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1167             : 
    1168          44 :   PetscFunctionBegin;
    1169          44 :   if (power->nonlinear) PetscCall(SNESDestroy(&power->snes));
    1170          44 :   PetscCall(PetscFree(eps->data));
    1171          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",NULL));
    1172          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",NULL));
    1173          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetNonlinear_C",NULL));
    1174          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetNonlinear_C",NULL));
    1175          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetUpdate_C",NULL));
    1176          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetUpdate_C",NULL));
    1177          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSignNormalization_C",NULL));
    1178          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSignNormalization_C",NULL));
    1179          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSNES_C",NULL));
    1180          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSNES_C",NULL));
    1181          44 :   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          36 : static PetscErrorCode EPSComputeVectors_Power(EPS eps)
    1207             : {
    1208          36 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1209             : 
    1210          36 :   PetscFunctionBegin;
    1211          36 :   if (eps->twosided) {
    1212           3 :     PetscCall(EPSComputeVectors_Twosided(eps));
    1213           3 :     PetscCall(BVNormalize(eps->V,NULL));
    1214           3 :     PetscCall(BVNormalize(eps->W,NULL));
    1215          33 :   } else if (!power->nonlinear) PetscCall(EPSComputeVectors_Schur(eps));
    1216          36 :   PetscFunctionReturn(PETSC_SUCCESS);
    1217             : }
    1218             : 
    1219          92 : static PetscErrorCode EPSSetDefaultST_Power(EPS eps)
    1220             : {
    1221          92 :   EPS_POWER      *power = (EPS_POWER*)eps->data;
    1222          92 :   KSP            ksp;
    1223          92 :   PC             pc;
    1224             : 
    1225          92 :   PetscFunctionBegin;
    1226          92 :   if (power->nonlinear) {
    1227          60 :     eps->categ=EPS_CATEGORY_PRECOND;
    1228          60 :     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          60 :     PetscCall(STSetType(eps->st,STPRECOND));
    1233          60 :     PetscCall(KSPGetPC(ksp,&pc));
    1234          60 :     PetscCall(PCSetType(pc,PCNONE));
    1235             :   }
    1236          92 :   PetscFunctionReturn(PETSC_SUCCESS);
    1237             : }
    1238             : 
    1239          44 : SLEPC_EXTERN PetscErrorCode EPSCreate_Power(EPS eps)
    1240             : {
    1241          44 :   EPS_POWER      *ctx;
    1242             : 
    1243          44 :   PetscFunctionBegin;
    1244          44 :   PetscCall(PetscNew(&ctx));
    1245          44 :   eps->data = (void*)ctx;
    1246             : 
    1247          44 :   eps->useds = PETSC_TRUE;
    1248          44 :   eps->categ = EPS_CATEGORY_OTHER;
    1249             : 
    1250          44 :   eps->ops->setup          = EPSSetUp_Power;
    1251          44 :   eps->ops->setupsort      = EPSSetUpSort_Default;
    1252          44 :   eps->ops->setfromoptions = EPSSetFromOptions_Power;
    1253          44 :   eps->ops->reset          = EPSReset_Power;
    1254          44 :   eps->ops->destroy        = EPSDestroy_Power;
    1255          44 :   eps->ops->view           = EPSView_Power;
    1256          44 :   eps->ops->backtransform  = EPSBackTransform_Power;
    1257          44 :   eps->ops->computevectors = EPSComputeVectors_Power;
    1258          44 :   eps->ops->setdefaultst   = EPSSetDefaultST_Power;
    1259          44 :   eps->stopping            = EPSStopping_Power;
    1260          44 :   ctx->sign_normalization  = PETSC_TRUE;
    1261             : 
    1262          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",EPSPowerSetShiftType_Power));
    1263          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",EPSPowerGetShiftType_Power));
    1264          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetNonlinear_C",EPSPowerSetNonlinear_Power));
    1265          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetNonlinear_C",EPSPowerGetNonlinear_Power));
    1266          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetUpdate_C",EPSPowerSetUpdate_Power));
    1267          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetUpdate_C",EPSPowerGetUpdate_Power));
    1268          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSignNormalization_C",EPSPowerSetSignNormalization_Power));
    1269          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSignNormalization_C",EPSPowerGetSignNormalization_Power));
    1270          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSNES_C",EPSPowerSetSNES_Power));
    1271          44 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSNES_C",EPSPowerGetSNES_Power));
    1272          44 :   PetscFunctionReturn(PETSC_SUCCESS);
    1273             : }

Generated by: LCOV version 1.14