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