Actual source code: slp.c

slepc-3.5.2 2014-10-10
Report Typos and Errors
  1: /*

  3:    SLEPc nonlinear eigensolver: "slp"

  5:    Method: Succesive linear problems

  7:    Algorithm:

  9:        Newton-type iteration based on first order Taylor approximation.

 11:    References:

 13:        [1] A. Ruhe, "Algorithms for the nonlinear eigenvalue problem", SIAM J.
 14:            Numer. Anal. 10(4):674-689, 1973.

 16:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 17:    SLEPc - Scalable Library for Eigenvalue Problem Computations
 18:    Copyright (c) 2002-2014, Universitat Politecnica de Valencia, Spain

 20:    This file is part of SLEPc.

 22:    SLEPc is free software: you can redistribute it and/or modify it under  the
 23:    terms of version 3 of the GNU Lesser General Public License as published by
 24:    the Free Software Foundation.

 26:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
 27:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
 28:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
 29:    more details.

 31:    You  should have received a copy of the GNU Lesser General  Public  License
 32:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
 33:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 34: */

 36: #include <slepc-private/nepimpl.h>         /*I "slepcnep.h" I*/

 38: typedef struct {
 39:   EPS       eps;             /* linear eigensolver for T*z = mu*Tp*z */
 40: } NEP_SLP;

 44: PetscErrorCode NEPSetUp_SLP(NEP nep)
 45: {
 47:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;
 48:   ST             st;
 49:   PetscBool      istrivial;

 52:   if (nep->ncv) { /* ncv set */
 53:     if (nep->ncv<nep->nev) SETERRQ(PetscObjectComm((PetscObject)nep),1,"The value of ncv must be at least nev");
 54:   } else if (nep->mpd) { /* mpd set */
 55:     nep->ncv = PetscMin(nep->n,nep->nev+nep->mpd);
 56:   } else { /* neither set: defaults depend on nev being small or large */
 57:     if (nep->nev<500) nep->ncv = PetscMin(nep->n,PetscMax(2*nep->nev,nep->nev+15));
 58:     else {
 59:       nep->mpd = 500;
 60:       nep->ncv = PetscMin(nep->n,nep->nev+nep->mpd);
 61:     }
 62:   }
 63:   if (!nep->mpd) nep->mpd = nep->ncv;
 64:   if (nep->ncv>nep->nev+nep->mpd) SETERRQ(PetscObjectComm((PetscObject)nep),1,"The value of ncv must not be larger than nev+mpd");
 65:   if (nep->nev>1) { PetscInfo(nep,"Warning: requested more than one eigenpair but SLP can only compute one\n"); }
 66:   if (!nep->max_it) nep->max_it = PetscMax(5000,2*nep->n/nep->ncv);
 67:   if (!nep->max_funcs) nep->max_funcs = nep->max_it;

 69:   RGIsTrivial(nep->rg,&istrivial);
 70:   if (!istrivial) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"This solver does not support region filtering");

 72:   if (!ctx->eps) { NEPSLPGetEPS(nep,&ctx->eps); }
 73:   EPSSetWhichEigenpairs(ctx->eps,EPS_TARGET_MAGNITUDE);
 74:   EPSSetTarget(ctx->eps,0.0);
 75:   EPSGetST(ctx->eps,&st);
 76:   STSetType(st,STSINVERT);
 77:   EPSSetDimensions(ctx->eps,1,nep->ncv?nep->ncv:PETSC_DEFAULT,nep->mpd?nep->mpd:PETSC_DEFAULT);
 78:   EPSSetTolerances(ctx->eps,nep->rtol==PETSC_DEFAULT?SLEPC_DEFAULT_TOL/10.0:nep->rtol/10.0,nep->max_it?nep->max_it:PETSC_DEFAULT);

 80:   NEPAllocateSolution(nep,0);
 81:   NEPSetWorkVecs(nep,1);
 82:   return(0);
 83: }

 87: PetscErrorCode NEPSolve_SLP(NEP nep)
 88: {
 90:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;
 91:   Mat            T=nep->function,Tp=nep->jacobian;
 92:   Vec            u,r=nep->work[0];
 93:   PetscScalar    lambda,mu,im;
 94:   PetscReal      relerr;
 95:   PetscInt       nconv;

 98:   /* get initial approximation of eigenvalue and eigenvector */
 99:   NEPGetDefaultShift(nep,&lambda);
100:   if (!nep->nini) {
101:     BVSetRandomColumn(nep->V,0,nep->rand);
102:   }
103:   BVGetColumn(nep->V,0,&u);

105:   /* Restart loop */
106:   while (nep->reason == NEP_CONVERGED_ITERATING) {
107:     nep->its++;

109:     /* evaluate T(lambda) and T'(lambda) */
110:     NEPComputeFunction(nep,lambda,T,T);
111:     NEPComputeJacobian(nep,lambda,Tp);

113:     /* form residual,  r = T(lambda)*u (used in convergence test only) */
114:     MatMult(T,u,r);

116:     /* convergence test */
117:     VecNorm(r,NORM_2,&relerr);
118:     nep->errest[nep->nconv] = relerr;
119:     nep->eigr[nep->nconv] = lambda;
120:     if (relerr<=nep->rtol) {
121:       nep->nconv = nep->nconv + 1;
122:       nep->reason = NEP_CONVERGED_FNORM_RELATIVE;
123:     }
124:     NEPMonitor(nep,nep->its,nep->nconv,nep->eigr,nep->errest,1);

126:     if (!nep->nconv) {
127:       /* compute eigenvalue correction mu and eigenvector approximation u */
128:       EPSSetOperators(ctx->eps,T,Tp);
129:       EPSSetInitialSpace(ctx->eps,1,&u);
130:       EPSSolve(ctx->eps);
131:       EPSGetConverged(ctx->eps,&nconv);
132:       if (!nconv) {
133:         PetscInfo1(nep,"iter=%D, inner iteration failed, stopping solve\n",nep->its);
134:         nep->reason = NEP_DIVERGED_LINEAR_SOLVE;
135:         break;
136:       }
137:       EPSGetEigenpair(ctx->eps,0,&mu,&im,u,NULL);
138:       if (PetscAbsScalar(im)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)nep),1,"Complex eigenvalue approximation - not implemented in real scalars");

140:       /* correct eigenvalue */
141:       lambda = lambda - mu;
142:     }
143:     if (nep->its >= nep->max_it) nep->reason = NEP_DIVERGED_MAX_IT;
144:   }
145:   BVRestoreColumn(nep->V,0,&u);
146:   return(0);
147: }

