Actual source code: interpol.c

slepc-3.7.0 2016-05-16
Report Typos and Errors
  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-2016, 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>         /*I "slepcpep.h" I*/

 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,trackall;
 56:   PetscInt       its,in;

 59:   NEPSetDimensions_Default(nep,nep->nev,&nep->ncv,&nep->mpd);
 60:   if (nep->ncv>nep->nev+nep->mpd) SETERRQ(PetscObjectComm((PetscObject)nep),1,"The value of ncv must not be larger than nev+mpd");
 61:   if (!nep->max_it) nep->max_it = PetscMax(5000,2*nep->n/nep->ncv);
 62:   if (nep->fui!=NEP_USER_INTERFACE_SPLIT) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"NEPINTERPOL only available for split operator");
 63:   if (nep->stopping!=NEPStoppingBasic) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"This solver does not support user-defined stopping test");

 65:   /* transfer PEP options */
 66:   if (!ctx->pep) { NEPInterpolGetPEP(nep,&ctx->pep); }
 67:   PEPSetBV(ctx->pep,nep->V);
 68:   PEPSetBasis(ctx->pep,PEP_BASIS_CHEBYSHEV1);
 69:   PEPSetWhichEigenpairs(ctx->pep,PEP_TARGET_MAGNITUDE);
 70:   PEPGetST(ctx->pep,&st);
 71:   STSetType(st,STSINVERT);
 72:   PEPSetDimensions(ctx->pep,nep->nev,nep->ncv?nep->ncv:PETSC_DEFAULT,nep->mpd?nep->mpd:PETSC_DEFAULT);
 73:   tol=ctx->pep->tol;
 74:   if (tol==PETSC_DEFAULT) tol = (nep->tol==PETSC_DEFAULT)?SLEPC_DEFAULT_TOL/10.0:nep->tol/10.0;
 75:   its=ctx->pep->max_it;
 76:   if (!its) its = nep->max_it?nep->max_it:PETSC_DEFAULT;
 77:   PEPSetTolerances(ctx->pep,tol,its);
 78:   NEPGetTrackAll(nep,&trackall);
 79:   PEPSetTrackAll(ctx->pep,trackall);

 81:   /* transfer region options */
 82:   RGIsTrivial(nep->rg,&istrivial);
 83:   if (istrivial) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"NEPINTERPOL requires a nontrivial region");
 84:   PetscObjectTypeCompare((PetscObject)nep->rg,RGINTERVAL,&flg);
 85:   if (!flg) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Only implemented for interval regions");
 86:   RGIntervalGetEndpoints(nep->rg,&a,&b,&c,&d);
 87:   if (a<=-PETSC_MAX_REAL || b>=PETSC_MAX_REAL) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Only implemented for bounded intervals");
 88:   PEPGetRG(ctx->pep,&rg);
 89:   RGSetType(rg,RGINTERVAL);
 90:   if (a==b) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Only implemented for intervals on the real axis");
 91:   s = 2.0/(b-a);
 92:   c = c*s;
 93:   d = d*s;
 94:   RGIntervalSetEndpoints(rg,-1.0,1.0,c,d);
 95:   RGCheckInside(nep->rg,1,&nep->target,&zero,&in);
 96:   if (in<0) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"The target is not inside the target set");
 97:   PEPSetTarget(ctx->pep,(nep->target-(a+b)/2)*s);

 99:   NEPAllocateSolution(nep,0);
100:   return(0);
101: }

105: /*
106:   Input: 
107:     d, number of nodes to compute
108:     a,b, interval extrems
109:   Output:
110:     *x, array containing the d Chebyshev nodes of the interval [a,b]
111:     *dct2, coefficients to compute a discrete cosine transformation (DCT-II)
112: */
113: static PetscErrorCode ChebyshevNodes(PetscInt d,PetscReal a,PetscReal b,PetscScalar *x,PetscReal *dct2)
114: {
115:   PetscInt  j,i;
116:   PetscReal t;

119:   for (j=0;j<d+1;j++) {
120:     t = ((2*j+1)*PETSC_PI)/(2*(d+1));
121:     x[j] = (a+b)/2.0+((b-a)/2.0)*PetscCosReal(t);
122:     for (i=0;i<d+1;i++) dct2[j*(d+1)+i] = PetscCosReal(i*t);
123:   }
124:   return(0);
125: }

