Actual source code: ex5.c

petsc-3.5.4 2015-05-23
Report Typos and Errors
  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);

 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;
 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:   const char     *shellname;
 40:   Vec            x,solution,X[20],R[20],B[20];
 41:   PC             pcmg,pc;
 42:   PetscBool      flg;

 44:   PetscInitialize(&Argc,&Args,(char*)0,help);

 46:   PetscOptionsGetInt(NULL,"-x",&x_mesh,NULL);
 47:   PetscOptionsGetInt(NULL,"-l",&levels,NULL);
 48:   PetscOptionsGetInt(NULL,"-c",&cycles,NULL);
 49:   PetscOptionsGetInt(NULL,"-smooths",&smooths,NULL);
 50:   PetscOptionsHasName(NULL,"-a",&flg);

 52:   if (flg) am = PC_MG_ADDITIVE;
 53:   PetscOptionsHasName(NULL,"-f",&flg);
 54:   if (flg) am = PC_MG_FULL;
 55:   PetscOptionsHasName(NULL,"-j",&flg);
 56:   if (flg) use_jacobi = 1;

 58:   PetscMalloc1(levels,&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(PETSC_COMM_WORLD,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,NULL);
 72:   PCMGSetType(pcmg,am);

 74:   PCMGGetCoarseSolve(pcmg,&cksp);
 75:   KSPSetOperators(cksp,cmat,cmat);
 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:     PCMGSetInterpolation(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]);
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);

115:     X[levels - 1 - i] = x;
116:     if (i > 0) {
117:       PCMGSetX(pcmg,levels - 1 - i,x);
118:     }
119:     VecCreateSeq(PETSC_COMM_SELF,N[i],&x);

121:     B[levels -1 - i] = x;
122:     if (i > 0) {
123:       PCMGSetRhs(pcmg,levels - 1 - i,x);
124:     }
125:     VecCreateSeq(PETSC_COMM_SELF,N[i],&x);

127:     R[levels - 1 - i] = x;

129:     PCMGSetR(pcmg,levels - 1 - i,x);
130:   }
131:   /* create coarse level vectors */
132:   VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x);
133:   PCMGSetX(pcmg,0,x); X[0] = x;
134:   VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x);
135:   PCMGSetRhs(pcmg,0,x); B[0] = x;

137:   /* create matrix multiply for finest level */
138:   MatCreateShell(PETSC_COMM_WORLD,N[0],N[0],N[0],N[0],(void*)0,&fmat);
139:   MatShellSetOperation(fmat,MATOP_MULT,(void (*)(void))amult);
140:   KSPSetOperators(kspmg,fmat,fmat);

142:   CalculateSolution(N[0],&solution);
143:   CalculateRhs(B[levels-1]);
144:   VecSet(X[levels-1],0.0);

146:   residual((Mat)0,B[levels-1],X[levels-1],R[levels-1]);
147:   CalculateError(solution,X[levels-1],R[levels-1],e);
148:   PetscPrintf(PETSC_COMM_SELF,"l_2 error %g max error %g resi %g\n",(double)e[0],(double)e[1],(double)e[2]);

150:   KSPSolve(kspmg,B[levels-1],X[levels-1]);
151:   KSPGetIterationNumber(kspmg,&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 %g\n",its,(double)e[0],(double)e[1],(double)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:     if (i) {VecDestroy(&R[i]);}
165:   }
166:   for (i=0; i<levels-1; i++) {
167:     MatDestroy(&mat[i]);
168:   }
169:   MatDestroy(&cmat);
170:   MatDestroy(&fmat);
171:   KSPDestroy(&kspmg);
172:   PetscFinalize();
173:   return 0;
174: }

