Actual source code: interpol.c
slepc-3.6.3 2016-03-29
1: /*
3: SLEPc nonlinear eigensolver: "interpol"
5: Method: Polynomial interpolation
7: Algorithm:
9: Uses a PEP object to solve the interpolated NEP. Currently supports
10: only Chebyshev interpolation on an interval.
12: References:
14: [1] C. Effenberger and D. Kresser, "Chebyshev interpolation for
15: nonlinear eigenvalue problems", BIT 52:933-951, 2012.
17: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
18: SLEPc - Scalable Library for Eigenvalue Problem Computations
19: Copyright (c) 2002-2015, Universitat Politecnica de Valencia, Spain
21: This file is part of SLEPc.
23: SLEPc is free software: you can redistribute it and/or modify it under the
24: terms of version 3 of the GNU Lesser General Public License as published by
25: the Free Software Foundation.
27: SLEPc is distributed in the hope that it will be useful, but WITHOUT ANY
28: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
29: FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
30: more details.
32: You should have received a copy of the GNU Lesser General Public License
33: along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
34: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35: */
37: #include <slepc/private/nepimpl.h> /*I "slepcnep.h" I*/
38: #include <slepc/private/pepimpl.h>
40: typedef struct {
41: PEP pep;
42: PetscInt deg;
43: } NEP_INTERPOL;
47: PetscErrorCode NEPSetUp_Interpol(NEP nep)
48: {
50: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
51: ST st;
52: RG rg;
53: PetscReal a,b,c,d,s,tol;
54: PetscScalar zero=0.0;
55: PetscBool flg,istrivial;
56: PetscInt its,in;
59: if (nep->ncv) { /* ncv set */
60: if (nep->ncv<nep->nev) SETERRQ(PetscObjectComm((PetscObject)nep),1,"The value of ncv must be at least nev");
61: } else if (nep->mpd) { /* mpd set */
62: nep->ncv = PetscMin(nep->n,nep->nev+nep->mpd);
63: } else { /* neither set: defaults depend on nev being small or large */
64: if (nep->nev<500) nep->ncv = PetscMin(nep->n,PetscMax(2*nep->nev,nep->nev+15));
65: else {
66: nep->mpd = 500;
67: nep->ncv = PetscMin(nep->n,nep->nev+nep->mpd);
68: }
69: }
70: if (!nep->mpd) nep->mpd = nep->ncv;
71: if (nep->ncv>nep->nev+nep->mpd) SETERRQ(PetscObjectComm((PetscObject)nep),1,"The value of ncv must not be larger than nev+mpd");
72: if (!nep->max_it) nep->max_it = PetscMax(5000,2*nep->n/nep->ncv);
73: if (!nep->max_funcs) nep->max_funcs = nep->max_it;
74: if (!nep->split) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"NEPINTERPOL only available for split operator");
76: /* transfer PEP options */
77: if (!ctx->pep) { NEPInterpolGetPEP(nep,&ctx->pep); }
78: PEPSetBV(ctx->pep,nep->V);
79: PEPSetBasis(ctx->pep,PEP_BASIS_CHEBYSHEV1);
80: PEPSetWhichEigenpairs(ctx->pep,PEP_TARGET_MAGNITUDE);
81: PEPGetST(ctx->pep,&st);
82: STSetType(st,STSINVERT);
83: PEPSetDimensions(ctx->pep,nep->nev,nep->ncv?nep->ncv:PETSC_DEFAULT,nep->mpd?nep->mpd:PETSC_DEFAULT);
84: tol=ctx->pep->tol;
85: if (tol==PETSC_DEFAULT) tol = (nep->rtol==PETSC_DEFAULT)?SLEPC_DEFAULT_TOL/10.0:nep->rtol/10.0;
86: its=ctx->pep->max_it;
87: if (!its) its = nep->max_it?nep->max_it:PETSC_DEFAULT;
88: PEPSetTolerances(ctx->pep,tol,its);
90: /* transfer region options */
91: RGIsTrivial(nep->rg,&istrivial);
92: if (istrivial) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"NEPINTERPOL requires a nontrivial region");
93: PetscObjectTypeCompare((PetscObject)nep->rg,RGINTERVAL,&flg);
94: if (!flg) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Only implemented for interval regions");
95: RGIntervalGetEndpoints(nep->rg,&a,&b,&c,&d);
96: if (a<=-PETSC_MAX_REAL || b>=PETSC_MAX_REAL) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Only implemented for bounded intervals");
97: PEPGetRG(ctx->pep,&rg);
98: RGSetType(rg,RGINTERVAL);
99: if (a==b) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Only implemented for intervals on the real axis");
100: s = 2.0/(b-a);
101: c = (c==0)? -PETSC_MAX_REAL: c*s;
102: d = (d==0)? PETSC_MAX_REAL: d*s;
103: RGIntervalSetEndpoints(rg,-1.0,1.0,c,d);
104: RGCheckInside(nep->rg,1,&nep->target,&zero,&in);
105: if (in<0) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"The target is not inside the target set");
106: PEPSetTarget(ctx->pep,(nep->target-(a+b)/2)*s);
108: NEPAllocateSolution(nep,0);
109: return(0);
110: }
114: /*
115: Input:
116: d, number of nodes to compute
117: a,b, interval extrems
118: Output:
119: *x, array containing the d Chebyshev nodes of the interval [a,b]
120: *dct2, coefficients to compute a discrete cosine transformation (DCT-II)
121: */
122: static PetscErrorCode ChebyshevNodes(PetscInt d,PetscReal a,PetscReal b,PetscScalar *x,PetscReal *dct2)
123: {
124: PetscInt j,i;
125: PetscReal t;
128: for (j=0;j<d+1;j++) {
129: t = ((2*j+1)*PETSC_PI)/(2*(d+1));
130: x[j] = (a+b)/2.0+((b-a)/2.0)*PetscCosReal(t);
131: for (i=0;i<d+1;i++) dct2[j*(d+1)+i] = PetscCosReal(i*t);
132: }
133: return(0);
134: }
138: PetscErrorCode NEPSolve_Interpol(NEP nep)
139: {
141: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
142: Mat *A; /*T=nep->function,Tp=nep->jacobian;*/
143: PetscScalar *x,*fx,t;
144: PetscReal *cs,a,b,s;
145: PetscInt i,j,k,deg=ctx->deg;
148: PetscMalloc4(deg+1,&A,(deg+1)*(deg+1),&cs,deg+1,&x,(deg+1)*nep->nt,&fx);
149: RGIntervalGetEndpoints(nep->rg,&a,&b,NULL,NULL);
150: ChebyshevNodes(deg,a,b,x,cs);
151: for (j=0;j<nep->nt;j++) {
152: for (i=0;i<=deg;i++) {
153: FNEvaluateFunction(nep->f[j],x[i],&fx[i+j*(deg+1)]);
154: }
155: }
157: /* Polynomial coefficients */
158: for (k=0;k<=deg;k++) {
159: MatDuplicate(nep->A[0],MAT_COPY_VALUES,&A[k]);
160: t = 0.0;
161: for (i=0;i<deg+1;i++) t += fx[i]*cs[i*(deg+1)+k];
162: t *= 2.0/(deg+1);
163: if (k==0) t /= 2.0;
164: MatScale(A[k],t);
165: for (j=1;j<nep->nt;j++) {
166: t = 0.0;
167: for (i=0;i<deg+1;i++) t += fx[i+j*(deg+1)]*cs[i*(deg+1)+k];
168: t *= 2.0/(deg+1);
169: if (k==0) t /= 2.0;
170: MatAXPY(A[k],t,nep->A[j],SUBSET_NONZERO_PATTERN);
171: }
172: }
174: PEPSetOperators(ctx->pep,deg+1,A);
175: for (k=0;k<=deg;k++) {
176: MatDestroy(&A[k]);
177: }
178: PetscFree4(A,cs,x,fx);
180: /* Solve polynomial eigenproblem */
181: PEPSolve(ctx->pep);
182: PEPGetConverged(ctx->pep,&nep->nconv);
183: PEPGetIterationNumber(ctx->pep,&nep->its);
184: PEPGetConvergedReason(ctx->pep,(PEPConvergedReason*)&nep->reason);
185: s = 2.0/(b-a);
186: for (i=0;i<nep->nconv;i++) {
187: PEPGetEigenpair(ctx->pep,i,&nep->eigr[i],&nep->eigi[i],NULL,NULL);
188: nep->eigr[i] /= s;
189: nep->eigr[i] += (a+b)/2.0;
190: nep->eigi[i] /= s;
191: }
192: nep->state = NEP_STATE_EIGENVECTORS;
193: return(0);
194: }
198: PetscErrorCode NEPSetFromOptions_Interpol(PetscOptions *PetscOptionsObject,NEP nep)
199: {
201: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
204: if (!ctx->pep) { NEPInterpolGetPEP(nep,&ctx->pep); }
205: PEPSetFromOptions(ctx->pep);
206: PetscOptionsHead(PetscOptionsObject,"NEP Interpol Options");
207: PetscOptionsInt("-nep_interpol_degree","Degree of interpolation polynomial","NEPInterpolSetDegree",ctx->deg,&ctx->deg,NULL);
208: PetscOptionsTail();
209: return(0);
210: }
214: static PetscErrorCode NEPInterpolSetDegree_Interpol(NEP nep,PetscInt deg)
215: {
216: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
219: ctx->deg = deg;
220: return(0);
221: }
225: /*@
226: NEPInterpolSetDegree - Sets the degree of the interpolation polynomial.
228: Collective on NEP
230: Input Parameters:
231: + nep - nonlinear eigenvalue solver
232: - deg - polynomial degree
234: Level: advanced
236: .seealso: NEPInterpolGetDegree()
237: @*/
238: PetscErrorCode NEPInterpolSetDegree(NEP nep,PetscInt deg)
239: {
245: PetscTryMethod(nep,"NEPInterpolSetDegree_C",(NEP,PetscInt),(nep,deg));
246: return(0);
247: }
251: static PetscErrorCode NEPInterpolGetDegree_Interpol(NEP nep,PetscInt *deg)
252: {
253: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
256: *deg = ctx->deg;
257: return(0);
258: }
262: /*@
263: NEPInterpolGetDegree - Gets the degree of the interpolation polynomial.
265: Not Collective
267: Input Parameter:
268: . nep - nonlinear eigenvalue solver
270: Output Parameter:
271: . pep - the polynomial degree
273: Level: advanced
275: .seealso: NEPInterpolSetDegree()
276: @*/
277: PetscErrorCode NEPInterpolGetDegree(NEP nep,PetscInt *deg)
278: {
284: PetscTryMethod(nep,"NEPInterpolGetDegree_C",(NEP,PetscInt*),(nep,deg));
285: return(0);
286: }
290: static PetscErrorCode NEPInterpolSetPEP_Interpol(NEP nep,PEP pep)
291: {
293: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
296: PetscObjectReference((PetscObject)pep);
297: PEPDestroy(&ctx->pep);
298: ctx->pep = pep;
299: PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->pep);
300: nep->state = NEP_STATE_INITIAL;
301: return(0);
302: }
306: /*@
307: NEPInterpolSetPEP - Associate a polynomial eigensolver object (PEP) to the
308: nonlinear eigenvalue solver.
310: Collective on NEP
312: Input Parameters:
313: + nep - nonlinear eigenvalue solver
314: - pep - the polynomial eigensolver object
316: Level: advanced
318: .seealso: NEPInterpolGetPEP()
319: @*/
320: PetscErrorCode NEPInterpolSetPEP(NEP nep,PEP pep)
321: {
328: PetscTryMethod(nep,"NEPInterpolSetPEP_C",(NEP,PEP),(nep,pep));
329: return(0);
330: }
334: static PetscErrorCode NEPInterpolGetPEP_Interpol(NEP nep,PEP *pep)
335: {
337: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
338: ST st;
341: if (!ctx->pep) {
342: PEPCreate(PetscObjectComm((PetscObject)nep),&ctx->pep);
343: PEPSetOptionsPrefix(ctx->pep,((PetscObject)nep)->prefix);
344: PEPAppendOptionsPrefix(ctx->pep,"nep_");
345: PEPGetST(ctx->pep,&st);
346: STSetOptionsPrefix(st,((PetscObject)ctx->pep)->prefix);
347: PetscObjectIncrementTabLevel((PetscObject)ctx->pep,(PetscObject)nep,1);
348: PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->pep);
349: }
350: *pep = ctx->pep;
351: return(0);
352: }
356: /*@
357: NEPInterpolGetPEP - Retrieve the polynomial eigensolver object (PEP)
358: associated with the nonlinear eigenvalue solver.
360: Not Collective
362: Input Parameter:
363: . nep - nonlinear eigenvalue solver
365: Output Parameter:
366: . pep - the polynomial eigensolver object
368: Level: advanced
370: .seealso: NEPInterpolSetPEP()
371: @*/
372: PetscErrorCode NEPInterpolGetPEP(NEP nep,PEP *pep)
373: {
379: PetscTryMethod(nep,"NEPInterpolGetPEP_C",(NEP,PEP*),(nep,pep));
380: return(0);
381: }
385: PetscErrorCode NEPView_Interpol(NEP nep,PetscViewer viewer)
386: {
388: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
391: if (!ctx->pep) { NEPInterpolGetPEP(nep,&ctx->pep); }
392: PetscViewerASCIIPrintf(viewer," Interpol: polynomial degree %D\n",ctx->deg);
393: PetscViewerASCIIPushTab(viewer);
394: PEPView(ctx->pep,viewer);
395: PetscViewerASCIIPopTab(viewer);
396: return(0);
397: }
401: PetscErrorCode NEPReset_Interpol(NEP nep)
402: {
404: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
407: if (!ctx->pep) { PEPReset(ctx->pep); }
408: return(0);
409: }
413: PetscErrorCode NEPDestroy_Interpol(NEP nep)
414: {
416: NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;
419: PEPDestroy(&ctx->pep);
420: PetscFree(nep->data);
421: PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolSetDegree_C",NULL);
422: PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolGetDegree_C",NULL);
423: PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolSetPEP_C",NULL);
424: PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolGetPEP_C",NULL);
425: return(0);
426: }
430: PETSC_EXTERN PetscErrorCode NEPCreate_Interpol(NEP nep)
431: {
433: NEP_INTERPOL *ctx;
436: PetscNewLog(nep,&ctx);
437: ctx->deg = 5;
438: nep->data = (void*)ctx;
440: nep->ops->solve = NEPSolve_Interpol;
441: nep->ops->setup = NEPSetUp_Interpol;
442: nep->ops->setfromoptions = NEPSetFromOptions_Interpol;
443: nep->ops->reset = NEPReset_Interpol;
444: nep->ops->destroy = NEPDestroy_Interpol;
445: nep->ops->view = NEPView_Interpol;
446: PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolSetDegree_C",NEPInterpolSetDegree_Interpol);
447: PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolGetDegree_C",NEPInterpolGetDegree_Interpol);
448: PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolSetPEP_C",NEPInterpolSetPEP_Interpol);
449: PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolGetPEP_C",NEPInterpolGetPEP_Interpol);
450: return(0);
451: }