Actual source code: ex21.c

slepc-3.5.2 2014-10-10
Report Typos and Errors
  1: /*
  2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  4:    Copyright (c) 2002-2014, Universitat Politecnica de Valencia, Spain

  6:    This file is part of SLEPc.

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

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

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

 22: static char help[] = "Simple 1-D nonlinear eigenproblem (matrix-free version, sequential).\n\n"
 23:   "The command line options are:\n"
 24:   "  -n <n>, where <n> = number of grid subdivisions\n\n";

 26: /*
 27:    Solve 1-D PDE
 28:             -u'' = lambda*u
 29:    on [0,1] subject to
 30:             u(0)=0, u'(1)=u(1)*lambda*kappa/(kappa-lambda)
 31: */

 33: #include <slepcnep.h>

 35: /*
 36:    User-defined routines
 37: */
 38: PetscErrorCode FormInitialGuess(Vec);
 39: PetscErrorCode FormFunction(NEP,PetscScalar,Mat,Mat,void*);
 40: PetscErrorCode FormJacobian(NEP,PetscScalar,Mat,void*);

 42: /*
 43:    Matrix operations and context
 44: */
 45: PetscErrorCode MatMult_Fun(Mat,Vec,Vec);
 46: PetscErrorCode MatGetDiagonal_Fun(Mat,Vec);
 47: PetscErrorCode MatDestroy_Fun(Mat);
 48: PetscErrorCode MatDuplicate_Fun(Mat,MatDuplicateOption,Mat*);
 49: PetscErrorCode MatMult_Jac(Mat,Vec,Vec);
 50: PetscErrorCode MatDestroy_Jac(Mat);

 52: typedef struct {
 53:   PetscScalar lambda,kappa;
 54:   PetscReal   h;
 55: } MatCtx;

 57: /*
 58:    User-defined application context
 59: */
 60: typedef struct {
 61:   PetscScalar kappa;   /* ratio between stiffness of spring and attached mass */
 62:   PetscReal   h;       /* mesh spacing */
 63: } ApplicationCtx;

 67: int main(int argc,char **argv)
 68: {
 69:   NEP            nep;             /* nonlinear eigensolver context */
 70:   PetscScalar    lambda;          /* eigenvalue */
 71:   Mat            F,J;             /* Function and Jacobian matrices */
 72:   ApplicationCtx ctx;             /* user-defined context */
 73:   MatCtx         *ctxF,*ctxJ;     /* contexts for shell matrices */
 74:   NEPType        type;
 75:   PetscInt       n=128,nev,i,its,nconv;
 76:   KSP            ksp;
 77:   PC             pc;
 78:   PetscMPIInt    size;
 79:   PetscReal      re,im,norm;

 82:   SlepcInitialize(&argc,&argv,(char*)0,help);
 83:   MPI_Comm_size(PETSC_COMM_WORLD,&size);
 84:   if (size != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"This is a uniprocessor example only!");
 85:   PetscOptionsGetInt(NULL,"-n",&n,NULL);
 86:   PetscPrintf(PETSC_COMM_WORLD,"\n1-D Nonlinear Eigenproblem, n=%D\n\n",n);
 87:   ctx.h = 1.0/(PetscReal)n;
 88:   ctx.kappa = 1.0;

 90:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 91:      Create nonlinear eigensolver context
 92:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 94:   NEPCreate(PETSC_COMM_WORLD,&nep);

 96:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 97:      Create matrix data structure; set Function evaluation routine
 98:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

100:   PetscNew(&ctxF);
101:   ctxF->h = ctx.h;
102:   ctxF->kappa = ctx.kappa;

104:   MatCreateShell(PETSC_COMM_WORLD,n,n,n,n,(void*)ctxF,&F);
105:   MatShellSetOperation(F,MATOP_MULT,(void(*)())MatMult_Fun);
106:   MatShellSetOperation(F,MATOP_GET_DIAGONAL,(void(*)())MatGetDiagonal_Fun);
107:   MatShellSetOperation(F,MATOP_DESTROY,(void(*)())MatDestroy_Fun);
108:   MatShellSetOperation(F,MATOP_DUPLICATE,(void(*)())MatDuplicate_Fun);

110:   /*
111:      Set Function matrix data structure and default Function evaluation
112:      routine
113:   */
114:   NEPSetFunction(nep,F,F,FormFunction,NULL);

116:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
117:      Create matrix data structure; set Jacobian evaluation routine
118:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

120:   PetscNew(&ctxJ);
121:   ctxJ->h = ctx.h;
122:   ctxJ->kappa = ctx.kappa;

124:   MatCreateShell(PETSC_COMM_WORLD,n,n,n,n,(void*)ctxJ,&J);
125:   MatShellSetOperation(J,MATOP_MULT,(void(*)())MatMult_Jac);
126:   MatShellSetOperation(J,MATOP_DESTROY,(void(*)())MatDestroy_Jac);

128:   /*
129:      Set Jacobian matrix data structure and default Jacobian evaluation
130:      routine
131:   */
132:   NEPSetJacobian(nep,J,FormJacobian,NULL);

134:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
135:      Customize nonlinear solver; set runtime options
136:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

138:   NEPGetKSP(nep,&ksp);
139:   KSPSetType(ksp,KSPBCGS);
140:   KSPGetPC(ksp,&pc);
141:   PCSetType(pc,PCJACOBI);

143:   /*
144:      Set solver parameters at runtime
145:   */
146:   NEPSetFromOptions(nep);

148:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
149:                       Solve the eigensystem
150:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

152:   NEPSolve(nep);
153:   NEPGetIterationNumber(nep,&its);
154:   PetscPrintf(PETSC_COMM_WORLD," Number of NEP iterations = %D\n\n",its);

156:   /*
157:      Optional: Get some information from the solver and display it
158:   */
159:   NEPGetType(nep,&type);
160:   PetscPrintf(PETSC_COMM_WORLD," Solution method: %s\n",type);
161:   NEPGetDimensions(nep,&nev,NULL,NULL);
162:   PetscPrintf(PETSC_COMM_WORLD," Number of requested eigenvalues: %D\n",nev);

164:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
165:                     Display solution and clean up
166:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

168:   /*
169:      Get number of converged approximate eigenpairs
170:   */
171:   NEPGetConverged(nep,&nconv);
172:   PetscPrintf(PETSC_COMM_WORLD," Number of converged approximate eigenpairs: %D\n\n",nconv);

174:   if (nconv>0) {
175:     /*
176:        Display eigenvalues and relative errors
177:     */
178:     PetscPrintf(PETSC_COMM_WORLD,
179:          "           k              ||T(k)x||\n"
180:          "   ----------------- ------------------\n");
181:     for (i=0;i<nconv;i++) {
182:       /*
183:         Get converged eigenpairs (in this example they are always real)
184:       */
185:       NEPGetEigenpair(nep,i,&lambda,NULL,NULL,NULL);
186:       /*
187:          Compute residual norm
188:       */
189:       NEPComputeRelativeError(nep,i,&norm);

191: #if defined(PETSC_USE_COMPLEX)
192:       re = PetscRealPart(lambda);
193:       im = PetscImaginaryPart(lambda);
194: #else
195:       re = lambda;
196:       im = 0.0;
197: #endif
198:       if (im!=0.0) {
199:         PetscPrintf(PETSC_COMM_WORLD," %9f%+9f j %12g\n",(double)re,(double)im,(double)norm);
200:       } else {
201:         PetscPrintf(PETSC_COMM_WORLD,"   %12f         %12g\n",(double)re,(double)norm);
202:       }
203:     }
204:     PetscPrintf(PETSC_COMM_WORLD,"\n");
205:   }

207:   NEPDestroy(&nep);
208:   MatDestroy(&F);
209:   MatDestroy(&J);
210:   SlepcFinalize();
211:   return 0;
212: }

