Actual source code: ex4.c

petsc-3.4.5 2014-06-29
  1: /*
  2:        The Problem:
  3:            Solve the convection-diffusion equation:

  5:              u_t+a*(u_x+u_y)=epsilon*(u_xx+u_yy)
  6:              u=0   at x=0, y=0
  7:              u_x=0 at x=1
  8:              u_y=0 at y=1
  9:              u = exp(-20.0*(pow(x-0.5,2.0)+pow(y-0.5,2.0))) at t=0

 11:        This program tests the routine of computing the Jacobian by the
 12:        finite difference method as well as PETSc with SUNDIALS.

 14: */

 16: static char help[] = "Solve the convection-diffusion equation. \n\n";

 18: #include <petscts.h>

 20: typedef struct
 21: {
 22:   PetscInt  m;          /* the number of mesh points in x-direction */
 23:   PetscInt  n;          /* the number of mesh points in y-direction */
 24:   PetscReal dx;         /* the grid space in x-direction */
 25:   PetscReal dy;         /* the grid space in y-direction */
 26:   PetscReal a;          /* the convection coefficient    */
 27:   PetscReal epsilon;    /* the diffusion coefficient     */
 28:   PetscReal tfinal;
 29: } Data;

 31: extern PetscErrorCode Monitor(TS,PetscInt,PetscReal,Vec,void*);
 32: extern PetscErrorCode Initial(Vec,void*);
 33: extern PetscErrorCode RHSFunction(TS,PetscReal,Vec,Vec,void*);
 34: extern PetscErrorCode RHSJacobian(TS,PetscReal,Vec,Mat*,Mat*,MatStructure*,void*);
 35: extern PetscErrorCode PostStep(TS);

 39: int main(int argc,char **argv)
 40: {
 42:   PetscInt       time_steps=100,iout,NOUT=1;
 43:   PetscMPIInt    size;
 44:   Vec            global;
 45:   PetscReal      dt,ftime,ftime_original;
 46:   TS             ts;
 47:   PetscViewer    viewfile;
 48:   MatStructure   J_structure;
 49:   Mat            J = 0;
 50:   Vec            x;
 51:   Data           data;
 52:   PetscInt       mn;
 53:   PetscBool      flg;
 54:   ISColoring     iscoloring;
 55:   MatFDColoring  matfdcoloring        = 0;
 56:   PetscBool      fd_jacobian_coloring = PETSC_FALSE;
 57:   SNES           snes;
 58:   KSP            ksp;
 59:   PC             pc;
 60:   PetscViewer    viewer;
 61:   char           pcinfo[120],tsinfo[120];
 62:   TSType         tstype;
 63:   PetscBool      sundials;

 65:   PetscInitialize(&argc,&argv,(char*)0,help);
 66:   MPI_Comm_size(PETSC_COMM_WORLD,&size);

 68:   /* set data */
 69:   data.m       = 9;
 70:   data.n       = 9;
 71:   data.a       = 1.0;
 72:   data.epsilon = 0.1;
 73:   data.dx      = 1.0/(data.m+1.0);
 74:   data.dy      = 1.0/(data.n+1.0);
 75:   mn           = (data.m)*(data.n);
 76:   PetscOptionsGetInt(NULL,"-time",&time_steps,NULL);

 78:   /* set initial conditions */
 79:   VecCreate(PETSC_COMM_WORLD,&global);
 80:   VecSetSizes(global,PETSC_DECIDE,mn);
 81:   VecSetFromOptions(global);
 82:   Initial(global,&data);
 83:   VecDuplicate(global,&x);

 85:   /* create timestep context */
 86:   TSCreate(PETSC_COMM_WORLD,&ts);
 87:   TSMonitorSet(ts,Monitor,&data,NULL);
 88: #if defined(PETSC_HAVE_SUNDIALS)
 89:   TSSetType(ts,TSSUNDIALS);
 90: #else
 91:   TSSetType(ts,TSEULER);
 92: #endif
 93:   dt             = 0.1;
 94:   ftime_original = data.tfinal = 1.0;

 96:   TSSetInitialTimeStep(ts,0.0,dt);
 97:   TSSetDuration(ts,time_steps,ftime_original);
 98:   TSSetSolution(ts,global);

100:   /* set user provided RHSFunction and RHSJacobian */
101:   TSSetRHSFunction(ts,NULL,RHSFunction,&data);
102:   MatCreate(PETSC_COMM_WORLD,&J);
103:   MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,mn,mn);
104:   MatSetFromOptions(J);
105:   MatSeqAIJSetPreallocation(J,5,NULL);
106:   MatMPIAIJSetPreallocation(J,5,NULL,5,NULL);

