Actual source code: ex4.c

petsc-dev 2014-02-02
Report Typos and Errors
  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:   MatColoring    mc;
 55:   ISColoring     iscoloring;
 56:   MatFDColoring  matfdcoloring        = 0;
 57:   PetscBool      fd_jacobian_coloring = PETSC_FALSE;
 58:   SNES           snes;
 59:   KSP            ksp;
 60:   PC             pc;
 61:   PetscViewer    viewer;
 62:   char           pcinfo[120],tsinfo[120];
 63:   TSType         tstype;
 64:   PetscBool      sundials;

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

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

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

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

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

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

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

135:       /* create coloring context */
136:       MatColoringCreate(J,&mc);
137:       MatColoringSetType(mc,MATCOLORINGSL);
138:       MatColoringSetFromOptions(mc);
139:       MatColoringApply(mc,&iscoloring);
140:       MatColoringDestroy(&mc);
141:       MatFDColoringCreate(J,iscoloring,&matfdcoloring);
142:       MatFDColoringSetFunction(matfdcoloring,(PetscErrorCode (*)(void))SNESTSFormFunction,ts);
143:       MatFDColoringSetFromOptions(matfdcoloring);
144:       MatFDColoringSetUp(J,iscoloring,matfdcoloring);
145:       SNESSetJacobian(snes,J,J,SNESComputeJacobianDefaultColor,matfdcoloring);
146:       ISColoringDestroy(&iscoloring);
147:     } else { /* Use finite differences (slow) */
148:       SNESSetJacobian(snes,J,J,SNESComputeJacobianDefault,NULL);
149:     }
150:   }

152:   /* Pick up a Petsc preconditioner */
153:   /* one can always set method or preconditioner during the run time */
154:   TSGetSNES(ts,&snes);
155:   SNESGetKSP(snes,&ksp);
156:   KSPGetPC(ksp,&pc);
157:   PCSetType(pc,PCJACOBI);

159:   TSSetFromOptions(ts);
160:   TSSetUp(ts);

162:   /* Test TSSetPostStep() */
163:   PetscOptionsHasName(NULL,"-test_PostStep",&flg);
164:   if (flg) {
165:     TSSetPostStep(ts,PostStep);
166:   }

168:   PetscOptionsGetInt(NULL,"-NOUT",&NOUT,NULL);
169:   for (iout=1; iout<=NOUT; iout++) {
170:     TSSetDuration(ts,time_steps,iout*ftime_original/NOUT);
171:     TSSolve(ts,global);
172:     TSGetSolveTime(ts,&ftime);
173:     TSSetInitialTimeStep(ts,ftime,dt);
174:   }
175:   /* Interpolate solution at tfinal */
176:   TSGetSolution(ts,&global);
177:   TSInterpolate(ts,ftime_original,global);

179:   PetscOptionsHasName(NULL,"-matlab_view",&flg);
180:   if (flg) { /* print solution into a MATLAB file */
181:     PetscViewerASCIIOpen(PETSC_COMM_WORLD,"out.m",&viewfile);
182:     PetscViewerSetFormat(viewfile,PETSC_VIEWER_ASCII_MATLAB);
183:     VecView(global,viewfile);
184:     PetscViewerDestroy(&viewfile);
185:   }

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

200:   /* free the memories */
201:   TSDestroy(&ts);
202:   VecDestroy(&global);
203:   VecDestroy(&x);
204:   MatDestroy(&J);
205:   if (fd_jacobian_coloring) {MatFDColoringDestroy(&matfdcoloring);}
206:   PetscFinalize();
207:   return 0;
208: }

210: /* -------------------------------------------------------------------*/
211: /* the initial function */
212: PetscReal f_ini(PetscReal x,PetscReal y)
213: {
214:   PetscReal f;

216:   f=PetscExpReal(-20.0*(PetscPowRealInt(x-0.5,2)+PetscPowRealInt(y-0.5,2)));
217:   return f;
218: }

222: PetscErrorCode Initial(Vec global,void *ctx)
223: {
224:   Data           *data = (Data*)ctx;
225:   PetscInt       m,row,col;
226:   PetscReal      x,y,dx,dy;
227:   PetscScalar    *localptr;
228:   PetscInt       i,mybase,myend,locsize;

232:   /* make the local  copies of parameters */
233:   m  = data->m;
234:   dx = data->dx;
235:   dy = data->dy;

237:   /* determine starting point of each processor */
238:   VecGetOwnershipRange(global,&mybase,&myend);
239:   VecGetLocalSize(global,&locsize);

241:   /* Initialize the array */
242:   VecGetArray(global,&localptr);

244:   for (i=0; i<locsize; i++) {
245:     row         = 1+(mybase+i)-((mybase+i)/m)*m;
246:     col         = (mybase+i)/m+1;
247:     x           = dx*row;
248:     y           = dy*col;
249:     localptr[i] = f_ini(x,y);
250:   }

252:   VecRestoreArray(global,&localptr);
253:   return(0);
254: }

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

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

