Actual source code: ex3.c

  2: static char help[] = "Solves the same eigenproblem as in example ex2, but using a shell matrix. "
  3:   "The problem is a standard symmetric eigenproblem corresponding to the 2-D Laplacian operator.\n\n"
  4:   "The command line options are:\n\n"
  5:   "  -n <n>, where <n> = number of grid subdivisions in both x and y dimensions.\n\n";

 7:  #include slepceps.h
  8: #include "petscblaslapack.h"

 10: /* 
 11:    User-defined routines
 12: */
 13: extern int MatLaplacian2D_Mult( Mat A, Vec x, Vec y );

 17: int main( int argc, char **argv )
 18: {
 19:   Mat         A;               /* operator matrix */
 20:   EPS         eps;             /* eigenproblem solver context */
 21:   EPSType     type;
 22:   PetscReal   error, tol, re, im;
 23:   PetscScalar kr, ki;
 24:   int         size, N, n=10, nev, ierr, maxit, i, its, nconv;

 26:   SlepcInitialize(&argc,&argv,(char*)0,help);
 27:   MPI_Comm_size(PETSC_COMM_WORLD,&size);
 28:   if (size != 1) SETERRQ(1,"This is a uniprocessor example only!");

 30:   PetscOptionsGetInt(PETSC_NULL,"-n",&n,PETSC_NULL);
 31:   N = n*n;
 32:   PetscPrintf(PETSC_COMM_WORLD,"\n2-D Laplacian Eigenproblem (matrix-free version), N=%d (%dx%d grid)\n\n",N,n,n);

 34:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 35:      Compute the operator matrix that defines the eigensystem, Ax=kx
 36:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 38:   MatCreateShell(PETSC_COMM_WORLD,N,N,N,N,&n,&A);
 39:   MatSetFromOptions(A);
 40:   MatShellSetOperation(A,MATOP_MULT,(void(*)())MatLaplacian2D_Mult);
 41:   MatShellSetOperation(A,MATOP_MULT_TRANSPOSE,(void(*)())MatLaplacian2D_Mult);

 43:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 44:                 Create the eigensolver and set various options
 45:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 47:   /* 
 48:      Create eigensolver context
 49:   */
 50:   EPSCreate(PETSC_COMM_WORLD,&eps);

 52:   /* 
 53:      Set operators. In this case, it is a standard eigenvalue problem
 54:   */
 55:   EPSSetOperators(eps,A,PETSC_NULL);
 56:   EPSSetProblemType(eps,EPS_HEP);

 58:   /*
 59:      Set solver parameters at runtime
 60:   */
 61:   EPSSetFromOptions(eps);

 63:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 64:                       Solve the eigensystem
 65:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 67:   EPSSolve(eps);
 68:   EPSGetIterationNumber(eps, &its);
 69:   PetscPrintf(PETSC_COMM_WORLD," Number of iterations of the method: %d\n",its);

 71:   /*
 72:      Optional: Get some information from the solver and display it
 73:   */
 74:   EPSGetType(eps,&type);
 75:   PetscPrintf(PETSC_COMM_WORLD," Solution method: %s\n\n",type);
 76:   EPSGetDimensions(eps,&nev,PETSC_NULL);
 77:   PetscPrintf(PETSC_COMM_WORLD," Number of requested eigenvalues: %d\n",nev);
 78:   EPSGetTolerances(eps,&tol,&maxit);
 79:   PetscPrintf(PETSC_COMM_WORLD," Stopping condition: tol=%.4g, maxit=%d\n",tol,maxit);

 81:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 82:                     Display solution and clean up
 83:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 85:   /* 
 86:      Get number of converged approximate eigenpairs
 87:   */
 88:   EPSGetConverged(eps,&nconv);
 89:   PetscPrintf(PETSC_COMM_WORLD," Number of converged eigenpairs: %d\n\n",nconv);
 90: 

 92:   if (nconv>0) {
 93:     /*
 94:        Display eigenvalues and relative errors
 95:     */
 96:     PetscPrintf(PETSC_COMM_WORLD,
 97:          "           k          ||Ax-kx||/||kx||\n"
 98:          "   ----------------- ------------------\n" );

100:     for( i=0; i<nconv; i++ ) {
101:       /* 
102:         Get converged eigenpairs: i-th eigenvalue is stored in kr (real part) and
103:         ki (imaginary part)
104:       */
105:       EPSGetEigenpair(eps,i,&kr,&ki,PETSC_NULL,PETSC_NULL);
106:       /*
107:          Compute the relative error associated to each eigenpair
108:       */
109:       EPSComputeRelativeError(eps,i,&error);

111: #ifdef PETSC_USE_COMPLEX
112:       re = PetscRealPart(kr);
113:       im = PetscImaginaryPart(kr);
114: #else
115:       re = kr;
116:       im = ki;
117: #endif 
118:       if (im!=0.0) {
119:         PetscPrintf(PETSC_COMM_WORLD," %9f%+9f j %12f\n",re,im,error);
120:       } else {
121:         PetscPrintf(PETSC_COMM_WORLD,"   %12f       %12f\n",re,error);
122:       }
123:     }
124:     PetscPrintf(PETSC_COMM_WORLD,"\n" );
125:   }
126: 
127:   /* 
128:      Free work space
129:   */
130:   EPSDestroy(eps);
131:   MatDestroy(A);
132:   SlepcFinalize();
133:   return 0;
134: }