108:   PetscOptionsHasName(NULL,"-ts_fd",&flg);
109:   if (!flg) {
110:     TSSetRHSJacobian(ts,J,J,RHSJacobian,&data);
111:   } else {
112:     TSGetSNES(ts,&snes);
113:     PetscOptionsHasName(NULL,"-fd_color",&fd_jacobian_coloring);
114:     if (fd_jacobian_coloring) { /* Use finite differences with coloring */
115:       /* Get data structure of J */
116:       PetscBool pc_diagonal;
117:       PetscOptionsHasName(NULL,"-pc_diagonal",&pc_diagonal);
118:       if (pc_diagonal) { /* the preconditioner of J is a diagonal matrix */
119:         PetscInt    rstart,rend,i;
120:         PetscScalar zero=0.0;
121:         MatGetOwnershipRange(J,&rstart,&rend);
122:         for (i=rstart; i<rend; i++) {
123:           MatSetValues(J,1,&i,1,&i,&zero,INSERT_VALUES);
124:         }
125:         MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);
126:         MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);
127:       } else {
128:         /* Fill the structure using the expensive SNESComputeJacobianDefault. Temporarily set up the TS so we can call this function */
129:         TSSetType(ts,TSBEULER);
130:         TSSetUp(ts);
131:         SNESComputeJacobianDefault(snes,x,&J,&J,&J_structure,ts);
132:       }

134:       /* create coloring context */
135:       MatGetColoring(J,MATCOLORINGSL,&iscoloring);
136:       MatFDColoringCreate(J,iscoloring,&matfdcoloring);
137:       MatFDColoringSetFunction(matfdcoloring,(PetscErrorCode (*)(void))SNESTSFormFunction,ts);
138:       MatFDColoringSetFromOptions(matfdcoloring);
139:       SNESSetJacobian(snes,J,J,SNESComputeJacobianDefaultColor,matfdcoloring);
140:       ISColoringDestroy(&iscoloring);
141:     } else { /* Use finite differences (slow) */
142:       SNESSetJacobian(snes,J,J,SNESComputeJacobianDefault,NULL);
143:     }
144:   }

146:   /* Pick up a Petsc preconditioner */
147:   /* one can always set method or preconditioner during the run time */
148:   TSGetSNES(ts,&snes);
149:   SNESGetKSP(snes,&ksp);
150:   KSPGetPC(ksp,&pc);
151:   PCSetType(pc,PCJACOBI);

153:   TSSetFromOptions(ts);
154:   TSSetUp(ts);

156:   /* Test TSSetPostStep() */
157:   PetscOptionsHasName(NULL,"-test_PostStep",&flg);
158:   if (flg) {
159:     TSSetPostStep(ts,PostStep);
160:   }

162:   PetscOptionsGetInt(NULL,"-NOUT",&NOUT,NULL);
163:   for (iout=1; iout<=NOUT; iout++) {
164:     TSSetDuration(ts,time_steps,iout*ftime_original/NOUT);
165:     TSSolve(ts,global);
166:     TSGetSolveTime(ts,&ftime);
167:     TSSetInitialTimeStep(ts,ftime,dt);
168:   }
169:   /* Interpolate solution at tfinal */
170:   TSGetSolution(ts,&global);
171:   TSInterpolate(ts,ftime_original,global);

173:   PetscOptionsHasName(NULL,"-matlab_view",&flg);
174:   if (flg) { /* print solution into a MATLAB file */
175:     PetscViewerASCIIOpen(PETSC_COMM_WORLD,"out.m",&viewfile);
176:     PetscViewerSetFormat(viewfile,PETSC_VIEWER_ASCII_MATLAB);
177:     VecView(global,viewfile);
178:     PetscViewerDestroy(&viewfile);
179:   }

181:   /* display solver info for Sundials */
182:   TSGetType(ts,&tstype);
183:   PetscObjectTypeCompare((PetscObject)ts,TSSUNDIALS,&sundials);
184:   if (sundials) {
185:     PetscViewerStringOpen(PETSC_COMM_WORLD,tsinfo,120,&viewer);
186:     TSView(ts,viewer);
187:     PetscViewerDestroy(&viewer);
188:     PetscViewerStringOpen(PETSC_COMM_WORLD,pcinfo,120,&viewer);
189:     PCView(pc,viewer);
190:     PetscPrintf(PETSC_COMM_WORLD,"%d Procs,%s TSType, %s Preconditioner\n",
191:                        size,tsinfo,pcinfo);
192:     PetscViewerDestroy(&viewer);
193:   }

