Actual source code: ex5.c
petsc-3.8.3 2017-12-09
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 <petscksp.h>
17: PetscErrorCode residual(Mat,Vec,Vec,Vec);
18: PetscErrorCode gauss_seidel(PC,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal,PetscInt,PetscBool,PetscInt*,PCRichardsonConvergedReason*);
19: PetscErrorCode jacobi(PC,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal,PetscInt,PetscBool,PetscInt*,PCRichardsonConvergedReason*);
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);
28: int main(int Argc,char **Args)
29: {
30: PetscInt x_mesh = 15,levels = 3,cycles = 1,use_jacobi = 0;
31: PetscInt i,smooths = 1,*N,its;
33: PCMGType am = PC_MG_MULTIPLICATIVE;
34: Mat cmat,mat[20],fmat;
35: KSP cksp,ksp[20],kspmg;
36: PetscReal e[3]; /* l_2 error,max error, residual */
37: const char *shellname;
38: Vec x,solution,X[20],R[20],B[20];
39: PC pcmg,pc;
40: PetscBool flg;
42: PetscInitialize(&Argc,&Args,(char*)0,help);if (ierr) return ierr;
43: PetscOptionsGetInt(NULL,NULL,"-x",&x_mesh,NULL);
44: PetscOptionsGetInt(NULL,NULL,"-l",&levels,NULL);
45: PetscOptionsGetInt(NULL,NULL,"-c",&cycles,NULL);
46: PetscOptionsGetInt(NULL,NULL,"-smooths",&smooths,NULL);
47: PetscOptionsHasName(NULL,NULL,"-a",&flg);
49: if (flg) am = PC_MG_ADDITIVE;
50: PetscOptionsHasName(NULL,NULL,"-f",&flg);
51: if (flg) am = PC_MG_FULL;
52: PetscOptionsHasName(NULL,NULL,"-j",&flg);
53: if (flg) use_jacobi = 1;
55: PetscMalloc1(levels,&N);
56: N[0] = x_mesh;
57: for (i=1; i<levels; i++) {
58: N[i] = N[i-1]/2;
59: if (N[i] < 1) SETERRQ(PETSC_COMM_WORLD,1,"Too many levels");
60: }
62: Create1dLaplacian(N[levels-1],&cmat);
64: KSPCreate(PETSC_COMM_WORLD,&kspmg);
65: KSPGetPC(kspmg,&pcmg);
66: KSPSetFromOptions(kspmg);
67: PCSetType(pcmg,PCMG);
68: PCMGSetLevels(pcmg,levels,NULL);
69: PCMGSetType(pcmg,am);
71: PCMGGetCoarseSolve(pcmg,&cksp);
72: KSPSetOperators(cksp,cmat,cmat);
73: KSPGetPC(cksp,&pc);
74: PCSetType(pc,PCLU);
75: KSPSetType(cksp,KSPPREONLY);
77: /* zero is finest level */
78: for (i=0; i<levels-1; i++) {
79: PCMGSetResidual(pcmg,levels - 1 - i,residual,(Mat)0);
80: MatCreateShell(PETSC_COMM_WORLD,N[i+1],N[i],N[i+1],N[i],(void*)0,&mat[i]);
81: MatShellSetOperation(mat[i],MATOP_MULT,(void (*)(void))restrct);
82: MatShellSetOperation(mat[i],MATOP_MULT_TRANSPOSE_ADD,(void (*)(void))interpolate);
83: PCMGSetInterpolation(pcmg,levels - 1 - i,mat[i]);
84: PCMGSetRestriction(pcmg,levels - 1 - i,mat[i]);
85: PCMGSetCycleTypeOnLevel(pcmg,levels - 1 - i,(PCMGCycleType)cycles);
87: /* set smoother */
88: PCMGGetSmoother(pcmg,levels - 1 - i,&ksp[i]);
89: KSPGetPC(ksp[i],&pc);
90: PCSetType(pc,PCSHELL);
91: PCShellSetName(pc,"user_precond");
92: PCShellGetName(pc,&shellname);
93: PetscPrintf(PETSC_COMM_WORLD,"level=%D, PCShell name is %s\n",i,shellname);
95: /* this is a dummy! since KSP requires a matrix passed in */
96: KSPSetOperators(ksp[i],mat[i],mat[i]);
97: /*
98: We override the matrix passed in by forcing it to use Richardson with
99: a user provided application. This is non-standard and this practice
100: should be avoided.
101: */
102: PCShellSetApplyRichardson(pc,gauss_seidel);
103: if (use_jacobi) {
104: PCShellSetApplyRichardson(pc,jacobi);
105: }
106: KSPSetType(ksp[i],KSPRICHARDSON);
107: KSPSetInitialGuessNonzero(ksp[i],PETSC_TRUE);
108: KSPSetTolerances(ksp[i],PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,smooths);
110: VecCreateSeq(PETSC_COMM_SELF,N[i],&x);
112: X[levels - 1 - i] = x;
113: if (i > 0) {
114: PCMGSetX(pcmg,levels - 1 - i,x);
115: }
116: VecCreateSeq(PETSC_COMM_SELF,N[i],&x);
118: B[levels -1 - i] = x;
119: if (i > 0) {
120: PCMGSetRhs(pcmg,levels - 1 - i,x);
121: }
122: VecCreateSeq(PETSC_COMM_SELF,N[i],&x);
124: R[levels - 1 - i] = x;
126: PCMGSetR(pcmg,levels - 1 - i,x);
127: }
128: /* create coarse level vectors */
129: VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x);
130: PCMGSetX(pcmg,0,x); X[0] = x;
131: VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x);
132: PCMGSetRhs(pcmg,0,x); B[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: KSPSetOperators(kspmg,fmat,fmat);
139: CalculateSolution(N[0],&solution);
140: CalculateRhs(B[levels-1]);
141: VecSet(X[levels-1],0.0);
143: residual((Mat)0,B[levels-1],X[levels-1],R[levels-1]);
144: CalculateError(solution,X[levels-1],R[levels-1],e);
145: PetscPrintf(PETSC_COMM_SELF,"l_2 error %g max error %g resi %g\n",(double)e[0],(double)e[1],(double)e[2]);
147: KSPSolve(kspmg,B[levels-1],X[levels-1]);
148: KSPGetIterationNumber(kspmg,&its);
149: residual((Mat)0,B[levels-1],X[levels-1],R[levels-1]);
150: CalculateError(solution,X[levels-1],R[levels-1],e);
151: PetscPrintf(PETSC_COMM_SELF,"its %D l_2 error %g max error %g resi %g\n",its,(double)e[0],(double)e[1],(double)e[2]);
153: PetscFree(N);
154: VecDestroy(&solution);
156: /* note we have to keep a list of all vectors allocated, this is
157: not ideal, but putting it in MGDestroy is not so good either*/
158: for (i=0; i<levels; i++) {
159: VecDestroy(&X[i]);
160: VecDestroy(&B[i]);
161: if (i) {VecDestroy(&R[i]);}
162: }
163: for (i=0; i<levels-1; i++) {
164: MatDestroy(&mat[i]);
165: }
166: MatDestroy(&cmat);
167: MatDestroy(&fmat);
168: KSPDestroy(&kspmg);
169: PetscFinalize();
170: return ierr;
171: }
173: /* --------------------------------------------------------------------- */
174: PetscErrorCode residual(Mat mat,Vec bb,Vec xx,Vec rr)
175: {
176: PetscInt i,n1;
177: PetscErrorCode ierr;
178: PetscScalar *x,*r;
179: const PetscScalar *b;
182: VecGetSize(bb,&n1);
183: VecGetArrayRead(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++) r[i] = b[i] + x[i+1] + x[i-1] - 2.0*x[i];
190: VecRestoreArrayRead(bb,&b);
191: VecRestoreArray(xx,&x);
192: VecRestoreArray(rr,&r);
193: return(0);
194: }
195: PetscErrorCode amult(Mat mat,Vec xx,Vec yy)
196: {
197: PetscInt i,n1;
198: PetscErrorCode ierr;
199: PetscScalar *y;
200: const PetscScalar *x;
203: VecGetSize(xx,&n1);
204: VecGetArrayRead(xx,&x);
205: VecGetArray(yy,&y);
206: n1--;
207: y[0] = -x[1] + 2.0*x[0];
208: y[n1] = -x[n1-1] + 2.0*x[n1];
209: for (i=1; i<n1; i++) y[i] = -x[i+1] - x[i-1] + 2.0*x[i];
210: VecRestoreArrayRead(xx,&x);
211: VecRestoreArray(yy,&y);
212: return(0);
213: }
214: /* --------------------------------------------------------------------- */
215: PetscErrorCode gauss_seidel(PC pc,Vec bb,Vec xx,Vec w,PetscReal rtol,PetscReal abstol,PetscReal dtol,PetscInt m,PetscBool guesszero,PetscInt *its,PCRichardsonConvergedReason *reason)
216: {
217: PetscInt i,n1;
218: PetscErrorCode ierr;
219: PetscScalar *x;
220: const PetscScalar *b;
223: *its = m;
224: *reason = PCRICHARDSON_CONVERGED_ITS;
225: VecGetSize(bb,&n1); n1--;
226: VecGetArrayRead(bb,&b);
227: VecGetArray(xx,&x);
228: while (m--) {
229: x[0] = .5*(x[1] + b[0]);
230: for (i=1; i<n1; i++) x[i] = .5*(x[i+1] + x[i-1] + b[i]);
231: x[n1] = .5*(x[n1-1] + b[n1]);
232: for (i=n1-1; i>0; i--) x[i] = .5*(x[i+1] + x[i-1] + b[i]);
233: x[0] = .5*(x[1] + b[0]);
234: }
235: VecRestoreArrayRead(bb,&b);
236: VecRestoreArray(xx,&x);
237: return(0);
238: }
239: /* --------------------------------------------------------------------- */
240: PetscErrorCode jacobi(PC pc,Vec bb,Vec xx,Vec w,PetscReal rtol,PetscReal abstol,PetscReal dtol,PetscInt m,PetscBool guesszero,PetscInt *its,PCRichardsonConvergedReason *reason)
241: {
242: PetscInt i,n,n1;
243: PetscErrorCode ierr;
244: PetscScalar *r,*x;
245: const PetscScalar *b;
248: *its = m;
249: *reason = PCRICHARDSON_CONVERGED_ITS;
250: VecGetSize(bb,&n); n1 = n - 1;
251: VecGetArrayRead(bb,&b);
252: VecGetArray(xx,&x);
253: VecGetArray(w,&r);
255: while (m--) {
256: r[0] = .5*(x[1] + b[0]);
257: for (i=1; i<n1; i++) r[i] = .5*(x[i+1] + x[i-1] + b[i]);
258: r[n1] = .5*(x[n1-1] + b[n1]);
259: for (i=0; i<n; i++) x[i] = (2.0*r[i] + x[i])/3.0;
260: }
261: VecRestoreArrayRead(bb,&b);
262: VecRestoreArray(xx,&x);
263: VecRestoreArray(w,&r);
264: return(0);
265: }
266: /*
267: We know for this application that yy and zz are the same
268: */
269: /* --------------------------------------------------------------------- */
270: PetscErrorCode interpolate(Mat mat,Vec xx,Vec yy,Vec zz)
271: {
272: PetscInt i,n,N,i2;
273: PetscErrorCode ierr;
274: PetscScalar *y;
275: const PetscScalar *x;
278: VecGetSize(yy,&N);
279: VecGetArrayRead(xx,&x);
280: VecGetArray(yy,&y);
281: n = N/2;
282: for (i=0; i<n; i++) {
283: i2 = 2*i;
284: y[i2] += .5*x[i];
285: y[i2+1] += x[i];
286: y[i2+2] += .5*x[i];
287: }
288: VecRestoreArrayRead(xx,&x);
289: VecRestoreArray(yy,&y);
290: return(0);
291: }
292: /* --------------------------------------------------------------------- */
293: PetscErrorCode restrct(Mat mat,Vec rr,Vec bb)
294: {
295: PetscInt i,n,N,i2;
296: PetscErrorCode ierr;
297: PetscScalar *b;
298: const PetscScalar *r;
301: VecGetSize(rr,&N);
302: VecGetArrayRead(rr,&r);
303: VecGetArray(bb,&b);
304: n = N/2;
306: for (i=0; i<n; i++) {
307: i2 = 2*i;
308: b[i] = (r[i2] + 2.0*r[i2+1] + r[i2+2]);
309: }
310: VecRestoreArrayRead(rr,&r);
311: VecRestoreArray(bb,&b);
312: return(0);
313: }
314: /* --------------------------------------------------------------------- */
315: PetscErrorCode Create1dLaplacian(PetscInt n,Mat *mat)
316: {
317: PetscScalar mone = -1.0,two = 2.0;
318: PetscInt i,idx;
322: MatCreateSeqAIJ(PETSC_COMM_SELF,n,n,3,NULL,mat);
324: idx = n-1;
325: MatSetValues(*mat,1,&idx,1,&idx,&two,INSERT_VALUES);
326: for (i=0; i<n-1; i++) {
327: MatSetValues(*mat,1,&i,1,&i,&two,INSERT_VALUES);
328: idx = i+1;
329: MatSetValues(*mat,1,&idx,1,&i,&mone,INSERT_VALUES);
330: MatSetValues(*mat,1,&i,1,&idx,&mone,INSERT_VALUES);
331: }
332: MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);
333: MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);
334: return(0);
335: }
336: /* --------------------------------------------------------------------- */
337: PetscErrorCode CalculateRhs(Vec u)
338: {
340: PetscInt i,n;
341: PetscReal h,x = 0.0;
342: PetscScalar uu;
345: VecGetSize(u,&n);
346: h = 1.0/((PetscReal)(n+1));
347: for (i=0; i<n; i++) {
348: x += h; uu = 2.0*h*h;
349: VecSetValues(u,1,&i,&uu,INSERT_VALUES);
350: }
351: return(0);
352: }
353: /* --------------------------------------------------------------------- */
354: PetscErrorCode CalculateSolution(PetscInt n,Vec *solution)
355: {
357: PetscInt i;
358: PetscReal h,x = 0.0;
359: PetscScalar uu;
362: VecCreateSeq(PETSC_COMM_SELF,n,solution);
363: h = 1.0/((PetscReal)(n+1));
364: for (i=0; i<n; i++) {
365: x += h; uu = x*(1.-x);
366: VecSetValues(*solution,1,&i,&uu,INSERT_VALUES);
367: }
368: return(0);
369: }
370: /* --------------------------------------------------------------------- */
371: PetscErrorCode CalculateError(Vec solution,Vec u,Vec r,PetscReal *e)
372: {
376: VecNorm(r,NORM_2,e+2);
377: VecWAXPY(r,-1.0,u,solution);
378: VecNorm(r,NORM_2,e);
379: VecNorm(r,NORM_1,e+1);
380: return(0);
381: }