151: PetscErrorCode NEPSetFromOptions_SLP(NEP nep)
152: {
154:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

157:   if (!ctx->eps) { NEPSLPGetEPS(nep,&ctx->eps); }
158:   EPSSetFromOptions(ctx->eps);
159:   return(0);
160: }

164: static PetscErrorCode NEPSLPSetEPS_SLP(NEP nep,EPS eps)
165: {
167:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

170:   PetscObjectReference((PetscObject)eps);
171:   EPSDestroy(&ctx->eps);
172:   ctx->eps = eps;
173:   PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->eps);
174:   nep->state = NEP_STATE_INITIAL;
175:   return(0);
176: }

180: /*@
181:    NEPSLPSetEPS - Associate a linear eigensolver object (EPS) to the
182:    nonlinear eigenvalue solver.

184:    Collective on NEP

186:    Input Parameters:
187: +  nep - nonlinear eigenvalue solver
188: -  eps - the eigensolver object

190:    Level: advanced

192: .seealso: NEPSLPGetEPS()
193: @*/
194: PetscErrorCode NEPSLPSetEPS(NEP nep,EPS eps)
195: {

202:   PetscTryMethod(nep,"NEPSLPSetEPS_C",(NEP,EPS),(nep,eps));
203:   return(0);
204: }

208: static PetscErrorCode NEPSLPGetEPS_SLP(NEP nep,EPS *eps)
209: {
211:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;
212:   ST             st;

215:   if (!ctx->eps) {
216:     EPSCreate(PetscObjectComm((PetscObject)nep),&ctx->eps);
217:     EPSSetOptionsPrefix(ctx->eps,((PetscObject)nep)->prefix);
218:     EPSAppendOptionsPrefix(ctx->eps,"nep_");
219:     EPSGetST(ctx->eps,&st);
220:     STSetOptionsPrefix(st,((PetscObject)ctx->eps)->prefix);
221:     PetscObjectIncrementTabLevel((PetscObject)ctx->eps,(PetscObject)nep,1);
222:     PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->eps);
223:   }
224:   *eps = ctx->eps;
225:   return(0);
226: }

230: /*@
231:    NEPSLPGetEPS - Retrieve the linear eigensolver object (EPS) associated
232:    to the nonlinear eigenvalue solver.

234:    Not Collective

236:    Input Parameter:
237: .  nep - nonlinear eigenvalue solver

239:    Output Parameter:
240: .  eps - the eigensolver object

242:    Level: advanced

244: .seealso: NEPSLPSetEPS()
245: @*/
246: PetscErrorCode NEPSLPGetEPS(NEP nep,EPS *eps)
247: {

253:   PetscTryMethod(nep,"NEPSLPGetEPS_C",(NEP,EPS*),(nep,eps));
254:   return(0);
255: }

259: PetscErrorCode NEPView_SLP(NEP nep,PetscViewer viewer)
260: {
262:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

265:   if (!ctx->eps) { NEPSLPGetEPS(nep,&ctx->eps); }
266:   PetscViewerASCIIPushTab(viewer);
267:   EPSView(ctx->eps,viewer);
268:   PetscViewerASCIIPopTab(viewer);
269:   return(0);
270: }

274: PetscErrorCode NEPReset_SLP(NEP nep)
275: {
277:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

280:   if (!ctx->eps) { EPSReset(ctx->eps); }
281:   return(0);
282: }

286: PetscErrorCode NEPDestroy_SLP(NEP nep)
287: {
289:   NEP_SLP        *ctx = (NEP_SLP*)nep->data;

292:   EPSDestroy(&ctx->eps);
293:   PetscFree(nep->data);
294:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPSetEPS_C",NULL);
295:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPGetEPS_C",NULL);
296:   return(0);
297: }

301: PETSC_EXTERN PetscErrorCode NEPCreate_SLP(NEP nep)
302: {
304:   NEP_SLP        *ctx;

307:   PetscNewLog(nep,&ctx);
308:   nep->data = (void*)ctx;

310:   nep->ops->solve          = NEPSolve_SLP;
311:   nep->ops->setup          = NEPSetUp_SLP;
312:   nep->ops->setfromoptions = NEPSetFromOptions_SLP;
313:   nep->ops->reset          = NEPReset_SLP;
314:   nep->ops->destroy        = NEPDestroy_SLP;
315:   nep->ops->view           = NEPView_SLP;
316:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPSetEPS_C",NEPSLPSetEPS_SLP);
317:   PetscObjectComposeFunction((PetscObject)nep,"NEPSLPGetEPS_C",NEPSLPGetEPS_SLP);
318:   return(0);
319: }