195:   /* free the memories */
196:   TSDestroy(&ts);
197:   VecDestroy(&global);
198:   VecDestroy(&x);
199:   MatDestroy(&J);
200:   if (fd_jacobian_coloring) {MatFDColoringDestroy(&matfdcoloring);}
201:   PetscFinalize();
202:   return 0;
203: }

205: /* -------------------------------------------------------------------*/
206: /* the initial function */
207: PetscReal f_ini(PetscReal x,PetscReal y)
208: {
209:   PetscReal f;

211:   f=exp(-20.0*(pow(x-0.5,2.0)+pow(y-0.5,2.0)));
212:   return f;
213: }

217: PetscErrorCode Initial(Vec global,void *ctx)
218: {
219:   Data           *data = (Data*)ctx;
220:   PetscInt       m,row,col;
221:   PetscReal      x,y,dx,dy;
222:   PetscScalar    *localptr;
223:   PetscInt       i,mybase,myend,locsize;

227:   /* make the local  copies of parameters */
228:   m  = data->m;
229:   dx = data->dx;
230:   dy = data->dy;

232:   /* determine starting point of each processor */
233:   VecGetOwnershipRange(global,&mybase,&myend);
234:   VecGetLocalSize(global,&locsize);

236:   /* Initialize the array */
237:   VecGetArray(global,&localptr);

239:   for (i=0; i<locsize; i++) {
240:     row         = 1+(mybase+i)-((mybase+i)/m)*m;
241:     col         = (mybase+i)/m+1;
242:     x           = dx*row;
243:     y           = dy*col;
244:     localptr[i] = f_ini(x,y);
245:   }

247:   VecRestoreArray(global,&localptr);
248:   return(0);
249: }

253: PetscErrorCode Monitor(TS ts,PetscInt step,PetscReal time,Vec global,void *ctx)
254: {
255:   VecScatter     scatter;
256:   IS             from,to;
257:   PetscInt       i,n,*idx,nsteps,maxsteps;
258:   Vec            tmp_vec;
260:   PetscScalar    *tmp;
261:   PetscReal      maxtime;
262:   Data           *data  = (Data*)ctx;
263:   PetscReal      tfinal = data->tfinal;

266:   if (time > tfinal) return(0);

268:   TSGetTimeStepNumber(ts,&nsteps);
269:   /* display output at selected time steps */
270:   TSGetDuration(ts, &maxsteps, &maxtime);
271:   if (nsteps % 10 != 0 && time < maxtime) return(0);

273:   /* Get the size of the vector */
274:   VecGetSize(global,&n);

276:   /* Set the index sets */
277:   PetscMalloc(n*sizeof(PetscInt),&idx);
278:   for (i=0; i<n; i++) idx[i]=i;

280:   /* Create local sequential vectors */
281:   VecCreateSeq(PETSC_COMM_SELF,n,&tmp_vec);

283:   /* Create scatter context */
284:   ISCreateGeneral(PETSC_COMM_SELF,n,idx,PETSC_COPY_VALUES,&from);
285:   ISCreateGeneral(PETSC_COMM_SELF,n,idx,PETSC_COPY_VALUES,&to);
286:   VecScatterCreate(global,from,tmp_vec,to,&scatter);
287:   VecScatterBegin(scatter,global,tmp_vec,INSERT_VALUES,SCATTER_FORWARD);
288:   VecScatterEnd(scatter,global,tmp_vec,INSERT_VALUES,SCATTER_FORWARD);

290:   VecGetArray(tmp_vec,&tmp);
291:   PetscPrintf(PETSC_COMM_WORLD,"At t[%d] =%14.2e u= %14.2e at the center \n",nsteps,time,PetscRealPart(tmp[n/2]));
292:   VecRestoreArray(tmp_vec,&tmp);

294:   PetscFree(idx);
295:   ISDestroy(&from);
296:   ISDestroy(&to);
297:   VecScatterDestroy(&scatter);
298:   VecDestroy(&tmp_vec);
299:   return(0);
300: }