129: PetscErrorCode NEPSolve_Interpol(NEP nep)
130: {
132:   NEP_INTERPOL   *ctx = (NEP_INTERPOL*)nep->data;
133:   Mat            *A;   /*T=nep->function,Tp=nep->jacobian;*/
134:   PetscScalar    *x,*fx,t;
135:   PetscReal      *cs,a,b,s;
136:   PetscInt       i,j,k,deg=ctx->deg;

139:   PetscMalloc4(deg+1,&A,(deg+1)*(deg+1),&cs,deg+1,&x,(deg+1)*nep->nt,&fx);
140:   RGIntervalGetEndpoints(nep->rg,&a,&b,NULL,NULL);
141:   ChebyshevNodes(deg,a,b,x,cs);
142:   for (j=0;j<nep->nt;j++) {
143:     for (i=0;i<=deg;i++) {
144:       FNEvaluateFunction(nep->f[j],x[i],&fx[i+j*(deg+1)]);
145:     }
146:   }

148:   /* Polynomial coefficients */
149:   for (k=0;k<=deg;k++) {
150:     MatDuplicate(nep->A[0],MAT_COPY_VALUES,&A[k]);
151:     t = 0.0;
152:     for (i=0;i<deg+1;i++) t += fx[i]*cs[i*(deg+1)+k];
153:     t *= 2.0/(deg+1); 
154:     if (k==0) t /= 2.0;
155:     MatScale(A[k],t);
156:     for (j=1;j<nep->nt;j++) {
157:       t = 0.0;
158:       for (i=0;i<deg+1;i++) t += fx[i+j*(deg+1)]*cs[i*(deg+1)+k];
159:       t *= 2.0/(deg+1); 
160:       if (k==0) t /= 2.0;
161:       MatAXPY(A[k],t,nep->A[j],nep->mstr);
162:     }
163:   }

165:   PEPSetOperators(ctx->pep,deg+1,A);
166:   for (k=0;k<=deg;k++) {
167:     MatDestroy(&A[k]);
168:   }
169:   PetscFree4(A,cs,x,fx);

171:   /* Solve polynomial eigenproblem */
172:   PEPSolve(ctx->pep);
173:   PEPGetConverged(ctx->pep,&nep->nconv);
174:   PEPGetIterationNumber(ctx->pep,&nep->its);
175:   PEPGetConvergedReason(ctx->pep,(PEPConvergedReason*)&nep->reason);
176:   s = 2.0/(b-a);
177:   for (i=0;i<nep->nconv;i++) {
178:     PEPGetEigenpair(ctx->pep,i,&nep->eigr[i],&nep->eigi[i],NULL,NULL);
179:     nep->eigr[i] /= s;
180:     nep->eigr[i] += (a+b)/2.0;
181:     nep->eigi[i] /= s;
182:   }
183:   nep->state = NEP_STATE_EIGENVECTORS;
184:   return(0);
185: }