273:   TSGetTimeStepNumber(ts,&nsteps);
274:   /* display output at selected time steps */
275:   TSGetDuration(ts, &maxsteps, &maxtime);
276:   if (nsteps % 10 != 0 && time < maxtime) return(0);

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

281:   /* Set the index sets */
282:   PetscMalloc1(n,&idx);
283:   for (i=0; i<n; i++) idx[i]=i;

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

288:   /* Create scatter context */
289:   ISCreateGeneral(PETSC_COMM_SELF,n,idx,PETSC_COPY_VALUES,&from);
290:   ISCreateGeneral(PETSC_COMM_SELF,n,idx,PETSC_COPY_VALUES,&to);
291:   VecScatterCreate(global,from,tmp_vec,to,&scatter);
292:   VecScatterBegin(scatter,global,tmp_vec,INSERT_VALUES,SCATTER_FORWARD);
293:   VecScatterEnd(scatter,global,tmp_vec,INSERT_VALUES,SCATTER_FORWARD);

295:   VecGetArray(tmp_vec,&tmp);
296:   PetscPrintf(PETSC_COMM_WORLD,"At t[%D] =%14.2e u= %14.2e at the center \n",nsteps,(double)time,(double)PetscRealPart(tmp[n/2]));
297:   VecRestoreArray(tmp_vec,&tmp);

299:   PetscFree(idx);
300:   ISDestroy(&from);
301:   ISDestroy(&to);
302:   VecScatterDestroy(&scatter);
303:   VecDestroy(&tmp_vec);
304:   return(0);
305: }

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

320:   m       = data->m;
321:   n       = data->n;
322:   mn      = m*n;
323:   dx      = data->dx;
324:   dy      = data->dy;
325:   a       = data->a;
326:   epsilon = data->epsilon;

328:   xc = -2.0*epsilon*(1.0/(dx*dx)+1.0/(dy*dy));
329:   xl = 0.5*a/dx+epsilon/(dx*dx);
330:   xr = -0.5*a/dx+epsilon/(dx*dx);
331:   yl = 0.5*a/dy+epsilon/(dy*dy);
332:   yr = -0.5*a/dy+epsilon/(dy*dy);

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

339:   row    = m-1;
340:   v[0]   = 2.0*xl; v[1] = xc;    v[2] = yr;
341:   idx[0] = m-2;  idx[1] = m-1; idx[2] = m-1+m;
342:   MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES);

344:   for (i=1; i<m-1; i++) {
345:     row    = i;
346:     v[0]   = xl;    v[1] = xc;  v[2] = xr;    v[3] = yr;
347:     idx[0] = i-1; idx[1] = i; idx[2] = i+1; idx[3] = i+m;
348:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);
349:   }

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

357:     row    = j*m+m-1;
358:     v[0]   = xc;        v[1] = 2.0*xl;      v[2] = yl;          v[3] = yr;
359:     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;
360:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);

362:     for (i=1; i<m-1; i++) {
363:       row    = j*m+i;
364:       v[0]   = xc;      v[1] = xl;        v[2] = xr;        v[3] = yl; v[4]=yr;
365:       idx[0] = j*m+i; idx[1] = j*m+i-1; idx[2] = j*m+i+1; idx[3] = j*m+i-m;
366:       idx[4] = j*m+i+m;
367:       MatSetValues(A,1,&row,5,idx,v,INSERT_VALUES);
368:     }
369:   }

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

376:   row    = mn-1;
377:   v[0]   = xc;     v[1] = 2.0*xl; v[2] = 2.0*yl;
378:   idx[0] = mn-1; idx[1] = mn-2; idx[2] = mn-1-m;
379:   MatSetValues(A,1,&i,3,idx,v,INSERT_VALUES);

381:   for (i=1; i<m-1; i++) {
382:     row    = mn-m+i;
383:     v[0]   = xl;         v[1] = xc;       v[2] = xr;         v[3] = 2.0*yl;
384:     idx[0] = mn-m+i-1; idx[1] = mn-m+i; idx[2] = mn-m+i+1; idx[3] = mn-m+i-m;
385:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);
386:   }

388:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
389:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);

391:   /* *flag = SAME_NONZERO_PATTERN; */
392:   *flag = DIFFERENT_NONZERO_PATTERN;
393:   return(0);
394: }

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

