Actual source code: ex5.c

  1: /*$Id: ex5.c,v 1.73 2001/03/28 19:41:57 balay Exp $*/

  3: static char help[] = "Tests the multigrid code.  The input parameters are:n
  4:   -x N              Use a mesh in the x direction of N.  n
  5:   -c N              Use N V-cycles.  n
  6:   -l N              Use N Levels.  n
  7:   -smooths N        Use N pre smooths and N post smooths.  n
  8:   -j                Use Jacobi smoother.  n
  9:   -a use additive multigrid n
 10:   -f use full multigrid (preconditioner variant) n
 11: This example also demonstrates matrix-free methodsnn";

 13: /*
 14:   This is not a good example to understand the use of multigrid with PETSc.
 15: */
 16: #include "petscmg.h"

 18: int  residual(Mat,Vec,Vec,Vec);
 19: int  gauss_seidel(void *,Vec,Vec,Vec,int);
 20: int  jacobi(void *,Vec,Vec,Vec,int);
 21: int  interpolate(Mat,Vec,Vec,Vec);
 22: int  restrct(Mat,Vec,Vec);
 23: int  Create1dLaplacian(int,Mat*);
 24: int  CalculateRhs(Vec);
 25: int  CalculateError(Vec,Vec,Vec,double*);
 26: int  CalculateSolution(int,Vec*);
 27: int  amult(Mat,Vec,Vec);

 29: int main(int Argc,char **Args)
 30: {
 31:   int         x_mesh = 15,levels = 3,cycles = 1,use_jacobi = 0;
 32:   int         i,smooths = 1,*N;
 33:   int         ierr,its;
 34:   MGType      am = MGMULTIPLICATIVE;
 35:   Mat         cmat,mat[20],fmat;
 36:   SLES        csles,sles[20],slesmg;
 37:   double      e[3]; /* l_2 error,max error, residual */
 38:   char        *shellname;
 39:   Vec         x,solution,X[20],R[20],B[20];
 40:   Scalar      zero = 0.0;
 41:   KSP         ksp,kspmg;
 42:   PC          pcmg,pc;
 43:   PetscTruth  flg;

 45:   PetscInitialize(&Argc,&Args,(char *)0,help);

 47:   PetscOptionsGetInt(PETSC_NULL,"-x",&x_mesh,PETSC_NULL);
 48:   PetscOptionsGetInt(PETSC_NULL,"-l",&levels,PETSC_NULL);
 49:   PetscOptionsGetInt(PETSC_NULL,"-c",&cycles,PETSC_NULL);
 50:   PetscOptionsGetInt(PETSC_NULL,"-smooths",&smooths,PETSC_NULL);
 51:   PetscOptionsHasName(PETSC_NULL,"-a",&flg);
 52:   if (flg) {am = MGADDITIVE;}
 53:   PetscOptionsHasName(PETSC_NULL,"-f",&flg);
 54:   if (flg) {am = MGFULL;}
 55:   PetscOptionsHasName(PETSC_NULL,"-j",&flg);
 56:   if (flg) {use_jacobi = 1;}
 57: 
 58:   PetscMalloc(levels*sizeof(int),&N);
 59:   N[0] = x_mesh;
 60:   for (i=1; i<levels; i++) {
 61:     N[i] = N[i-1]/2;
 62:     if (N[i] < 1) {SETERRQ(1,"Too many levels");}
 63:   }

 65:   Create1dLaplacian(N[levels-1],&cmat);

 67:   SLESCreate(PETSC_COMM_WORLD,&slesmg);
 68:   SLESGetPC(slesmg,&pcmg);
 69:   SLESGetKSP(slesmg,&kspmg);
 70:   SLESSetFromOptions(slesmg);
 71:   PCSetType(pcmg,PCMG);
 72:   MGSetLevels(pcmg,levels,PETSC_NULL);
 73:   MGSetType(pcmg,am);

 75:   MGGetCoarseSolve(pcmg,&csles);
 76:   SLESSetOperators(csles,cmat,cmat,
 77:          DIFFERENT_NONZERO_PATTERN);
 78:   SLESGetPC(csles,&pc);
 79:   PCSetType(pc,PCLU);
 80:   SLESGetKSP(csles,&ksp);
 81:   KSPSetType(ksp,KSPPREONLY);

 83:   /* zero is finest level */
 84:   for (i=0; i<levels-1; i++) {
 85:     MGSetResidual(pcmg,levels - 1 - i,residual,(Mat)0);
 86:     MatCreateShell(PETSC_COMM_WORLD,N[i+1],N[i],N[i+1],N[i],(void *)0,&mat[i]);
 87:     MatShellSetOperation(mat[i],MATOP_MULT,(void(*)())restrct);
 88:     MatShellSetOperation(mat[i],MATOP_MULT_TRANSPOSE_ADD,(void(*)())interpolate);
 89:     MGSetInterpolate(pcmg,levels - 1 - i,mat[i]);
 90:     MGSetRestriction(pcmg,levels - 1 - i,mat[i]);
 91:     MGSetCyclesOnLevel(pcmg,levels - 1 - i,cycles);

 93:     /* set smoother */
 94:     MGGetSmoother(pcmg,levels - 1 - i,&sles[i]);
 95:     SLESGetPC(sles[i],&pc);
 96:     PCSetType(pc,PCSHELL);
 97:     PCShellSetName(pc,"user_precond");
 98:     PCShellGetName(pc,&shellname);
 99:     PetscPrintf(PETSC_COMM_WORLD,"level=%d, PCShell name is %sn",i,shellname);

101:     /* this is a dummy! since SLES requires a matrix passed in  */
102:     SLESSetOperators(sles[i],mat[i],mat[i],DIFFERENT_NONZERO_PATTERN);
103:     /* 
104:         We override the matrix passed in by forcint it to use Richardson with 
105:         a user provided application. This is non-standard and this practice
106:         should be avoided.
107:     */
108:     PCShellSetApplyRichardson(pc,gauss_seidel,(void *)0);
109:     if (use_jacobi) {
110:       PCShellSetApplyRichardson(pc,jacobi,(void *)0);
111:     }
112:     SLESGetKSP(sles[i],&ksp);
113:     KSPSetType(ksp,KSPRICHARDSON);
114:     KSPSetInitialGuessNonzero(ksp);
115:     KSPSetTolerances(ksp,PETSC_DEFAULT,PETSC_DEFAULT,
116:                             PETSC_DEFAULT,smooths);

118:     VecCreateSeq(PETSC_COMM_SELF,N[i],&x);
119:     X[levels - 1 - i] = x;
120:     MGSetX(pcmg,levels - 1 - i,x);
121:     VecCreateSeq(PETSC_COMM_SELF,N[i],&x);
122:     B[levels -1 - i] = x;
123:     MGSetRhs(pcmg,levels - 1 - i,x);
124:     VecCreateSeq(PETSC_COMM_SELF,N[i],&x);
125:     R[levels - 1 - i] = x;
126:     MGSetR(pcmg,levels - 1 - i,x);
127:   }
128:   /* create coarse level vectors */
129:   VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x);
130:   MGSetX(pcmg,0,x); X[0] = x;
131:   VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x);
132:   MGSetRhs(pcmg,0,x); B[0] = x;
133:   VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x);
134:   MGSetR(pcmg,0,x); R[0] = x;