136: /*
137:     Compute the matrix vector multiplication y<---T*x where T is a nx by nx
138:     tridiagonal matrix with DD on the diagonal, DL on the subdiagonal, and 
139:     DU on the superdiagonal.
140:  */
141: static void tv( int nx, PetscScalar *x, PetscScalar *y )
142: {
143:   PetscScalar dd, dl, du;
144:   int         j;

146:   dd  = 4.0;
147:   dl  = -1.0;
148:   du  = -1.0;

150:   y[0] =  dd*x[0] + du*x[1];
151:   for( j=1; j<nx-1; j++ )
152:     y[j] = dl*x[j-1] + dd*x[j] + du*x[j+1];
153:   y[nx-1] = dl*x[nx-2] + dd*x[nx-1];
154: }

158: /*
159:     Matrix-vector product subroutine for the 2D Laplacian.

161:     The matrix used is the 2 dimensional discrete Laplacian on unit square with
162:     zero Dirichlet boundary condition.
163:  
164:     Computes y <-- A*x, where A is the block tridiagonal matrix
165:  
166:                  | T -I          | 
167:                  |-I  T -I       |
168:              A = |   -I  T       |
169:                  |        ...  -I|
170:                  |           -I T|
171:  
172:     The subroutine TV is called to compute y<--T*x.
173:  */
174: int MatLaplacian2D_Mult( Mat A, Vec x, Vec y )
175: {
176:   void        *ctx;
177:   int         ierr, nx, lo, j, one=1;
178:   PetscScalar *px, *py, dmone=-1.0;
179: 
180:   MatShellGetContext( A, &ctx );
181:   nx = *(int *)ctx;
182:   VecGetArray( x, &px );
183:   VecGetArray( y, &py );

185:   tv( nx, &px[0], &py[0] );
186:   BLaxpy_( &nx, &dmone, &px[nx], &one, &py[0], &one );

188:   for( j=2; j<nx; j++ ) {
189:     lo = (j-1)*nx;
190:     tv( nx, &px[lo], &py[lo]);
191:     BLaxpy_( &nx, &dmone, &px[lo-nx], &one, &py[lo], &one );
192:     BLaxpy_( &nx, &dmone, &px[lo+nx], &one, &py[lo], &one );
193:   }

195:   lo = (nx-1)*nx;
196:   tv( nx, &px[lo], &py[lo]);
197:   BLaxpy_( &nx, &dmone, &px[lo-nx], &one, &py[lo], &one );

199:   VecRestoreArray( x, &px );
200:   VecRestoreArray( y, &py );

202:   return 0;
203: }