Actual source code: ex5.c
2: static char help[] = "Tests the multigrid code. The input parameters are:\n\
3: -x N Use a mesh in the x direction of N. \n\
4: -c N Use N V-cycles. \n\
5: -l N Use N Levels. \n\
6: -smooths N Use N pre smooths and N post smooths. \n\
7: -j Use Jacobi smoother. \n\
8: -a use additive multigrid \n\
9: -f use full multigrid (preconditioner variant) \n\
10: This example also demonstrates matrix-free methods\n\n";
12: /*
13: This is not a good example to understand the use of multigrid with PETSc.
14: */
15: #include petscmg.h
17: PetscErrorCode residual(Mat,Vec,Vec,Vec);
18: PetscErrorCode gauss_seidel(void*,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal,PetscInt);
19: PetscErrorCode jacobi(void*,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal,PetscInt);
20: PetscErrorCode interpolate(Mat,Vec,Vec,Vec);
21: PetscErrorCode restrct(Mat,Vec,Vec);
22: PetscErrorCode Create1dLaplacian(PetscInt,Mat*);
23: PetscErrorCode CalculateRhs(Vec);
24: PetscErrorCode CalculateError(Vec,Vec,Vec,PetscReal*);
25: PetscErrorCode CalculateSolution(PetscInt,Vec*);
26: PetscErrorCode amult(Mat,Vec,Vec);
30: int main(int Argc,char **Args)
31: {
32: PetscInt x_mesh = 15,levels = 3,cycles = 1,use_jacobi = 0;
33: PetscInt i,smooths = 1,*N,its;
34: PetscErrorCode ierr;
35: PCMGType am = PC_MG_MULTIPLICATIVE;
36: Mat cmat,mat[20],fmat;
37: KSP cksp,ksp[20],kspmg;
38: PetscReal e[3]; /* l_2 error,max error, residual */
39: char *shellname;
40: Vec x,solution,X[20],R[20],B[20];
41: PetscScalar zero = 0.0;
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 = PC_MG_ADDITIVE;}
53: PetscOptionsHasName(PETSC_NULL,"-f",&flg);
54: if (flg) {am = PC_MG_FULL;}
55: PetscOptionsHasName(PETSC_NULL,"-j",&flg);
56: if (flg) {use_jacobi = 1;}
57:
58: PetscMalloc(levels*sizeof(PetscInt),&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: KSPCreate(PETSC_COMM_WORLD,&kspmg);
68: KSPGetPC(kspmg,&pcmg);
69: KSPSetFromOptions(kspmg);
70: PCSetType(pcmg,PCMG);
71: PCMGSetLevels(pcmg,levels,PETSC_NULL);
72: PCMGSetType(pcmg,am);
74: PCMGGetCoarseSolve(pcmg,&cksp);
75: KSPSetOperators(cksp,cmat,cmat,DIFFERENT_NONZERO_PATTERN);
76: KSPGetPC(cksp,&pc);
77: PCSetType(pc,PCLU);
78: KSPSetType(cksp,KSPPREONLY);
80: /* zero is finest level */
81: for (i=0; i<levels-1; i++) {
82: PCMGSetResidual(pcmg,levels - 1 - i,residual,(Mat)0);
83: MatCreateShell(PETSC_COMM_WORLD,N[i+1],N[i],N[i+1],N[i],(void*)0,&mat[i]);
84: MatShellSetOperation(mat[i],MATOP_MULT,(void(*)(void))restrct);
85: MatShellSetOperation(mat[i],MATOP_MULT_TRANSPOSE_ADD,(void(*)(void))interpolate);
86: PCMGSetInterpolate(pcmg,levels - 1 - i,mat[i]);
87: PCMGSetRestriction(pcmg,levels - 1 - i,mat[i]);
88: PCMGSetCyclesOnLevel(pcmg,levels - 1 - i,cycles);
90: /* set smoother */
91: PCMGGetSmoother(pcmg,levels - 1 - i,&ksp[i]);
92: KSPGetPC(ksp[i],&pc);
93: PCSetType(pc,PCSHELL);
94: PCShellSetName(pc,"user_precond");
95: PCShellGetName(pc,&shellname);
96: PetscPrintf(PETSC_COMM_WORLD,"level=%D, PCShell name is %s\n",i,shellname);
98: /* this is a dummy! since KSP requires a matrix passed in */
99: KSPSetOperators(ksp[i],mat[i],mat[i],DIFFERENT_NONZERO_PATTERN);
100: /*
101: We override the matrix passed in by forcing it to use Richardson with
102: a user provided application. This is non-standard and this practice
103: should be avoided.
104: */
105: PCShellSetApplyRichardson(pc,gauss_seidel);
106: if (use_jacobi) {
107: PCShellSetApplyRichardson(pc,jacobi);
108: }
109: KSPSetType(ksp[i],KSPRICHARDSON);
110: KSPSetInitialGuessNonzero(ksp[i],PETSC_TRUE);
111: KSPSetTolerances(ksp[i],PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,smooths);
113: VecCreateSeq(PETSC_COMM_SELF,N[i],&x);
114: X[levels - 1 - i] = x;
115: if (i > 0) {
116: PCMGSetX(pcmg,levels - 1 - i,x);
117: }
118: VecCreateSeq(PETSC_COMM_SELF,N[i],&x);
119: B[levels -1 - i] = x;
120: if (i > 0) {
121: PCMGSetRhs(pcmg,levels - 1 - i,x);
122: }
123: VecCreateSeq(PETSC_COMM_SELF,N[i],&x);
124: R[levels - 1 - i] = x;
125: PCMGSetR(pcmg,levels - 1 - i,x);
126: }
127: /* create coarse level vectors */
128: VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x);
129: PCMGSetX(pcmg,0,x); X[0] = x;
130: VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x);
131: PCMGSetRhs(pcmg,0,x); B[0] = x;
133: /* create matrix multiply for finest level */
134: MatCreateShell(PETSC_COMM_WORLD,N[0],N[0],N[0],N[0],(void*)0,&fmat);
135: MatShellSetOperation(fmat,MATOP_MULT,(void(*)(void))amult);
136: KSPSetOperators(kspmg,fmat,fmat,DIFFERENT_NONZERO_PATTERN);
138: CalculateSolution(N[0],&solution);
139: CalculateRhs(B[levels-1]);
140: VecSet(X[levels-1],zero);
142: residual((Mat)0,B[levels-1],X[levels-1],R[levels-1]);
143: CalculateError(solution,X[levels-1],R[levels-1],e);
144: PetscPrintf(PETSC_COMM_SELF,"l_2 error %g max error %g resi %g\n",e[0],e[1],e[2]);
146: KSPSolve(kspmg,B[levels-1],X[levels-1]);
147: KSPGetIterationNumber(kspmg,&its);
148: residual((Mat)0,B[levels-1],X[levels-1],R[levels-1]);
149: CalculateError(solution,X[levels-1],R[levels-1],e);
150: PetscPrintf(PETSC_COMM_SELF,"its %D l_2 error %g max error %g resi %g\n",its,e[0],e[1],e[2]);
152: PetscFree(N);
153: VecDestroy(solution);
155: /* note we have to keep a list of all vectors allocated, this is
156: not ideal, but putting it in MGDestroy is not so good either*/
157: for (i=0; i<levels; i++) {
158: VecDestroy(X[i]);
159: VecDestroy(B[i]);
160: if(i){VecDestroy(R[i]);}
161: }
162: for (i=0; i<levels-1; i++) {
163: MatDestroy(mat[i]);
164: }
165: MatDestroy(cmat);
166: MatDestroy(fmat);
167: KSPDestroy(kspmg);
168: PetscFinalize();
169: return 0;
170: }
172: /* --------------------------------------------------------------------- */
175: PetscErrorCode residual(Mat mat,Vec bb,Vec xx,Vec rr)
176: {
177: PetscInt i,n1;
179: PetscScalar *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: }
199: PetscErrorCode amult(Mat mat,Vec xx,Vec yy)
200: {
201: PetscInt i,n1;
203: PetscScalar *y,*x;
206: VecGetSize(xx,&n1);
207: VecGetArray(xx,&x);
208: VecGetArray(yy,&y);
209: n1--;
210: y[0] = -x[1] + 2.0*x[0];
211: y[n1] = -x[n1-1] + 2.0*x[n1];
212: for (i=1; i<n1; i++) {
213: y[i] = -x[i+1] - x[i-1] + 2.0*x[i];
214: }
215: VecRestoreArray(xx,&x);
216: VecRestoreArray(yy,&y);
217: return(0);
218: }
219: /* --------------------------------------------------------------------- */
222: PetscErrorCode gauss_seidel(void *ptr,Vec bb,Vec xx,Vec w,PetscReal rtol,PetscReal abstol,PetscReal dtol,PetscInt m)
223: {
224: PetscInt i,n1;
226: PetscScalar *x,*b;
229: VecGetSize(bb,&n1); n1--;
230: VecGetArray(bb,&b);
231: VecGetArray(xx,&x);
232: while (m--) {
233: x[0] = .5*(x[1] + b[0]);
234: for (i=1; i<n1; i++) {
235: x[i] = .5*(x[i+1] + x[i-1] + b[i]);
236: }
237: x[n1] = .5*(x[n1-1] + b[n1]);
238: for (i=n1-1; i>0; i--) {
239: x[i] = .5*(x[i+1] + x[i-1] + b[i]);
240: }
241: x[0] = .5*(x[1] + b[0]);
242: }
243: VecRestoreArray(bb,&b);
244: VecRestoreArray(xx,&x);
245: return(0);
246: }
247: /* --------------------------------------------------------------------- */
250: PetscErrorCode jacobi(void *ptr,Vec bb,Vec xx,Vec w,PetscReal rtol,PetscReal abstol,PetscReal dtol,PetscInt m)
251: {
252: PetscInt i,n,n1;
254: PetscScalar *r,*b,*x;
257: VecGetSize(bb,&n); n1 = n - 1;
258: VecGetArray(bb,&b);
259: VecGetArray(xx,&x);
260: VecGetArray(w,&r);
262: while (m--) {
263: r[0] = .5*(x[1] + b[0]);
264: for (i=1; i<n1; i++) {
265: r[i] = .5*(x[i+1] + x[i-1] + b[i]);
266: }
267: r[n1] = .5*(x[n1-1] + b[n1]);
268: for (i=0; i<n; i++) x[i] = (2.0*r[i] + x[i])/3.0;
269: }
270: VecRestoreArray(bb,&b);
271: VecRestoreArray(xx,&x);
272: VecRestoreArray(w,&r);
273: return(0);
274: }
275: /*
276: We know for this application that yy and zz are the same
277: */
278: /* --------------------------------------------------------------------- */
281: PetscErrorCode interpolate(Mat mat,Vec xx,Vec yy,Vec zz)
282: {
283: PetscInt i,n,N,i2;
285: PetscScalar *x,*y;
288: VecGetSize(yy,&N);
289: VecGetArray(xx,&x);
290: VecGetArray(yy,&y);
291: n = N/2;
292: for (i=0; i<n; i++) {
293: i2 = 2*i;
294: y[i2] += .5*x[i];
295: y[i2+1] += x[i];
296: y[i2+2] += .5*x[i];
297: }
298: VecRestoreArray(xx,&x);
299: VecRestoreArray(yy,&y);
300: return(0);
301: }
302: /* --------------------------------------------------------------------- */
305: PetscErrorCode restrct(Mat mat,Vec rr,Vec bb)
306: {
307: PetscInt i,n,N,i2;
309: PetscScalar *r,*b;
312: VecGetSize(rr,&N);
313: VecGetArray(rr,&r);
314: VecGetArray(bb,&b);
315: n = N/2;
317: for (i=0; i<n; i++) {
318: i2 = 2*i;
319: b[i] = (r[i2] + 2.0*r[i2+1] + r[i2+2]);
320: }
321: VecRestoreArray(rr,&r);
322: VecRestoreArray(bb,&b);
323: return(0);
324: }
325: /* --------------------------------------------------------------------- */
328: PetscErrorCode Create1dLaplacian(PetscInt n,Mat *mat)
329: {
330: PetscScalar mone = -1.0,two = 2.0;
331: PetscInt i,idx;
335: MatCreateSeqAIJ(PETSC_COMM_SELF,n,n,3,PETSC_NULL,mat);
336:
337: idx= n-1;
338: MatSetValues(*mat,1,&idx,1,&idx,&two,INSERT_VALUES);
339: for (i=0; i<n-1; i++) {
340: MatSetValues(*mat,1,&i,1,&i,&two,INSERT_VALUES);
341: idx = i+1;
342: MatSetValues(*mat,1,&idx,1,&i,&mone,INSERT_VALUES);
343: MatSetValues(*mat,1,&i,1,&idx,&mone,INSERT_VALUES);
344: }
345: MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);
346: MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);
347: return(0);
348: }
349: /* --------------------------------------------------------------------- */
352: PetscErrorCode CalculateRhs(Vec u)
353: {
355: PetscInt i,n;
356: PetscReal h,x = 0.0;
357: PetscScalar uu;
360: VecGetSize(u,&n);
361: h = 1.0/((PetscReal)(n+1));
362: for (i=0; i<n; i++) {
363: x += h; uu = 2.0*h*h;
364: VecSetValues(u,1,&i,&uu,INSERT_VALUES);
365: }
367: return(0);
368: }
369: /* --------------------------------------------------------------------- */
372: PetscErrorCode CalculateSolution(PetscInt n,Vec *solution)
373: {
375: PetscInt i;
376: PetscReal h,x = 0.0;
377: PetscScalar uu;
380: VecCreateSeq(PETSC_COMM_SELF,n,solution);
381: h = 1.0/((PetscReal)(n+1));
382: for (i=0; i<n; i++) {
383: x += h; uu = x*(1.-x);
384: VecSetValues(*solution,1,&i,&uu,INSERT_VALUES);
385: }
386: return(0);
387: }
388: /* --------------------------------------------------------------------- */
391: PetscErrorCode CalculateError(Vec solution,Vec u,Vec r,PetscReal *e)
392: {
393: PetscScalar mone = -1.0;
397: VecNorm(r,NORM_2,e+2);
398: VecWAXPY(r,mone,u,solution);
399: VecNorm(r,NORM_2,e);
400: VecNorm(r,NORM_1,e+1);
401: return(0);
402: }