136:   /* create matrix multiply for finest level */
137:   MatCreateShell(PETSC_COMM_WORLD,N[0],N[0],N[0],N[0],(void *)0,&fmat);
138:   MatShellSetOperation(fmat,MATOP_MULT,(void(*)())amult);
139:   SLESSetOperators(slesmg,fmat,fmat,DIFFERENT_NONZERO_PATTERN);

141:   CalculateSolution(N[0],&solution);
142:   CalculateRhs(B[levels-1]);
143:   VecSet(&zero,X[levels-1]);

145:   if (MGCheck(pcmg)) {SETERRQ(1,0);}
146: 
147:   residual((Mat)0,B[levels-1],X[levels-1],R[levels-1]);
148:   CalculateError(solution,X[levels-1],R[levels-1],e);
149:   PetscPrintf(PETSC_COMM_SELF,"l_2 error %g max error %g resi %gn",e[0],e[1],e[2]);

151:   SLESSolve(slesmg,B[levels-1],X[levels-1],&its);
152:   residual((Mat)0,B[levels-1],X[levels-1],R[levels-1]);
153:   CalculateError(solution,X[levels-1],R[levels-1],e);
154:   PetscPrintf(PETSC_COMM_SELF,"its %d l_2 error %g max error %g resi %gn",its,e[0],e[1],e[2]);

