Actual source code: ex5.c

petsc-3.8.3 2017-12-09
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);

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