304: PetscErrorCode RHSJacobian(TS ts,PetscReal t,Vec x,Mat *AA,Mat *BB,MatStructure *flag,void *ptr)
305: {
306:   Data           *data = (Data*)ptr;
307:   Mat            A     = *AA;
308:   PetscScalar    v[5];
309:   PetscInt       idx[5],i,j,row;
311:   PetscInt       m,n,mn;
312:   PetscReal      dx,dy,a,epsilon,xc,xl,xr,yl,yr;

315:   m       = data->m;
316:   n       = data->n;
317:   mn      = m*n;
318:   dx      = data->dx;
319:   dy      = data->dy;
320:   a       = data->a;
321:   epsilon = data->epsilon;

323:   xc = -2.0*epsilon*(1.0/(dx*dx)+1.0/(dy*dy));
324:   xl = 0.5*a/dx+epsilon/(dx*dx);
325:   xr = -0.5*a/dx+epsilon/(dx*dx);
326:   yl = 0.5*a/dy+epsilon/(dy*dy);
327:   yr = -0.5*a/dy+epsilon/(dy*dy);

329:   row    = 0;
330:   v[0]   = xc;  v[1] = xr;  v[2] = yr;
331:   idx[0] = 0; idx[1] = 2; idx[2] = m;
332:   MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES);

334:   row    = m-1;
335:   v[0]   = 2.0*xl; v[1] = xc;    v[2] = yr;
336:   idx[0] = m-2;  idx[1] = m-1; idx[2] = m-1+m;
337:   MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES);

339:   for (i=1; i<m-1; i++) {
340:     row    = i;
341:     v[0]   = xl;    v[1] = xc;  v[2] = xr;    v[3] = yr;
342:     idx[0] = i-1; idx[1] = i; idx[2] = i+1; idx[3] = i+m;
343:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);
344:   }

346:   for (j=1; j<n-1; j++) {
347:     row    = j*m;
348:     v[0]   = xc;    v[1] = xr;    v[2] = yl;      v[3] = yr;
349:     idx[0] = j*m; idx[1] = j*m; idx[2] = j*m-m; idx[3] = j*m+m;
350:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);

352:     row    = j*m+m-1;
353:     v[0]   = xc;        v[1] = 2.0*xl;      v[2] = yl;          v[3] = yr;
354:     idx[0] = j*m+m-1; idx[1] = j*m+m-1-1; idx[2] = j*m+m-1-m; idx[3] = j*m+m-1+m;
355:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);

357:     for (i=1; i<m-1; i++) {
358:       row    = j*m+i;
359:       v[0]   = xc;      v[1] = xl;        v[2] = xr;        v[3] = yl; v[4]=yr;
360:       idx[0] = j*m+i; idx[1] = j*m+i-1; idx[2] = j*m+i+1; idx[3] = j*m+i-m;
361:       idx[4] = j*m+i+m;
362:       MatSetValues(A,1,&row,5,idx,v,INSERT_VALUES);
363:     }
364:   }

366:   row    = mn-m;
367:   v[0]   = xc;     v[1] = xr;       v[2] = 2.0*yl;
368:   idx[0] = mn-m; idx[1] = mn-m+1; idx[2] = mn-m-m;
369:   MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES);

371:   row    = mn-1;
372:   v[0]   = xc;     v[1] = 2.0*xl; v[2] = 2.0*yl;
373:   idx[0] = mn-1; idx[1] = mn-2; idx[2] = mn-1-m;
374:   MatSetValues(A,1,&i,3,idx,v,INSERT_VALUES);

376:   for (i=1; i<m-1; i++) {
377:     row    = mn-m+i;
378:     v[0]   = xl;         v[1] = xc;       v[2] = xr;         v[3] = 2.0*yl;
379:     idx[0] = mn-m+i-1; idx[1] = mn-m+i; idx[2] = mn-m+i+1; idx[3] = mn-m+i-m;
380:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);
381:   }

383:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
384:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);

386:   /* *flag = SAME_NONZERO_PATTERN; */
387:   *flag = DIFFERENT_NONZERO_PATTERN;
388:   return(0);
389: }