214: /* ------------------------------------------------------------------- */
217: /*
218:    FormInitialGuess - Computes initial guess.

220:    Input/Output Parameter:
221: .  x - the solution vector
222: */
223: PetscErrorCode FormInitialGuess(Vec x)
224: {

228:   VecSet(x,1.0);
229:   return(0);
230: }

232: /* ------------------------------------------------------------------- */
235: /*
236:    FormFunction - Computes Function matrix  T(lambda)

238:    Input Parameters:
239: .  nep    - the NEP context
240: .  lambda - real part of the scalar argument
241: .  ctx    - optional user-defined context, as set by NEPSetJacobian()

243:    Output Parameters:
244: .  fun - Function matrix
245: .  B   - optionally different preconditioning matrix
246: */
247: PetscErrorCode FormFunction(NEP nep,PetscScalar lambda,Mat fun,Mat B,void *ctx)
248: {
250:   MatCtx         *ctxF;

253:   MatShellGetContext(fun,(void**)&ctxF);
254:   ctxF->lambda = lambda;
255:   return(0);
256: }

258: /* ------------------------------------------------------------------- */
261: /*
262:    FormJacobian - Computes Jacobian matrix  T'(lambda)

264:    Input Parameters:
265: .  nep    - the NEP context
266: .  lambda - real part of the scalar argument
267: .  ctx    - optional user-defined context, as set by NEPSetJacobian()

269:    Output Parameters:
270: .  jac - Jacobian matrix
271: .  B   - optionally different preconditioning matrix
272: */
273: PetscErrorCode FormJacobian(NEP nep,PetscScalar lambda,Mat jac,void *ctx)
274: {
276:   MatCtx         *ctxJ;

279:   MatShellGetContext(jac,(void**)&ctxJ);
280:   ctxJ->lambda = lambda;
281:   return(0);
282: }