156:   PetscFree(N);
157:   VecDestroy(solution);

159:   /* note we have to keep a list of all vectors allocated, this is 
160:      not ideal, but putting it in MGDestroy is not so good either*/
161:   for (i=0; i<levels; i++) {
162:     VecDestroy(X[i]);
163:     VecDestroy(B[i]);
164:     VecDestroy(R[i]);
165:   }
166:   for (i=0; i<levels-1; i++) {
167:     MatDestroy(mat[i]);
168:   }
169:   MatDestroy(cmat);
170:   MatDestroy(fmat);
171:   SLESDestroy(slesmg);
172:   PetscFinalize();
173:   return 0;
174: }

176: /* --------------------------------------------------------------------- */
177: int residual(Mat mat,Vec bb,Vec xx,Vec rr)
178: {
179:   int    i,n1,ierr;
180:   Scalar *b,*x,*r;

182:   VecGetSize(bb,&n1);
183:   VecGetArray(bb,&b);
184:   VecGetArray(xx,&x);
185:   VecGetArray(rr,&r);
186:   n1--;
187:   r[0] = b[0] + x[1] - 2.0*x[0];
188:   r[n1] = b[n1] + x[n1-1] - 2.0*x[n1];
189:   for (i=1; i<n1; i++) {
190:     r[i] = b[i] + x[i+1] + x[i-1] - 2.0*x[i];
191:   }
192:   VecRestoreArray(bb,&b);
193:   VecRestoreArray(xx,&x);
194:   VecRestoreArray(rr,&r);
195:   return 0;
196: }
197: int amult(Mat mat,Vec xx,Vec yy)
198: {
199:   int    i,n1,ierr;
200:   Scalar *y,*x;

202:   VecGetSize(xx,&n1);
203:   VecGetArray(xx,&x);
204:   VecGetArray(yy,&y);
205:   n1--;
206:   y[0] =  -x[1] + 2.0*x[0];
207:   y[n1] = -x[n1-1] + 2.0*x[n1];
208:   for (i=1; i<n1; i++) {
209:     y[i] = -x[i+1] - x[i-1] + 2.0*x[i];
210:   }
211:   VecRestoreArray(xx,&x);
212:   VecRestoreArray(yy,&y);
213:   return 0;
214: }
215: /* --------------------------------------------------------------------- */
216: int gauss_seidel(void *ptr,Vec bb,Vec xx,Vec w,int m)
217: {
218:   int    i,n1,ierr;
219:   Scalar *x,*b;

221:   VecGetSize(bb,&n1); n1--;
222:   VecGetArray(bb,&b);
223:   VecGetArray(xx,&x);
224:   while (m--) {
225:     x[0] =  .5*(x[1] + b[0]);
226:     for (i=1; i<n1; i++) {
227:       x[i] = .5*(x[i+1] + x[i-1] + b[i]);
228:     }
229:     x[n1] = .5*(x[n1-1] + b[n1]);
230:     for (i=n1-1; i>0; i--) {
231:       x[i] = .5*(x[i+1] + x[i-1] + b[i]);
232:     }
233:     x[0] =  .5*(x[1] + b[0]);
234:   }
235:   VecRestoreArray(bb,&b);
236:   VecRestoreArray(xx,&x);
237:   return 0;
238: }
239: /* --------------------------------------------------------------------- */
240: int jacobi(void *ptr,Vec bb,Vec xx,Vec w,int m)
241: {
242:   int      i,n,n1,ierr;
243:   Scalar   *r,*b,*x;

245:   VecGetSize(bb,&n); n1 = n - 1;
246:   VecGetArray(bb,&b);
247:   VecGetArray(xx,&x);
248:   VecGetArray(w,&r);

250:   while (m--) {
251:     r[0] = .5*(x[1] + b[0]);
252:     for (i=1; i<n1; i++) {
253:        r[i] = .5*(x[i+1] + x[i-1] + b[i]);
254:     }
255:     r[n1] = .5*(x[n1-1] + b[n1]);
256:     for (i=0; i<n; i++) x[i] = (2.0*r[i] + x[i])/3.0;
257:   }
258:   VecRestoreArray(bb,&b);
259:   VecRestoreArray(xx,&x);
260:   VecRestoreArray(w,&r);
261:   return 0;
262: }
263: /*
264:    We know for this application that yy  and zz are the same
265: */
266: /* --------------------------------------------------------------------- */
267: int interpolate(Mat mat,Vec xx,Vec yy,Vec zz)
268: {
269:   int    i,n,N,i2,ierr;
270:   Scalar *x,*y;

272:   VecGetSize(yy,&N);
273:   VecGetArray(xx,&x);
274:   VecGetArray(yy,&y);
275:   n = N/2;
276:   for (i=0; i<n; i++) {
277:     i2 = 2*i;
278:     y[i2] +=  .5*x[i];
279:     y[i2+1] +=  x[i];
280:     y[i2+2] +=  .5*x[i];
281:   }
282:   VecRestoreArray(xx,&x);
283:   VecRestoreArray(yy,&y);
284:   return 0;
285: }
286: /* --------------------------------------------------------------------- */
287: int restrct(Mat mat,Vec rr,Vec bb)
288: {
289:   int    i,n,N,i2,ierr;
290:   Scalar *r,*b;

292:   VecGetSize(rr,&N);
293:   VecGetArray(rr,&r);
294:   VecGetArray(bb,&b);
295:   n = N/2;

297:   for (i=0; i<n; i++) {
298:     i2 = 2*i;
299:     b[i] = (r[i2] + 2.0*r[i2+1] + r[i2+2]);
300:   }
301:   VecRestoreArray(rr,&r);
302:   VecRestoreArray(bb,&b);
303:   return 0;
304: }
305: /* --------------------------------------------------------------------- */
306: int Create1dLaplacian(int n,Mat *mat)
307: {
308:   Scalar mone = -1.0,two = 2.0;
309:   int    ierr,i,idx;

311:   MatCreateSeqAIJ(PETSC_COMM_SELF,n,n,3,PETSC_NULL,mat);
312: 
313:   idx= n-1;
314:   MatSetValues(*mat,1,&idx,1,&idx,&two,INSERT_VALUES);
315:   for (i=0; i<n-1; i++) {
316:     MatSetValues(*mat,1,&i,1,&i,&two,INSERT_VALUES);
317:     idx = i+1;
318:     MatSetValues(*mat,1,&idx,1,&i,&mone,INSERT_VALUES);
319:     MatSetValues(*mat,1,&i,1,&idx,&mone,INSERT_VALUES);
320:   }
321:   MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);
322:   MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);
323:   return 0;
324: }
325: /* --------------------------------------------------------------------- */
326: int CalculateRhs(Vec u)
327: {
328:   int    i,n,ierr;
329:   double h,x = 0.0;
330:   Scalar uu;
331:   VecGetSize(u,&n);
332:   h = 1.0/((double)(n+1));
333:   for (i=0; i<n; i++) {
334:     x += h; uu = 2.0*h*h;
335:     VecSetValues(u,1,&i,&uu,INSERT_VALUES);
336:   }

338:   return 0;
339: }
340: /* --------------------------------------------------------------------- */
341: int CalculateSolution(int n,Vec *solution)
342: {
343:   int    i,ierr;
344:   double h,x = 0.0;
345:   Scalar uu;
346:   VecCreateSeq(PETSC_COMM_SELF,n,solution);
347:   h = 1.0/((double)(n+1));
348:   for (i=0; i<n; i++) {
349:     x += h; uu = x*(1.-x);
350:     VecSetValues(*solution,1,&i,&uu,INSERT_VALUES);
351:   }
352:   return 0;
353: }
354: /* --------------------------------------------------------------------- */
355: int CalculateError(Vec solution,Vec u,Vec r,double *e)
356: {
357:   Scalar mone = -1.0;
358:   int    ierr;

360:   VecNorm(r,NORM_2,e+2);
361:   VecWAXPY(&mone,u,solution,r);
362:   VecNorm(r,NORM_2,e);
363:   VecNorm(r,NORM_1,e+1);
364:   return 0;
365: }