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: }