415:   m       = data->m;
416:   n       = data->n;
417:   mn      = m*n;
418:   dx      = data->dx;
419:   dy      = data->dy;
420:   a       = data->a;
421:   epsilon = data->epsilon;

423:   xc = -2.0*epsilon*(1.0/(dx*dx)+1.0/(dy*dy));
424:   xl = 0.5*a/dx+epsilon/(dx*dx);
425:   xr = -0.5*a/dx+epsilon/(dx*dx);
426:   yl = 0.5*a/dy+epsilon/(dy*dy);
427:   yr = -0.5*a/dy+epsilon/(dy*dy);

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

432:   /* Set the index sets */
433:   PetscMalloc1(len,&idx);
434:   for (i=0; i<len; i++) idx[i]=i;

436:   /* Create local sequential vectors */
437:   VecCreateSeq(PETSC_COMM_SELF,len,&tmp_in);
438:   VecDuplicate(tmp_in,&tmp_out);

440:   /* Create scatter context */
441:   ISCreateGeneral(PETSC_COMM_SELF,len,idx,PETSC_COPY_VALUES,&from);
442:   ISCreateGeneral(PETSC_COMM_SELF,len,idx,PETSC_COPY_VALUES,&to);
443:   VecScatterCreate(globalin,from,tmp_in,to,&scatter);
444:   VecScatterBegin(scatter,globalin,tmp_in,INSERT_VALUES,SCATTER_FORWARD);
445:   VecScatterEnd(scatter,globalin,tmp_in,INSERT_VALUES,SCATTER_FORWARD);
446:   VecScatterDestroy(&scatter);

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

451:   /* Extract outcome array*/
452:   VecGetArray(tmp_out,&outptr);

454:   outptr[0]   = xc*inptr[0]+xr*inptr[1]+yr*inptr[m];
455:   outptr[m-1] = 2.0*xl*inptr[m-2]+xc*inptr[m-1]+yr*inptr[m-1+m];
456:   for (i=1; i<m-1; i++) {
457:     outptr[i] = xc*inptr[i]+xl*inptr[i-1]+xr*inptr[i+1]
458:       +yr*inptr[i+m];
459:   }

461:   for (j=1; j<n-1; j++) {
462:     outptr[j*m] = xc*inptr[j*m]+xr*inptr[j*m+1]+
463:                   yl*inptr[j*m-m]+yr*inptr[j*m+m];
464:     outptr[j*m+m-1] = xc*inptr[j*m+m-1]+2.0*xl*inptr[j*m+m-1-1]+
465:                       yl*inptr[j*m+m-1-m]+yr*inptr[j*m+m-1+m];
466:     for (i=1; i<m-1; i++) {
467:       outptr[j*m+i] = xc*inptr[j*m+i]+xl*inptr[j*m+i-1]+xr*inptr[j*m+i+1]
468:                       +yl*inptr[j*m+i-m]+yr*inptr[j*m+i+m];
469:     }
470:   }

472:   outptr[mn-m] = xc*inptr[mn-m]+xr*inptr[mn-m+1]+2.0*yl*inptr[mn-m-m];
473:   outptr[mn-1] = 2.0*xl*inptr[mn-2]+xc*inptr[mn-1]+2.0*yl*inptr[mn-1-m];
474:   for (i=1; i<m-1; i++) {
475:     outptr[mn-m+i] = xc*inptr[mn-m+i]+xl*inptr[mn-m+i-1]+xr*inptr[mn-m+i+1]
476:                      +2*yl*inptr[mn-m+i-m];
477:   }

479:   VecRestoreArray(tmp_in,&inptr);
480:   VecRestoreArray(tmp_out,&outptr);

482:   VecScatterCreate(tmp_out,from,globalout,to,&scatter);
483:   VecScatterBegin(scatter,tmp_out,globalout,INSERT_VALUES,SCATTER_FORWARD);
484:   VecScatterEnd(scatter,tmp_out,globalout,INSERT_VALUES,SCATTER_FORWARD);

486:   /* Destroy idx aand scatter */
487:   VecDestroy(&tmp_in);
488:   VecDestroy(&tmp_out);
489:   ISDestroy(&from);
490:   ISDestroy(&to);
491:   VecScatterDestroy(&scatter);

493:   PetscFree(idx);
494:   return(0);
495: }

499: PetscErrorCode PostStep(TS ts)
500: {
502:   PetscReal      t;

505:   TSGetTime(ts,&t);
506:   PetscPrintf(PETSC_COMM_SELF,"  PostStep, t: %g\n",(double)t);
507:   return(0);
508: }