189: static PetscErrorCode PEPMonitor_Interpol(PEP pep,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
190: {
191:   PetscInt       i;
192:   NEP            nep = (NEP)ctx;

196:   for (i=0;i<PetscMin(nest,nep->ncv);i++) {
197:     nep->eigr[i]   = eigr[i];
198:     nep->eigi[i]   = eigi[i];
199:     nep->errest[i] = errest[i];
200:   }
201:   NEPMonitor(nep,its,nconv,nep->eigr,nep->eigi,nep->errest,nest);
202:   return(0);
203: }

207: PetscErrorCode NEPSetFromOptions_Interpol(PetscOptionItems *PetscOptionsObject,NEP nep)
208: {
210:   NEP_INTERPOL   *ctx = (NEP_INTERPOL*)nep->data;

213:   if (!ctx->pep) { NEPInterpolGetPEP(nep,&ctx->pep); }
214:   PEPSetFromOptions(ctx->pep);
215:   PetscOptionsHead(PetscOptionsObject,"NEP Interpol Options");
216:   PetscOptionsInt("-nep_interpol_degree","Degree of interpolation polynomial","NEPInterpolSetDegree",ctx->deg,&ctx->deg,NULL);
217:   PetscOptionsTail();
218:   return(0);
219: }

223: static PetscErrorCode NEPInterpolSetDegree_Interpol(NEP nep,PetscInt deg)
224: {
225:   NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;

228:   ctx->deg = deg;
229:   return(0);
230: }

234: /*@
235:    NEPInterpolSetDegree - Sets the degree of the interpolation polynomial.

237:    Collective on NEP

239:    Input Parameters:
240: +  nep - nonlinear eigenvalue solver
241: -  deg - polynomial degree

243:    Level: advanced

245: .seealso: NEPInterpolGetDegree()
246: @*/
247: PetscErrorCode NEPInterpolSetDegree(NEP nep,PetscInt deg)
248: {

254:   PetscTryMethod(nep,"NEPInterpolSetDegree_C",(NEP,PetscInt),(nep,deg));
255:   return(0);
256: }

260: static PetscErrorCode NEPInterpolGetDegree_Interpol(NEP nep,PetscInt *deg)
261: {
262:   NEP_INTERPOL *ctx = (NEP_INTERPOL*)nep->data;

265:   *deg = ctx->deg;
266:   return(0);
267: }

271: /*@
272:    NEPInterpolGetDegree - Gets the degree of the interpolation polynomial.

274:    Not Collective

276:    Input Parameter:
277: .  nep - nonlinear eigenvalue solver

279:    Output Parameter:
280: .  deg - the polynomial degree

282:    Level: advanced

284: .seealso: NEPInterpolSetDegree()
285: @*/
286: PetscErrorCode NEPInterpolGetDegree(NEP nep,PetscInt *deg)
287: {

293:   PetscUseMethod(nep,"NEPInterpolGetDegree_C",(NEP,PetscInt*),(nep,deg));
294:   return(0);
295: }

299: static PetscErrorCode NEPInterpolSetPEP_Interpol(NEP nep,PEP pep)
300: {
302:   NEP_INTERPOL   *ctx = (NEP_INTERPOL*)nep->data;

305:   PetscObjectReference((PetscObject)pep);
306:   PEPDestroy(&ctx->pep);
307:   ctx->pep = pep;
308:   PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->pep);
309:   nep->state = NEP_STATE_INITIAL;
310:   return(0);
311: }

315: /*@
316:    NEPInterpolSetPEP - Associate a polynomial eigensolver object (PEP) to the
317:    nonlinear eigenvalue solver.

319:    Collective on NEP

321:    Input Parameters:
322: +  nep - nonlinear eigenvalue solver
323: -  pep - the polynomial eigensolver object

325:    Level: advanced

327: .seealso: NEPInterpolGetPEP()
328: @*/
329: PetscErrorCode NEPInterpolSetPEP(NEP nep,PEP pep)
330: {

337:   PetscTryMethod(nep,"NEPInterpolSetPEP_C",(NEP,PEP),(nep,pep));
338:   return(0);
339: }