176: /* --------------------------------------------------------------------- */
179: PetscErrorCode residual(Mat mat,Vec bb,Vec xx,Vec rr)
180: {
181:   PetscInt       i,n1;
183:   PetscScalar    *b,*x,*r;

186:   VecGetSize(bb,&n1);
187:   VecGetArray(bb,&b);
188:   VecGetArray(xx,&x);
189:   VecGetArray(rr,&r);
190:   n1--;
191:   r[0]  = b[0] + x[1] - 2.0*x[0];
192:   r[n1] = b[n1] + x[n1-1] - 2.0*x[n1];
193:   for (i=1; i<n1; i++) r[i] = b[i] + x[i+1] + x[i-1] - 2.0*x[i];
194:   VecRestoreArray(bb,&b);
195:   VecRestoreArray(xx,&x);
196:   VecRestoreArray(rr,&r);
197:   return(0);
198: }
201: PetscErrorCode amult(Mat mat,Vec xx,Vec yy)
202: {
203:   PetscInt       i,n1;
205:   PetscScalar    *y,*x;

208:   VecGetSize(xx,&n1);
209:   VecGetArray(xx,&x);
210:   VecGetArray(yy,&y);
211:   n1--;
212:   y[0] =  -x[1] + 2.0*x[0];
213:   y[n1] = -x[n1-1] + 2.0*x[n1];
214:   for (i=1; i<n1; i++) y[i] = -x[i+1] - x[i-1] + 2.0*x[i];
215:   VecRestoreArray(xx,&x);
216:   VecRestoreArray(yy,&y);
217:   return(0);
218: }
219: /* --------------------------------------------------------------------- */
222: 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)
223: {
224:   PetscInt       i,n1;
226:   PetscScalar    *x,*b;

229:   *its    = m;
230:   *reason = PCRICHARDSON_CONVERGED_ITS;
231:   VecGetSize(bb,&n1); n1--;
232:   VecGetArray(bb,&b);
233:   VecGetArray(xx,&x);
234:   while (m--) {
235:     x[0] =  .5*(x[1] + b[0]);
236:     for (i=1; i<n1; i++) x[i] = .5*(x[i+1] + x[i-1] + b[i]);
237:     x[n1] = .5*(x[n1-1] + b[n1]);
238:     for (i=n1-1; i>0; i--) x[i] = .5*(x[i+1] + x[i-1] + b[i]);
239:     x[0] =  .5*(x[1] + b[0]);
240:   }
241:   VecRestoreArray(bb,&b);
242:   VecRestoreArray(xx,&x);
243:   return(0);
244: }
245: /* --------------------------------------------------------------------- */
248: PetscErrorCode jacobi(PC pc,Vec bb,Vec xx,Vec w,PetscReal rtol,PetscReal abstol,PetscReal dtol,PetscInt m,PetscBool guesszero,PetscInt *its,PCRichardsonConvergedReason *reason)
249: {
250:   PetscInt       i,n,n1;
252:   PetscScalar    *r,*b,*x;

255:   *its    = m;
256:   *reason = PCRICHARDSON_CONVERGED_ITS;
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++) r[i] = .5*(x[i+1] + x[i-1] + b[i]);
265:     r[n1] = .5*(x[n1-1] + b[n1]);
266:     for (i=0; i<n; i++) x[i] = (2.0*r[i] + x[i])/3.0;
267:   }
268:   VecRestoreArray(bb,&b);
269:   VecRestoreArray(xx,&x);
270:   VecRestoreArray(w,&r);
271:   return(0);
272: }
273: /*
274:    We know for this application that yy  and zz are the same
275: */
276: /* --------------------------------------------------------------------- */
279: PetscErrorCode interpolate(Mat mat,Vec xx,Vec yy,Vec zz)
280: {
281:   PetscInt       i,n,N,i2;
283:   PetscScalar    *x,*y;

286:   VecGetSize(yy,&N);
287:   VecGetArray(xx,&x);
288:   VecGetArray(yy,&y);
289:   n    = N/2;
290:   for (i=0; i<n; i++) {
291:     i2       = 2*i;
292:     y[i2]   += .5*x[i];
293:     y[i2+1] +=    x[i];
294:     y[i2+2] += .5*x[i];
295:   }
296:   VecRestoreArray(xx,&x);
297:   VecRestoreArray(yy,&y);
298:   return(0);
299: }
300: /* --------------------------------------------------------------------- */
303: PetscErrorCode restrct(Mat mat,Vec rr,Vec bb)
304: {
305:   PetscInt       i,n,N,i2;
307:   PetscScalar    *r,*b;

310:   VecGetSize(rr,&N);
311:   VecGetArray(rr,&r);
312:   VecGetArray(bb,&b);
313:   n    = N/2;

315:   for (i=0; i<n; i++) {
316:     i2   = 2*i;
317:     b[i] = (r[i2] + 2.0*r[i2+1] + r[i2+2]);
318:   }
319:   VecRestoreArray(rr,&r);
320:   VecRestoreArray(bb,&b);
321:   return(0);
322: }
323: /* --------------------------------------------------------------------- */
326: PetscErrorCode Create1dLaplacian(PetscInt n,Mat *mat)
327: {
328:   PetscScalar    mone = -1.0,two = 2.0;
329:   PetscInt       i,idx;

333:   MatCreateSeqAIJ(PETSC_COMM_SELF,n,n,3,NULL,mat);

335:   idx  = n-1;
336:   MatSetValues(*mat,1,&idx,1,&idx,&two,INSERT_VALUES);
337:   for (i=0; i<n-1; i++) {
338:     MatSetValues(*mat,1,&i,1,&i,&two,INSERT_VALUES);
339:     idx  = i+1;
340:     MatSetValues(*mat,1,&idx,1,&i,&mone,INSERT_VALUES);
341:     MatSetValues(*mat,1,&i,1,&idx,&mone,INSERT_VALUES);
342:   }
343:   MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);
344:   MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);
345:   return(0);
346: }
347: /* --------------------------------------------------------------------- */
350: PetscErrorCode CalculateRhs(Vec u)
351: {
353:   PetscInt       i,n;
354:   PetscReal      h,x = 0.0;
355:   PetscScalar    uu;

358:   VecGetSize(u,&n);
359:   h    = 1.0/((PetscReal)(n+1));
360:   for (i=0; i<n; i++) {
361:     x   += h; uu = 2.0*h*h;
362:     VecSetValues(u,1,&i,&uu,INSERT_VALUES);
363:   }
364:   return(0);
365: }
366: /* --------------------------------------------------------------------- */
369: PetscErrorCode CalculateSolution(PetscInt n,Vec *solution)
370: {
372:   PetscInt       i;
373:   PetscReal      h,x = 0.0;
374:   PetscScalar    uu;

377:   VecCreateSeq(PETSC_COMM_SELF,n,solution);
378:   h    = 1.0/((PetscReal)(n+1));
379:   for (i=0; i<n; i++) {
380:     x   += h; uu = x*(1.-x);
381:     VecSetValues(*solution,1,&i,&uu,INSERT_VALUES);
382:   }
383:   return(0);
384: }
385: /* --------------------------------------------------------------------- */
388: PetscErrorCode CalculateError(Vec solution,Vec u,Vec r,PetscReal *e)
389: {

393:   VecNorm(r,NORM_2,e+2);
394:   VecWAXPY(r,-1.0,u,solution);
395:   VecNorm(r,NORM_2,e);
396:   VecNorm(r,NORM_1,e+1);
397:   return(0);
398: }