Actual source code: slp.c
slepc-3.5.2 2014-10-10
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: }