Actual source code: ex5.c

  1: /*$Id: ex5.c,v 1.76 2001/08/07 21:30:37 bsmith 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,PetscReal,PetscReal,PetscReal,int);
 20: int  jacobi(void *,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal,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,PetscReal*);
 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:   PetscReal   e[3]; /* l_2 error,max error, residual */
 38:   char        *shellname;
 39:   Vec         x,solution,X[20],R[20],B[20];
 40:   PetscScalar 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,DIFFERENT_NONZERO_PATTERN);
 77:   SLESGetPC(csles,&pc);
 78:   PCSetType(pc,PCLU);
 79:   SLESGetKSP(csles,&ksp);
 80:   KSPSetType(ksp,KSPPREONLY);

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

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

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

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

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

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

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

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

154:   PetscFree(N);
155:   VecDestroy(solution);

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

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

181:   VecGetSize(bb,&n1);
182:   VecGetArray(bb,&b);
183:   VecGetArray(xx,&x);
184:   VecGetArray(rr,&r);
185:   n1--;
186:   r[0] = b[0] + x[1] - 2.0*x[0];
187:   r[n1] = b[n1] + x[n1-1] - 2.0*x[n1];
188:   for (i=1; i<n1; i++) {
189:     r[i] = b[i] + x[i+1] + x[i-1] - 2.0*x[i];
190:   }
191:   VecRestoreArray(bb,&b);
192:   VecRestoreArray(xx,&x);
193:   VecRestoreArray(rr,&r);
194:   return(0);
195: }
196: int amult(Mat mat,Vec xx,Vec yy)
197: {
198:   int         i,n1,ierr;
199:   PetscScalar *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,PetscReal rtol,PetscReal atol,PetscReal dtol,int m)
217: {
218:   int         i,n1,ierr;
219:   PetscScalar *x,*b;

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

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

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

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

296:   VecGetSize(rr,&N);
297:   VecGetArray(rr,&r);
298:   VecGetArray(bb,&b);
299:   n = N/2;

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

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

338:   VecGetSize(u,&n);
339:   h = 1.0/((PetscReal)(n+1));
340:   for (i=0; i<n; i++) {
341:     x += h; uu = 2.0*h*h;
342:     VecSetValues(u,1,&i,&uu,INSERT_VALUES);
343:   }

345:   return(0);
346: }
347: /* --------------------------------------------------------------------- */
348: int CalculateSolution(int n,Vec *solution)
349: {
350:   int         i,ierr;
351:   PetscReal   h,x = 0.0;
352:   PetscScalar uu;

355:   VecCreateSeq(PETSC_COMM_SELF,n,solution);
356:   h = 1.0/((PetscReal)(n+1));
357:   for (i=0; i<n; i++) {
358:     x += h; uu = x*(1.-x);
359:     VecSetValues(*solution,1,&i,&uu,INSERT_VALUES);
360:   }
361:   return(0);
362: }
363: /* --------------------------------------------------------------------- */
364: int CalculateError(Vec solution,Vec u,Vec r,PetscReal *e)
365: {
366:   PetscScalar mone = -1.0;
367:   int    ierr;

370:   VecNorm(r,NORM_2,e+2);
371:   VecWAXPY(&mone,u,solution,r);
372:   VecNorm(r,NORM_2,e);
373:   VecNorm(r,NORM_1,e+1);
374:   return(0);
375: }