284: /* ------------------------------------------------------------------- */
287: PetscErrorCode MatMult_Fun(Mat A,Vec x,Vec y)
288: {
289:   PetscErrorCode    ierr;
290:   MatCtx            *ctx;
291:   PetscInt          i,n;
292:   const PetscScalar *px;
293:   PetscScalar       *py,c,d,de,oe;
294:   PetscReal         h;

297:   MatShellGetContext(A,(void**)&ctx);
298:   VecGetArrayRead(x,&px);
299:   VecGetArray(y,&py);

301:   VecGetSize(x,&n);
302:   h = ctx->h;
303:   c = ctx->kappa/(ctx->lambda-ctx->kappa);
304:   d = n;
305:   de = 2.0*(d-ctx->lambda*h/3.0);   /* diagonal entry */
306:   oe = -d-ctx->lambda*h/6.0;        /* offdiagonal entry */
307:   py[0] = de*px[0] + oe*px[1];
308:   for (i=1;i<n-1;i++) py[i] = oe*px[i-1] +de*px[i] + oe*px[i+1];
309:   de = d-ctx->lambda*h/3.0+ctx->lambda*c;   /* diagonal entry of last row */
310:   py[n-1] = oe*px[n-2] + de*px[n-1];

312:   VecRestoreArrayRead(x,&px);
313:   VecRestoreArray(y,&py);
314:   return(0);
315: }

317: /* ------------------------------------------------------------------- */
320: PetscErrorCode MatGetDiagonal_Fun(Mat A,Vec diag)
321: {
322:   PetscErrorCode    ierr;
323:   MatCtx            *ctx;
324:   PetscInt          n;
325:   PetscScalar       *pd,c,d;
326:   PetscReal         h;

329:   MatShellGetContext(A,(void**)&ctx);
330:   h = ctx->h;
331:   c = ctx->kappa/(ctx->lambda-ctx->kappa);
332:   d = n;
333:   VecSet(diag,2.0*(d-ctx->lambda*h/3.0));
334:   VecGetSize(diag,&n);
335:   VecGetArray(diag,&pd);
336:   pd[n-1] = d-ctx->lambda*h/3.0+ctx->lambda*c;
337:   VecRestoreArray(diag,&pd);
338:   return(0);
339: }

341: /* ------------------------------------------------------------------- */
344: PetscErrorCode MatDestroy_Fun(Mat A)
345: {
346:   MatCtx         *ctx;

350:   MatShellGetContext(A,(void**)&ctx);
351:   PetscFree(ctx);
352:   return(0);
353: }

355: /* ------------------------------------------------------------------- */
358: PetscErrorCode MatDuplicate_Fun(Mat A,MatDuplicateOption op,Mat *B)
359: {
360:   MatCtx         *actx,*bctx;
361:   PetscInt       n;
362:   MPI_Comm       comm;

366:   MatShellGetContext(A,(void**)&actx);
367:   MatGetSize(A,&n,NULL);

369:   PetscNew(&bctx);
370:   bctx->h      = actx->h;
371:   bctx->kappa  = actx->kappa;
372:   bctx->lambda = actx->lambda;

374:   PetscObjectGetComm((PetscObject)A,&comm);
375:   MatCreateShell(comm,n,n,n,n,(void*)bctx,B);
376:   MatShellSetOperation(*B,MATOP_MULT,(void(*)())MatMult_Fun);
377:   MatShellSetOperation(*B,MATOP_GET_DIAGONAL,(void(*)())MatGetDiagonal_Fun);
378:   MatShellSetOperation(*B,MATOP_DESTROY,(void(*)())MatDestroy_Fun);
379:   MatShellSetOperation(*B,MATOP_DUPLICATE,(void(*)())MatDuplicate_Fun);
380:   return(0);
381: }

383: /* ------------------------------------------------------------------- */
386: PetscErrorCode MatMult_Jac(Mat A,Vec x,Vec y)
387: {
388:   PetscErrorCode    ierr;
389:   MatCtx            *ctx;
390:   PetscInt          i,n;
391:   const PetscScalar *px;
392:   PetscScalar       *py,c,de,oe;
393:   PetscReal         h;

396:   MatShellGetContext(A,(void**)&ctx);
397:   VecGetArrayRead(x,&px);
398:   VecGetArray(y,&py);

400:   VecGetSize(x,&n);
401:   h = ctx->h;
402:   c = ctx->kappa/(ctx->lambda-ctx->kappa);
403:   de = -2.0*h/3.0;    /* diagonal entry */
404:   oe = -h/6.0;        /* offdiagonal entry */
405:   py[0] = de*px[0] + oe*px[1];
406:   for (i=1;i<n-1;i++) py[i] = oe*px[i-1] +de*px[i] + oe*px[i+1];
407:   de = -h/3.0-c*c;    /* diagonal entry of last row */
408:   py[n-1] = oe*px[n-2] + de*px[n-1];

410:   VecRestoreArrayRead(x,&px);
411:   VecRestoreArray(y,&py);
412:   return(0);
413: }

415: /* ------------------------------------------------------------------- */
418: PetscErrorCode MatDestroy_Jac(Mat A)
419: {
420:   MatCtx         *ctx;

424:   MatShellGetContext(A,(void**)&ctx);
425:   PetscFree(ctx);
426:   return(0);
427: }