343: static PetscErrorCode NEPInterpolGetPEP_Interpol(NEP nep,PEP *pep)
344: {
346:   NEP_INTERPOL   *ctx = (NEP_INTERPOL*)nep->data;
347:   ST             st;

350:   if (!ctx->pep) {
351:     PEPCreate(PetscObjectComm((PetscObject)nep),&ctx->pep);
352:     PEPSetOptionsPrefix(ctx->pep,((PetscObject)nep)->prefix);
353:     PEPAppendOptionsPrefix(ctx->pep,"nep_interpol_");
354:     PEPGetST(ctx->pep,&st);
355:     STSetOptionsPrefix(st,((PetscObject)ctx->pep)->prefix);
356:     PetscObjectIncrementTabLevel((PetscObject)ctx->pep,(PetscObject)nep,1);
357:     PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->pep);
358:     PEPMonitorSet(ctx->pep,PEPMonitor_Interpol,nep,NULL);
359:   }
360:   *pep = ctx->pep;
361:   return(0);
362: }

366: /*@
367:    NEPInterpolGetPEP - Retrieve the polynomial eigensolver object (PEP)
368:    associated with the nonlinear eigenvalue solver.

370:    Not Collective

372:    Input Parameter:
373: .  nep - nonlinear eigenvalue solver

375:    Output Parameter:
376: .  pep - the polynomial eigensolver object

378:    Level: advanced

380: .seealso: NEPInterpolSetPEP()
381: @*/
382: PetscErrorCode NEPInterpolGetPEP(NEP nep,PEP *pep)
383: {

389:   PetscUseMethod(nep,"NEPInterpolGetPEP_C",(NEP,PEP*),(nep,pep));
390:   return(0);
391: }

395: PetscErrorCode NEPView_Interpol(NEP nep,PetscViewer viewer)
396: {
398:   NEP_INTERPOL   *ctx = (NEP_INTERPOL*)nep->data;
399:   PetscBool      isascii;

402:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
403:   if (isascii) {
404:     if (!ctx->pep) { NEPInterpolGetPEP(nep,&ctx->pep); }
405:     PetscViewerASCIIPrintf(viewer,"  Interpol: polynomial degree %D\n",ctx->deg);
406:     PetscViewerASCIIPushTab(viewer);
407:     PEPView(ctx->pep,viewer);
408:     PetscViewerASCIIPopTab(viewer);
409:   }
410:   return(0);
411: }

415: PetscErrorCode NEPReset_Interpol(NEP nep)
416: {
418:   NEP_INTERPOL   *ctx = (NEP_INTERPOL*)nep->data;

421:   if (!ctx->pep) { PEPReset(ctx->pep); }
422:   return(0);
423: }

427: PetscErrorCode NEPDestroy_Interpol(NEP nep)
428: {
430:   NEP_INTERPOL   *ctx = (NEP_INTERPOL*)nep->data;

433:   PEPDestroy(&ctx->pep);
434:   PetscFree(nep->data);
435:   PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolSetDegree_C",NULL);
436:   PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolGetDegree_C",NULL);
437:   PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolSetPEP_C",NULL);
438:   PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolGetPEP_C",NULL);
439:   return(0);
440: }

444: PETSC_EXTERN PetscErrorCode NEPCreate_Interpol(NEP nep)
445: {
447:   NEP_INTERPOL   *ctx;

450:   PetscNewLog(nep,&ctx);
451:   ctx->deg  = 5;
452:   nep->data = (void*)ctx;

454:   nep->ops->solve          = NEPSolve_Interpol;
455:   nep->ops->setup          = NEPSetUp_Interpol;
456:   nep->ops->setfromoptions = NEPSetFromOptions_Interpol;
457:   nep->ops->reset          = NEPReset_Interpol;
458:   nep->ops->destroy        = NEPDestroy_Interpol;
459:   nep->ops->view           = NEPView_Interpol;
460:   PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolSetDegree_C",NEPInterpolSetDegree_Interpol);
461:   PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolGetDegree_C",NEPInterpolGetDegree_Interpol);
462:   PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolSetPEP_C",NEPInterpolSetPEP_Interpol);
463:   PetscObjectComposeFunction((PetscObject)nep,"NEPInterpolGetPEP_C",NEPInterpolGetPEP_Interpol);
464:   return(0);
465: }