391: /* globalout = -a*(u_x+u_y) + epsilon*(u_xx+u_yy) */
394: PetscErrorCode RHSFunction(TS ts,PetscReal t,Vec globalin,Vec globalout,void *ctx)
395: {
396:   Data           *data = (Data*)ctx;
397:   PetscInt       m,n,mn;
398:   PetscReal      dx,dy;
399:   PetscReal      xc,xl,xr,yl,yr;
400:   PetscReal      a,epsilon;
401:   PetscScalar    *inptr,*outptr;
402:   PetscInt       i,j,len;
404:   IS             from,to;
405:   PetscInt       *idx;
406:   VecScatter     scatter;
407:   Vec            tmp_in,tmp_out;

410:   m       = data->m;
411:   n       = data->n;
412:   mn      = m*n;
413:   dx      = data->dx;
414:   dy      = data->dy;
415:   a       = data->a;
416:   epsilon = data->epsilon;

418:   xc = -2.0*epsilon*(1.0/(dx*dx)+1.0/(dy*dy));
419:   xl = 0.5*a/dx+epsilon/(dx*dx);
420:   xr = -0.5*a/dx+epsilon/(dx*dx);
421:   yl = 0.5*a/dy+epsilon/(dy*dy);
422:   yr = -0.5*a/dy+epsilon/(dy*dy);

424:   /* Get the length of parallel vector */
425:   VecGetSize(globalin,&len);

427:   /* Set the index sets */
428:   PetscMalloc(len*sizeof(PetscInt),&idx);
429:   for (i=0; i<len; i++) idx[i]=i;

431:   /* Create local sequential vectors */
432:   VecCreateSeq(PETSC_COMM_SELF,len,&tmp_in);
433:   VecDuplicate(tmp_in,&tmp_out);

435:   /* Create scatter context */
436:   ISCreateGeneral(PETSC_COMM_SELF,len,idx,PETSC_COPY_VALUES,&from);
437:   ISCreateGeneral(PETSC_COMM_SELF,len,idx,PETSC_COPY_VALUES,&to);
438:   VecScatterCreate(globalin,from,tmp_in,to,&scatter);
439:   VecScatterBegin(scatter,globalin,tmp_in,INSERT_VALUES,SCATTER_FORWARD);
440:   VecScatterEnd(scatter,globalin,tmp_in,INSERT_VALUES,SCATTER_FORWARD);
441:   VecScatterDestroy(&scatter);

443:   /*Extract income array - include ghost points */
444:   VecGetArray(tmp_in,&inptr);

446:   /* Extract outcome array*/
447:   VecGetArray(tmp_out,&outptr);

449:   outptr[0]   = xc*inptr[0]+xr*inptr[1]+yr*inptr[m];
450:   outptr[m-1] = 2.0*xl*inptr[m-2]+xc*inptr[m-1]+yr*inptr[m-1+m];
451:   for (i=1; i<m-1; i++) {
452:     outptr[i] = xc*inptr[i]+xl*inptr[i-1]+xr*inptr[i+1]
453:       +yr*inptr[i+m];
454:   }

456:   for (j=1; j<n-1; j++) {
457:     outptr[j*m] = xc*inptr[j*m]+xr*inptr[j*m+1]+
458:                   yl*inptr[j*m-m]+yr*inptr[j*m+m];
459:     outptr[j*m+m-1] = xc*inptr[j*m+m-1]+2.0*xl*inptr[j*m+m-1-1]+
460:                       yl*inptr[j*m+m-1-m]+yr*inptr[j*m+m-1+m];
461:     for (i=1; i<m-1; i++) {
462:       outptr[j*m+i] = xc*inptr[j*m+i]+xl*inptr[j*m+i-1]+xr*inptr[j*m+i+1]
463:                       +yl*inptr[j*m+i-m]+yr*inptr[j*m+i+m];
464:     }
465:   }

467:   outptr[mn-m] = xc*inptr[mn-m]+xr*inptr[mn-m+1]+2.0*yl*inptr[mn-m-m];
468:   outptr[mn-1] = 2.0*xl*inptr[mn-2]+xc*inptr[mn-1]+2.0*yl*inptr[mn-1-m];
469:   for (i=1; i<m-1; i++) {
470:     outptr[mn-m+i] = xc*inptr[mn-m+i]+xl*inptr[mn-m+i-1]+xr*inptr[mn-m+i+1]
471:                      +2*yl*inptr[mn-m+i-m];
472:   }

474:   VecRestoreArray(tmp_in,&inptr);
475:   VecRestoreArray(tmp_out,&outptr);

477:   VecScatterCreate(tmp_out,from,globalout,to,&scatter);
478:   VecScatterBegin(scatter,tmp_out,globalout,INSERT_VALUES,SCATTER_FORWARD);
479:   VecScatterEnd(scatter,tmp_out,globalout,INSERT_VALUES,SCATTER_FORWARD);

481:   /* Destroy idx aand scatter */
482:   VecDestroy(&tmp_in);
483:   VecDestroy(&tmp_out);
484:   ISDestroy(&from);
485:   ISDestroy(&to);
486:   VecScatterDestroy(&scatter);

488:   PetscFree(idx);
489:   return(0);
490: }

494: PetscErrorCode PostStep(TS ts)
495: {
497:   PetscReal      t;

500:   TSGetTime(ts,&t);
501:   PetscPrintf(PETSC_COMM_SELF,"  PostStep, t: %g\n",t);
502:   return(0);
503: }